Herramientas de usuario

Herramientas del sitio


clase:daw:daw:2eval:tema06

¡Esta es una revisión vieja del documento!


6. Control de Versiones Avanzado

En este tema vamos a ver sobre todo a tratar con ramas, merges y conflictos.

Mas información:

Necesidad de Ramas

El siguiente esquema muestra el sistema de ramas que se va a usar en clase. Mas información en A successful Git branching model

Ejemplo de Ramas

Ramas a crear:

  • develop: Lo que se ha desarrollando y el equipo de desarrollo dice que ya funciona. Cuando se quiera se pasa a release.
  • release: Lo que se esta probando en un entorno similar al de producción. Cuando está probado, se copia a master.
  • master: Lo que ya se puede instalar en el producción.
  • rama de funcionalidad: Cada vez que alguien quiere hacer algo , crea una rama desde develop y cuando acaba la fusiona en develop.
En la rama de funcionalidad se pueden hacer todos los commits que queramos ya que luego se van a unificar en uno solo. Es lo que llamamos "microcommits". Es así ya que son commits parciales que se hacen para acabar la tarea pero finalmente en la rama develop queremos que sean un solo commit.

Pasos a seguir para hacer una modificación.

  • Crea la rama feature desde develop.
  • Realizar la tarea con tantos commits como sea necesario.
  • Mergear la rama develop en feature ya que así se resuelven los problemas de mergeo en la rama feature
  • Ir a la rama develop y mergear la rama feature con --squash
  • Borrar la rama feature
  • Subir la rama develop
  • Mergear la rama develop en release y subir release
  • Mergear la rama release en master y subir master

Usando Ramas

Veamos ahora como se trabaja con ramas

  • Crear una rama nueva y subirla
git branch nuevaRama
git checkout nuevaRama
git push -u origin nuevaRama



  • Bajar una nueva rama
git fetch --prune   
git checkout nuevaRama
  • fetch:Se pone --prune , para que borre las referencias locales de ramas remotas que ya no están.
  • checkout: Por defecto al cambiar a la nueva rama ya se hace un --track a origin/nuevaRama



  • Borrar una rama en local que ha sido mergeada o subida
git branch -d miRama
git branch --delete miRama



  • Borrar una rama en local que NO ha sido mergeada ni subida (hay 3 formas distintas). Pero es usar el modificador -f o --force
git branch -d -f      miRama
git branch --delete --force miRama
git branch -D         miRama



  • Borrar una rama en remoto
git push origin --delete miRama



Merge

El merge es unir los commit de una rama en otra. Hay muchas formas de hacer un merge , veamos algunas de ellas.

Vamos a suponer que queremos hacer un merge de la rama "mirama" en la rama actual , los posibles comandos son:

Comando Características Cuando usarlo
git rebase rama Pone los commits en la nueva rama siempre después de los que ya hay, es decir que los reordena Poner los commits de origin/develop en nuestra develop porque hay commits distintos en cada rama pero del mismo commit origen
git merge --squash rama Junta todos los "microcommits" de la rama en uno solo en la rama destino. Es necesario acto seguido el commit De una rama feature a develop
git merge --ff-only rama Nunca crea nuevos commits en la rama destino pero falla si es necesario crear un nuevo commit,
por lo que --ff-only ayuda a detectar si hay algún problema
De develop a Release
De release a master o para actualizar cualquier rama desde GitHub cuando no hay commits nuevos en local
git merge rama Es el merge normal que puede crear nuevos commits De una rama develop a feature.
Para resolver los conflictos desde nuestra rama feature ya que nos da igual si hay nuevos commits


git rebase rama

Pone los commits en la nueva rama siempre después de los que ya hay, es decir que los reordena.

Se usa para poner los commits de origin/develop en nuestra develop de antes que lo de develop porque hay commits distintos en cada rama pero del mismo commit origen


git merge --squash rama

Junta todos los "microcommits" de la rama en uno solo en la rama destino. Es necesario acto seguido el commit

Se usa para pasar los microcommits de una rama feature a develop


git merge --ff-only rama

Solo adelanta el puntero de donde está la rama. Nunca crea nuevos commits en la rama destino pero falla si es necesario crear un nuevo commit,
por lo que --ff-only ayuda a detectar si hay algún problema.

Se usa De develop a Release.De release a master o para actualizar cualquier rama desde GitHub cuando no hay commits nuevos en local


git merge rama

Es el merge normal que puede crear nuevos commits | De una rama develop a feature.

Se usa para resolver los conflictos desde nuestra rama feature ya que nos da igual si hay nuevos commits

Usos de Merge

  • Bajar (o actualizar) una rama ( como master, release o develop) desde Github,suponiendo que no va a haber problemas. Es decir que no hemos hecho nosotros un commit en ese rama desde la última vez que la bajamos.
