En este tema vamos a ver sobre todo a tratar con ramas, merges y conflictos.
Mas información:
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:
release
.master
.develop
y cuando acaba la fusiona en develop
. develop
queremos que sean un solo commit.
Pasos a seguir para hacer una modificación.
feature
desde develop
.develop
en feature
ya que así se resuelven los problemas de mergeo en la rama feature
develop
y mergear la rama feature
con --squash
feature
develop
develop
en release
y subir release
release
en master
y subir master
Veamos ahora como se trabaja con ramas
git branch nuevaRama git switch nuevaRama git push --set-upstream origin nuevaRama git push -u origin nuevaRama
git fetch --prune git switch nuevaRama
fetch
:Se pone --prune
, para que borre las referencias locales de ramas remotas que ya no están.switch
: Por defecto al cambiar a la nueva rama ya se hace un --track
a origin/nuevaRama
git branch --delete miRama git branch -d miRama
-f
o --force
git branch --delete --force miRama git branch -d -f miRama git branch -D miRama
git push origin --delete miRama
El merge es unir los commit de una rama en otra. Hay muchas formas de hacer un merge , veamos algunas de ellas.
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 |
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 commit -m "E"
git fetch --prune
git switch develop
git rebase origin/develop
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
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 fetch --prune
git merge --ff-only origin/develop
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
git fetch --prune git switch develop git merge --ff-only origin/develop git fetch --prune git switch release git merge --ff-only origin/release git fetch --prune git switch master git merge --ff-only origin/master
git switch release git merge --ff-only develop git switch master git merge --ff-only release
git fetch --prune git switch 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.
--squash
(Antes hemos actualizado develop desde GitHub).
git switch develop git merge --squash lorenzo_42 git commit -am "feat(#42):pantalla de Login"
git merge --squash
el commit
git switch lorenzo_42 git merge develop
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:
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.
Imaginemos el mismo fichero index.html
en 2 ramas distintas:
Nuestra Rama | Rama a Fusionar |
---|---|
<html> <body> <h1>Hola mundo</h1> </body> </html> | <html> <body> <h1>Adios planeta</h1> </body> </html> |
Cuando se produce el conflicto, el fichero resultante queda de la siguiente forma:
<html> <body> <<<<<<< HEAD <h1>Hola mundo</h1> ======= <h1>Adios planeta</h1> >>>>>>> Rama a Fusionar </body> </html>
Ahora tenemos que decidir como resolver el conflicto que el resultado definitivo ya depende del código que estemos fusionando. Un posible resultado podría ser:
<html> <body> <h1>Hola y Adios mundo</h1> </body> </html>
Imaginemos que queremos mergear la rama origin/develop
sobre 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 aquí:
git switch develop git rebase origin/develop vi index.html #Arreglar el conflicto git add index.html git rebase --continue
Imaginemos que queremos mergear una rama de una funcionalidad llamada "Lorenzo_3" sobre develop
.
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.
Ahora debemos como antes arreglar el conflicto editando el fichero index.html
y hacer el commit que de todas formas ya íbamos a hacer
git commit -am "feat(#45):Nueva cabecera"
El ejemplo completo lo podemos ver aqui:
git switch develop git merge --squash Lorenzo_3 vi index.html #Arreglar el conflicto git commit -am "feat(#45):Nueva cabecera"
Con un fast-forward nunca se puede producir un conflicto.
Imaginemos que queremos mergear los cambios de develop
en la rama Lorenzo_3
Si hay un conflicto se producirá el siguiente mensaje:
Auto-fusionando index.html CONFLICTO (contenido): Conflicto de fusión en index.html Fusión automática falló; arregle los conflictos y luego realice un commit con el resultado.
Ahora debemos como antes arreglar el conflicto editando el fichero index.html
y el --continue
:
git add index.html git merge --continue
Es decir añadir el fichero que ha dado el conflicto con un git add
y luego hacer un git merge --continue
para que se acabe de mergear.
El ejemplo completo lo podemos ver aqui:
git switch Lorenzo_3 git merge develop vi index.html #Arreglar el conflicto git add index.html git merge --continue
git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop
git switch release && git merge --ff-only develop && git switch master && git merge --ff-only release && git switch develop
git switch master && git push && git switch release && git push && git switch develop && git push
#Día 1:Lunes git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop git branch lorenzo_45 git switch lorenzo_45 git push --set-upstream origin lorenzo_45 git commit -m "micro-commit-dia-1-a" git commit -m "micro-commit-dia-1-b" git push #Día 2:Martes git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop git switch lorenzo_45 git merge develop git commit -m "micro-commit-dia-2-a" git commit -m "micro-commit-dia-2-b" git commit -m "micro-commit-dia-2-c" git push #Día 3:Miercoles git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop git switch lorenzo_45 git merge develop git commit -m "micro-commit-dia-3-a" git commit -m "micro-commit-dia-3-b" git commit -m "micro-commit-dia-3-c" git push #Día 4: Jueves git fetch --prune && git switch develop && git merge --ff-only origin/develop && git switch release && git merge --ff-only origin/release && git switch master && git merge --ff-only origin/master && git switch develop git switch lorenzo_45 git merge develop git switch develop git merge --squash lorenzo_45 git commit -am "feat(#45):Crear la pantalla de login" git push #Si falla el push hacer el fetch y rebase git fetch --prune git rebase origin/develop git push origin --delete lorenzo_45 git branch --delete lorenzo_45
feature_40
feature_40
y modifica el fichero varias veces para crear varios "microcommits".feature_40
feature_40
en develop
feature_40
en localfeature_40
en remotodevelop
en release
release
en master
develop
, release
y master
a GitHubVamos a seguir con el ejercicio anterior pero ahora con 2 usuarios distintos (se puede hacer en 2 carpetas distintas)
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 GitHubdevelop
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 GitHubdevelop
de remotodevelop
de remotofeat_50
en develop
fix_51
en develop
feat_50
en local y en remoto feat_51
en local y en remoto develop
en release
release
en master
develop
, release
y master
a GitHubdevelop
a remoto. No te dejará. develop
en remoto y haz un rebase para mergearlosdevelop
a remoto. Ya te dejará.develop
en release
release
en master
develop
, release
y master
a GitHub Vamos a seguir con el ejercicio anterior pero ahora con 2 usuarios distintos (se puede hacer en 2 carpetas distintas).
develop
ahora crea una rama llamada feat_60
, modifica un fichero y hazlo varias veces para crear varios "microcommits". Sube la rama a GitHubdevelop
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 GitHubdevelop
de remotodevelop
de remotofeat_60
en develop
feat_61
en develop
feat_60
en local y en remoto feat_61
en local y en remoto develop
en release
release
en master
develop
, release
y master
a GitHubdevelop
a remoto. No te dejará. develop
en remoto y haz un rebase para mergearlos. Tendrás que solucionar el conflictodevelop
a remoto. Ya te dejará.develop
en release
release
en master
develop
, release
y master
a GitHub Vamos a seguir con el ejercicio anterior pero ahora con 2 usuarios distintos (se puede hacer en 2 carpetas distintas).
develop
ahora crea una rama llamada feat_70
, modifica un fichero y hazlo varias veces para crear varios "microcommits". Sube la rama a GitHubfeat_70
en develop
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 GitHubfeat_71
en develop
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 GitHubfeat_72
en develop
feat_70
en local y en remoto feat_71
en local y en remoto feat_72
en local y en remoto develop
en release
release
en master
develop
, release
y master
a GitHubdevelop
a remoto. No te dejará. develop
en remoto y haz un rebase para mergearlos. Tendrás que solucionar varias veces el conflicto ya que había varios commits pendientes.develop
a remoto. Ya te dejará.develop
en release
release
en master
develop
, release
y master
a GitHub Crea un nuevo proyecto en Git.
prueba
y la subes a Gitorigin/prueba
en local y prueba
en remotoprueba
en localorigin/prueba
en local y prueba
en remotoprueba
en remotoorigin/prueba
en local pero ya NO está prueba
en remotoorigin/prueba
en local