git fetch --prune
git checkout develop
git merge --ff-only origin/develop
git fetch --prune
git checkout release
git merge --ff-only origin/release
git fetch --prune
git checkout master
git merge --ff-only origin/master



  • mergear , develop en release o release en master (suponiendo que están actualizadas ambas ramas porque las hemos actualizado con las órdenes anteriores) y que no hemos hecho commits directamente ni en release ni en master.
git checkout release
git merge --ff-only develop
git checkout master
git merge --ff-only release



  • Mergear (rebase) los cambios de origin/develop en nuestra develop si hay commits distintos en develop y origin/develop.
git fetch --prune
git checkout develop
git rebase origin/develop

Lo normal es hacer el rebase cuando al hacer un git push se produce el siguiente error:

 ! [rejected]        develop -> develop (fetch first)
error: falló el push de algunas referencias a 'https://github.com/usuario/repositorio.git'
ayuda: Actualizaciones fueron rechazadas porque el remoto contiene trabajo que
ayuda: no existe localmente. Esto es causado usualmente por otro repositorio 
ayuda: realizando push a la misma ref. Quizás quiera integrar primero los cambios
ayuda: remotos (ej. 'git pull ...') antes de volver a hacer push.
ayuda: Vea 'Notes about fast-forwards0 en 'git push --help' para detalles.



  • Merge en develop de nuestra rama de feature con un solo commit con --squash (Antes hemos actualizado develop desde GitHub).
git checkout develop
git merge  --squash lorenzo_42
git commit -am "feat(#42):pantalla de Login"
Recuerda hacer siempre después del git merge --squash el commit



  • Mergear los cambios de develop en nuestra rama para ir solucionado los conflictos poco a poco (Antes hemos actualizado develop desde GitHub).
git checkout lorenzo_42
git merge develop



A partir de la versión 2.27 , al hacer un git pull aparece el siguiente mensaje
logongas@beren:~/Documentos/ensenyament/2daw-daw/prueba_daw$ git pull
ayuda: Hacer un pull sin especificar cómo reconciliar las ramas es poco
ayuda: recomendable. Puedes eliminar este mensaje usando uno de los
ayuda: siguientes comandos antes de tu siguiente pull:
ayuda: 
ayuda:   git config pull.rebase false  # hacer merge (estrategia por defecto)
ayuda:   git config pull.rebase true   # aplicar rebase
ayuda:   git config pull.ff only       # aplicar solo fast-forward
ayuda: 
ayuda: Puedes reemplazar "git config" con "git config --global" para aplicar
ayuda: la preferencia en todos los repositorios. Puedes también pasar --rebase,
ayuda: --no-rebase, o --ff-only en el comando para sobreescribir la configuración
ayuda: por defecto en cada invocación.
ayuda: 

Es decir que avisa que se configure para saber que hacer en caso de problemas, si con Fast-Forward, con un rebase o con merge. Así que como siempre hemos recomendado , es mejor no usar git pull ya que así decidimos nosotros que hacer o en el peor de los casos indicar para que haga siempre un --ff-only mediante al orden:

git config --global pull.ff only

De esa forma podremos hacer un git pull de forma segura (siempre y cuando no estés en otro ordenador donde no lo hayan configurado así :-(). Aunque mejor aun es dehabilitar git pull: Can I disable git pull?

Mas información:

Mas información:

Conflictos

En caso de hacer un git merge o un git rebase, etc. se puede producir un conflicto. Que consiste en que git no sabe como fusionar los ficheros. En ese caso lo primero es resolver cada conflicto en cada fichero.

Conflicto en merge

Imaginemos que queremos mergear una rama de funcionalidad sobre develop.

git checkout develop
git merge --squash feature_lorenzo_45

Si hay un conflicto se producirá el siguiente mensaje:

Auto-fusionando index.html
CONFLICTO (contenido): Conflicto de fusión en index.html
Commit de squash -- no actualizando HEAD
Fusión automática falló; arregle los conflictos y luego realice un commit con el resultado.

En ese caso deberemos editar el fichero index.html y arreglar el conflicto que tiene un aspecto similar al siguiente:

<html>
	<body>
<<<<<<< HEAD
		<h1>Hola mundo</h1>
=======
		<h1>Adios planeta</h1>
>>>>>>> feature_lorenzo_45
	</body>
</html>

Ahí se indica las lineas que debemos unificar.Y para arreglarlo hay eliminar las líneas que delimitan el conflicto.Que dando por ejemplo así:

<html>
	<body>
		<h1>Hola planeta</h1>
	</body>
</html>

y finalmente hacer el git commit

git commit -am "feat(#45):Nueva cabecera"

Conflicto en rebase

Imaginemos que queremos mergear la rama origin/develop sobre develop.

git checkout develop
git rebase origin/develop

Si hay un conflicto se producirá el siguiente mensaje:

En primer lugar, rebobinando HEAD para después reproducir tus cambios encima de ésta...
Aplicando: feat(#50):Cabecera tercera
Usando la información del índice para reconstruir un árbol base...
M	index.html
Retrocediendo para parchar base y fusión de 3-vías...
Auto-fusionando index.html
CONFLICTO (contenido): Conflicto de fusión en index.html
error: Falló al fusionar en los cambios.
El parche falló en 0001 feat(#50):Cabecera tercera
Use 'git am --show-current-patch' para ver el parche fallido

Resuelva todos los conflictos manualmente ya sea con 
"git add/rm <archivo_conflictivo>", luego ejecute "git rebase --continue".
Si prefieres saltar este parche, ejecuta "git rebase --skip" .
Para abortar y regresar al estado previo al "git rebase", ejecuta "git rebase --abort".

Ahora debemos como antes arreglar el conflicto editando el fichero index.html pero ahora deberemos hacer dos cosas mas:

git add index.html 
git rebase --continue

Es decir añadir el fichero que ha dado el conflicto con un git add y luego hacer un git rebase --continue para que se acabe de fusionar.

El ejemplo completo lo podemos ver aqui:

#Subimos los cambios de develop
git push
#SI da algún problema, bajamos los cambios
git fetch --prune
git checkout develop
git rebase origin/develop
#SI hay algún conflicto lo resolvemos
vi ficheroN_del_conflicto
#Es necesario hacer el git add para añadir los ficheros modificados por el conflicto
git add ficheroN_del_conflicto
#Continuamos el rebase para acabar de hacer los cambios
git rebase --continue
#Y finalmente ya podemos subirlos
git push

  • Y para acabar un ejemplo para hacer un commit , mergearlos a las otras 2 ramas y subirlo

#Bajarte la última versión de todo
git fetch --prune && git checkout develop && git merge --ff-only origin/develop && git checkout release && git merge --ff-only origin/release && git checkout master && git merge --ff-only origin/master && git checkout develop
#Hacer el commit
git commit -am "mensaje"
#Hacer los merges con las otras 2 ramas
git checkout release && git merge --ff-only develop && git checkout master && git merge --ff-only release
#Subir los cambios de las 3 ramas
git checkout master && git push && git checkout release && git push && git checkout develop && git push

Mas cosas de Git

Para acabar dejamos alguna pincelada mas de cosas que existen en Git pero que no vamos a ver:

git commit --fixup <commit>  
git rebase -i --autosquash

  • Stash

git stash
git stash pop

  • Cherry-pick

Recetas

  • Bajarse lo último de las 3 ramas.

git fetch --prune && git checkout develop && git merge --ff-only origin/develop && git checkout release && git merge --ff-only origin/release && git checkout master && git merge --ff-only origin/master && git checkout develop

  • Hacer un merge de las 3 ramas

git checkout release && git merge --ff-only develop && git checkout master && git merge --ff-only release && git checkout develop

  • Subir las 3 ramas

git checkout master && git push && git checkout release && git push && git checkout develop && git push

Ejercicios

Ejercicio 1

  • Crea un proyecto de Git con dos ficheros
  • Luego crea las siguientes tres ramas:
    • master
    • release
    • develop
  • Sube las 3 ramas a GitHub.
  • Desde develop ahora crea una rama llamada feature_40
  • Añade un nuevo fichero a la rama feature_40 y modifica el fichero varias veces para crear varios "microcommits".
  • Sube la rama feature_40
  • Mergea la rama feature_40 en develop
  • Borra la rama feature_40 en local
  • Borra la rama feature_40 en remoto
  • Mergea la rama develop en release
  • Mergea la rama release en master
  • Sube las ramas develop, release y master a GitHub

Ejercicio 2

Vamos a seguir con el ejercicio anterior pero ahora con 2 usuarios distintos (se puede hacer en 2 carpetas distintas)

  • Usuario 1:Desde develop ahora crea una rama llamada feat_50, añade un fichero y modifica el fichero varias veces para crear varios "microcommits". Sube la rama a GitHub
  • Usuario 2:Desde develop ahora crea una rama llamada fix_51, añade otro fichero y modifica el fichero varias veces para crear varios "microcommits". Sube la rama a GitHub
  • Usuario 1: Baja la rama develop de remoto
  • Usuario 2: Baja la rama develop de remoto
  • Usuario 1: Mergea la rama feat_50 en develop
  • Usuario 2: Mergea la rama fix_51 en develop
  • Usuario 1: Borra la rama feat_50 en local y en remoto
  • Usuario 2: Borra la rama feat_51 en local y en remoto
  • Usuario 1: Mergea la rama develop en release
  • Usuario 1: Mergea la rama release en master
  • Usuario 1: Sube las ramas develop, release y master a GitHub
  • Usuario 2: Sube la rama develop a remoto. No te dejará.
  • Usuario 2: Baja los cambios de develop en remoto y haz un rebase para mergearlos
  • Usuario 2: Sube la rama develop a remoto. Ya te dejará.
  • Usuario 2: Mergea la rama develop en release
  • Usuario 2: Mergea la rama release en master
  • Usuario 2: Sube las ramas develop, release y master a GitHub

Ejercicio 3

Vamos a seguir con el ejercicio anterior pero ahora con 2 usuarios distintos (se puede hacer en 2 carpetas distintas).

  • Usuario 1:Desde develop ahora crea una rama llamada feat_60, modifica un fichero y hazlo varias veces para crear varios "microcommits". Sube la rama a GitHub
  • Usuario 2:Desde develop ahora crea una rama llamada feat_61, modifica el mismo fichero y en las mismas lineas y hazlo varias veces para crear varios "microcommits". Sube la rama a GitHub
  • Usuario 1: Baja la rama develop de remoto
  • Usuario 2: Baja la rama develop de remoto
  • Usuario 1: Mergea la rama feat_60 en develop
  • Usuario 2: Mergea la rama feat_61 en develop
  • Usuario 1: Borra la rama feat_60 en local y en remoto
  • Usuario 2: Borra la rama feat_61 en local y en remoto
  • Usuario 1: Mergea la rama develop en release
  • Usuario 1: Mergea la rama release en master
  • Usuario 1: Sube las ramas develop, release y master a GitHub
  • Usuario 2: Sube la rama develop a remoto. No te dejará.
  • Usuario 2: Baja los cambios de develop en remoto y haz un rebase para mergearlos. Tendrás que solucionar el conflicto
  • Usuario 2: Sube la rama develop a remoto. Ya te dejará.
  • Usuario 2: Mergea la rama develop en release
  • Usuario 2: Mergea la rama release en master
  • Usuario 2: Sube las ramas develop, release y master a GitHub

Ejercicio 4

Vamos a seguir con el ejercicio anterior pero ahora con 2 usuarios distintos (se puede hacer en 2 carpetas distintas).

  • Usuario 1:Desde develop ahora crea una rama llamada feat_70, modifica un fichero y hazlo varias veces para crear varios "microcommits". Sube la rama a GitHub
  • Usuario 1: Mergea la rama feat_70 en develop
  • Usuario 2:Desde develop ahora crea una rama llamada feat_71, modifica el mismo fichero y en las mismas lineas y hazlo varias veces para crear varios "microcommits". Sube la rama a GitHub
  • Usuario 2: Mergea la rama feat_71 en develop
  • Usuario 2:Desde develop ahora crea una rama llamada feat_72, modifica el mismo fichero y en las mismas lineas y hazlo varias veces para crear varios "microcommits". Sube la rama a GitHub
  • Usuario 2: Mergea la rama feat_72 en develop
  • Usuario 1: Borra la rama feat_70 en local y en remoto
  • Usuario 2: Borra la rama feat_71 en local y en remoto
  • Usuario 2: Borra la rama feat_72 en local y en remoto
  • Usuario 1: Mergea la rama develop en release
  • Usuario 1: Mergea la rama release en master
  • Usuario 1: Sube las ramas develop, release y master a GitHub
  • Usuario 2: Sube la rama develop a remoto. No te dejará.
  • Usuario 2: Baja los cambios de develop en remoto y haz un rebase para mergearlos. Tendrás que solucionar varias veces el conflicto ya que había varios commits pendientes.
  • Usuario 2: Sube la rama develop a remoto. Ya te dejará.
  • Usuario 2: Mergea la rama develop en release
  • Usuario 2: Mergea la rama release en master
  • Usuario 2: Sube las ramas develop, release y master a GitHub

Ejercicio 5

Crea un nuevo proyecto en Git.

  • Usuario 1:Crea una rama llamada prueba y la subes a Git
  • Usuario 2: Haz un Pull y comprueba que existe la rama origin/prueba en local y prueba en remoto
  • Usuario 1: Borra la rama prueba en local
  • Usuario 2: Haz un Fetch y comprueba que aun está la rama origin/prueba en local y prueba en remoto
  • Usuario 1: Borra la rama prueba en remoto
  • Usuario 2: Fetch (SIN PRUNE) y comprueba que aun está la rama origin/prueba en local pero ya NO está prueba en remoto
  • Usuario 2: Fetch (CON PRUNE) y ya NO está la rama origin/prueba en local
clase/daw/daw/2eval/tema06.1636890257.txt.gz · Última modificación: 2021/11/14 12:44 por admin