34
loading...
This website collects cookies to deliver better user experience
$ git log --graph --format='%C(auto)%h %s%n%C(auto)%d%n' --all
git merge
o git pull
(sí, porque git pull
hace merges por debajo), mientras que el resto de los commits suelen ser resultado de git commit
, aunque también serlo de git revert
o de git merge --squash
.git commit
o git merge
estando en esa rama (por ej. la rama "pippin-merry" estaba en el commit "pippin + merry: camino a insengard", y se modifico automáticamente para referenciar a "pippin-merry: concilio de los ents" cuando se hizo dicho commit). 872cac9
).git pull
o sincronizar las ramas locales con las ramas del repositorio remoto git push
, hay que tener en cuenta una serie de cosas que se tratarán en el siguiente post.HEAD
siempre indica el commit actual y HEAD~
siempre indica el commit anterior.master
indica el último commit de la master
y master~
indica el commit anterior.872cac9
indica el commit 872cac9
y 872cac9~
indica el commit anterior.git reset HEAD~
es mucho más rápido que git log
para obtener el hash del commit anterior y luego hacer git reset <hash>
.~
es una "referencia por ancestro" que indica el commit padre. Se pueden añadir todos los ~
que se quieran para obtener referencias a commits anteriores; HEAD~
referencia al commit "padre"; HEAD~~
, o HEAD~2
referencian al commit "abuelo"; HEAD~3
referencian al "bisabuelo"; etc.^1
, o simplemente ^
, y ^2
, para hacer referencias a los commits implicados en merge commits ; si HEAD
es un merge commit, HEAD^
es equivalente a HEAD~
, e indica el commit en el que se estaba cuando se hizo git merge
; HEAD^2
indica el último commit de la rama con la que se hizo merge.HEAD^2~2
.git branch -m
.# git status para ver la rana actual.
$ git status
En la rama fature
nada para hacer commit, el árbol de trabajo está
limpio
# O git status para ver todas las ramas,
# con un * delante de la rama actual.
$ git branch
dovolop
* fature
master
# Renombrar la rama actual.
$ git branch -m feature
# Renombrar otra rama.
$ git branch -m dovolop develop
$ git branch
develop
* feature
master
git branch --delete <rama>
o git branch -d <rama>
: Git comprobará si <rama>
esta mergeada en la rama actual, y de no estarla, no permitirá borrar la rama, evitando así que puedan perderse commits.git branch --delete --force <rama>
o git branch -D <rama>
: borra la rama, este o no mergeada en la rama actual.git branch -d
para ir sobre seguro, y git branch -D
solo para esos casos en los que se esta completamente seguro.git branch <rama> <hash>
, donde <hash>
indicaría el último commit de la rama en el momento de borrarla. git reflog
puede ser una buena opción para buscarlo, ya que muestra un histórico de todos los commits por los que se ha pasado. En Deshacer un git reset hay más detalles sobre git reflog
.git reflog
puede no ser la mejor opción, ya que el hash que se busca puede estar enterrado entre muchos otros. Documentándome para el post he visto opciones mejores como esta o esta, pero personalmente no me ha surgido el caso de tener que recuperar una rama borrada hace semanas.$ git branch -vv
feature/create-home 6748ee2 crear hoja de estilos home.css
feature/setup-project 9e75aa0 añadido .gitignore
* master 9e75aa0 añadido .gitignore
# Como la rama feature/setup-project está mergeada en master
# se borra sin problemas.
$ git branch -d feature/setup-project
Eliminada la rama feature/setup-project (era 9e75aa0)..
# Como la rama feature/create-home no está mergeada en master
# borrarla con -d da error.
$ git branch -d feature/create-home
error: La rama 'feature/create-home' no ha sido fusionada completamente.
Si estás seguro de querer borrarla, ejecuta 'git branch -D feature/create-home'.
# Si se fuerza el borrado si que deja.
$ git branch -D feature/create-home
Eliminada la rama feature/create-home (era 6748ee2)..
# Pero me doy cuenta de mi error :(
# Así que busco el commit.
$ git reflog
...
9e75aa0 (HEAD -> master) HEAD@{6}: checkout: moving from feature/create-home to master
# Y recreo la rama.
$ git branch feature/create-home 6748ee2
$ git branch -vv
feature/create-home 6748ee2 crear hoja de estilos home.css
* master 9e75aa0 añadido .gitignore
git merge
puede hacer cosas distintas dependiendo de las diferencias que haya entre la rama actual y la rama que se quiere mergear.target
, ha partido del último commit de la rama actual; en este caso git merge
simplemente modificará la referencia de la rama actual para que apunte al mismo commit que la rama target
.feature/create-home
en la rama master
; dado que feature/create-home
parte de master
git merge
por defecto hará fast forward.$ git status
En la rama master
$ git merge feature/create-home
Actualizando 85b13b4..82975ee
Fast-forward
home.css | 3 +++
home.html | 2 ++
2 files changed, 5 insertions(+)
create mode 100644 home.css
create mode 100644 home.html
git merge
creará un merge commit.$ git status
En la rama master
$ git merge feature/create-home
# Se abre un editor de texto para poder personalizar el
# mensaje del commit.
# Tras guardar el mensaje:
Merge made by the 'recursive' strategy.
home.css | 3 +++
home.html | 2 ++
2 files changed, 5 insertions(+)
create mode 100644 home.css
create mode 100644 home.html
git reset --hard
para hacer tabla rasa y empezar de cero, porque hay veces en que los conflictos se resuelven y los tests dejan de pasar, o simplemente porque los conflictos son complicados y se prefiere empezar fresco después de una pausa.<<<<<<< HEAD
<a href="contact.html">Contacto</a>
=======
<h1> Home </h1>
<p> bienvenido </p>
>>>>>>> feature/create-home
<<<<<<<<
y =======
esta lo que hay en la rama actual, y entre ========
y >>>>>>
lo que hay en la rama a mergear.$ git merge feature/create-home
CONFLICTO (add/add): Conflicto de merge en home.html
Auto-fusionando home.html
Fusión automática falló; arregle los conflictos y luego realice
un commit con el resultado.
# Resolver conflictos.
$ git commit -a
[master 1814deb] Merge branch 'feature/create-home'
doThings
a createUser
, junto con todos sus usos, y se mergease una rama que ha introducido un nuevo uso de doThings
en un nuevo archivo, git merge
puede no encontrar conflictos y mergear automáticamente, pero cuando se invoque doThings
en el nuevo archivo se producirá un error, ya que doThings
ha dejado de existir. git merge
para controlar como se hace el merge:
--ff-only
para indicar que solo se quiere hacer merge si es fast forward, fallando en caso contrario ( por ej. git merge --ff-only feature/create-home
).
Puede ser útil para actualizar ramas importantes como master
con total tranquilidad.--no-commit
fuerza a que si el merge implica un merge commit, Git se detenga justo antes de hacer el commit, como haría si hubiese conflictos; en ese momento se podrán revisar los cambios, ejecutar los tests, arreglar alguna cosilla su fuese necesario, y finalmente, hacer el commit.
Si el merge es fast forward este se hará automáticamente usando la estrategia de fast forward, ignorando el flag --no-commit
.git branch <rama>
.git cherry-pick
de los commits que se quieren mover.hotfix
de la rama de integración develop
, en lugar de haberlo hecho de la rama principal master
.hotfix
para que parta de master
:master
y click en "Reset current branch to here" o similar.git checkout -B hotfix master
.git rebase
, aunque hay que visualizar muy bien lo que se quiere hacer antes de usarlo.hotfix
.hotfix
para que apunte al punto correcto con "Reset current branch to here" si se una GUI o git checkout -B hotfix master
si se usa consola.git cherry-pick
git rebase
es git rebase <rama-destino> <rama-a-mover>
, o, si ya se está en <rama-a-mover>
, simplemente git rebase <rama-destino>
; haciendo un símil, sería como "trasplantar la rama".git rebase master hotfix
movería los commits de la rama hotfix
para que salgan del commit G
en lugar del commit E
.A'
es una copia A
pero con distinto padre; decir "mover" no es del todo correcto, pero es una simplificación bastante útil).git rebase
mueve todos los commits de <rama-a-mover>
que no tiene <rama-destino>
, incluso aunque alguno de esos commits estén compartidos con otra rama.git rebase master hotfix
movería los commits E y F
, que solo tiene hotfix
, y copiaría los commits C, D y F
, que hotfix
comparte con la rama develop
y que no están en en master
.hotfix
y develop
en master
no habría conflictos porque, aunque los commits C', D' y F'
estén duplicados en la rama develop
, Git detectaría que son lo mismo.git rebase --onto <rama-destino> <desde-la-rama> <rama-a-mover>
git rebase --onto master develop hotfix
movería solo los commits E y F
, que están en la rama hotfix
y salen de la rama develop
.git rebase
es lo que menos comandos requiere, pero en contra tiene que lleva su tiempo visualizarlo.git rebase
es que puede implicar resolver conflictos varias veces si las ramas de origen y destino son muy distintas; si eso ocurre, siempre se puede dar marchar atrás con git rebase --abort
y replantarse la estrategia.git revert
.git revert
de cada uno de los commits que se han añadido con el merge, empezando por el más reciente.git reset -m1 <hash>
, donde -m1
indica que se desean deshacer los cambios que vinieron de <rama>
cuando se hizo git merge <rama>
.git reset -m2 <hash>
para indicar que se desean deshacer las diferencias que había en la rama en la que se hizo git merge <rama>
con respecto de <rama>
, para que tras el git revert
se tenga lo mismo que en <rama>
.# Acabo de hacer un merge y lo quiero deshacer.
# Hago git log -1 para ver la información del último commit.
# 'Merge: 6512051 6748ee2' me dice que
# estaba en el commit 6512051 cuando hice el merge
# de otra rama que a su vez estaba en el commit 6748ee2.
$ git log -1
commit 7a12efcf980753856b67b72b040a73a93cdb3c9b (HEAD -> master)
Merge: 6512051 6748ee2
Merge branch 'feature/create-home'
# Compruebo cuales son las diferencias entre el commit
# 6512051 y el commit en el que estoy.
$ git diff 6512051 HEAD
diff --git a/home.css b/home.css
new file mode 100644
index 0000000..6748ee2
--- /dev/null
+++ b/home.css
...
diff --git a/home.html b/home.html
new file mode 100644
index 0000000..6141d5d
--- /dev/null
+++ b/home.html
...
# Hago el revert del merge indicando con -m1 que quiero
# tomar como referencia lo que había antes del merge.
$ git revert -m1 7a12efcf980753856b67b72b040a73a93cdb3c9b
[master f65033c] Revert "Merge branch 'feature/create-home'"
1 file changed, 2 deletions(-)
# log -1 me indica que hay nuevo commit.
$ git log -1 f65033c
commit f65033c1cb53ab664482d9d7ee3f836a493e249f
Revert "Merge branch 'feature/create-home'"
This reverts commit 7a12efcf980753856b67b72b040a73a93cdb3c9b, reversing
changes made to 651205183ba4da49663163b881901c74e8c98606.
# Compruebo los cambios y no hay diferencias.
$ git diff 6512051 HEAD
<rama>
, git merge <rama>
dirá que "la rama ya está actualizada" y no hará nada, aunque quizá lo natural sería pensar que volvería a aplicar los cambios de <rama>
.<rama>
, git merge <rama>
solo aplicará los cambios de los nuevos commits; la "buena" noticia es que en git merge
notificará unos conflictos bastante extraños que harán ver que algo raro pasa.git revert
sólo modifica archivos, no modifica el histórico de commits, así que cuando se le pide a Git que mergee commits que ya tiene en su histórico, se limita a ignorarlos porque ya los tiene.feature/create-home
en la rama master
.git merge --no-ff <rama>
. --no-ff
sirve para forzar que se cree un merge commit, aunque se pudiese hacer fast forward.# Me aseguro de que estoy en la rama master,
# que es donde quiero hacer el merge.
$ git merge status
En la rama master
nada para hacer commit, el árbol de trabajo está limpio
$ git merge --no-ff feature/create-home
Merge made by the 'recursive' strategy.
home.css | 3 +++
home.html | 2 ++
2 files changed, 5 insertions(+)
create mode 100644 home.css
create mode 100644 home.html
git merge --squash <rama>
.git commit
, cuyo mensaje por defecto será un sumario de todos los commits de <rama>
, aunque se podrá personalizar.# Me aseguro de que estoy en la rama master,
# que es donde quiero hacer el merge.
$ git merge status
En la rama master
nada para hacer commit, el árbol de trabajo está limpio
$ git merge --squash feature/create-home
Actualizando 85b13b4..82975ee
Fast-forward
Commit de squash -- no actualizando HEAD
home.css | 3 +++
home.html | 2 ++
2 files changed, 5 insertions(+)
create mode 100644 home.css
create mode 100644 home.html
$ git commit
[master 1a5ee55] Squashed commit of the following:
2 files changed, 5 insertions(+)
create mode 100644 home.css
create mode 100644 home.html
$ git log -1
commit 1a5ee55ca09d28b8469385fa6675211ddc2d23ca (HEAD -> master)
Squashed commit of the following:
commit 82975ee0f7f4fcab93e2b0d0d6e9d2f915510881
crear hoja de estilos home.css
commit b9632f136aef8ae41306fc4468aa979800fb330a
crear home.html
A home.css
A home.html
git rebase <rama-destino> <rama-a-mover>
.<rama-a-mover>
, se puede hacer directamente git rebase <rama-destino>
.git merge
para añadir los commits en la rama de integración.# "Replanto" feature/create-home en master.
$ git rebase master feature/create-home
En primer lugar, rebobinando HEAD para después reproducir
tus cambios encima de ésta...
Aplicando: crear home.html
Aplicando: crear hoja de estilos home.css
# Hago checkout en master.
$ git checkout master
Cambiado a rama 'master'
# Hago un merge fast forward de la rama a integrar.
$ git merge --ff-only feature/create-home
Actualizando e157378..d63cc7b
Fast-forward
log.txt | 2 ++
1 file changed, 2 insertions(+)
git rebase
es que puede llegar a ser necesarios resolver conflictos si <rama-a-mover>
parte de un commit antiguo de <rama-destino>
. <rama-a-mover>
tiene varios commits puede llegar a ser necesario resolver conflictos una vez por cada commit. git rebase
, y excepcionalmente, cuando se encuentran un caso donde la resolución de conflictos se complica, usan git merge
para así solo resolver conflictos una única vez.git rebase
seguir las instrucciones que da Git como salida del comando.master
, y todos los commits se hacen sobre ella. master
ha divergido respecto de la rama master
del repositorio remoto, habrá que decidir si optar por merge commits o por rebase.git merge
preserva todo el histórico de commits tal y surgió, pero si no se sigue un buen flujo de ramas puede resultar en un árbol de commits muy complejo, donde sería difícil determinar cuando se introdujo un bloque de código o un bug.git merge --squash
deja un árbol de commits muy sencillo, con una única rama y un único commit por cada feature, pero puede dejar commits muy grandes y se pierde información de los commits individuales.git rebase
produce una única rama con todos los commits que se han hecho, pero se pierde la información de en que punto se inicio una rama y los merges con conflictos pueden ser muy dolorosos.git merge
o git rebase
.git checkout
a ramas, pero también se puede hacer a tags y a commits. En estos últimos casos se pasa al estado "detached HEAD", o "HEAD desacoplada" si se tiene Git configurado en castellano .$ git log --graph --format='%C(auto)%h %s%n%C(auto)%d'
* d63cc7b crear hoja de estilos home.css
| (HEAD -> master, feature/create-home)
* 1676ceb crear home.html
|
* e157378 añadido .gitignore
|
* 85b13b4 set up proyecto
|
* 417ceac commit inicial
# git status indica que estoy en la rama master.
$ git status
En la rama master
nada para hacer commit, el árbol de trabajo está limpio
# Al hacer checkout a un commit se muestra un mensaje
# que da respeto.
$ git checkout e157378
Nota: cambiando a 'e157378'.
Te encuentras en estado 'detached HEAD'. Puedes revisar por aquí, hacer
cambios experimentales y hacer commits, y puedes descartar cualquier
commit que hayas hecho en este estado sin impactar a tu rama realizando
otro checkout.
Si quieres crear una nueva rama para mantener los commits que has creado,
puedes hacerlo (ahora o después) usando -c con el comando checkout. Ejemplo:
git switch -c <nombre-de-nueva-rama>
O deshacer la operación con:
git switch -
Desactiva este aviso poniendo la variable de config advice.detachedHead en false
HEAD está ahora en e157378 añadido .gitignore
# git status en lugar de mostrar un nombre de rama
# muestra un mensaje bastante raro....
$ git status
HEAD desacoplada en e157378
nada para hacer commit, el árbol de trabajo está limpio
# git branch, para ver las ramas, también muestra
# el mensaje raro.
$ git branch
* (HEAD desacoplada en e157378)
master
git checkout
a una rama.git checkout
a otra rama, ya que ese commit se puede llegar a perder a menos que se conozca su clave hash o se use git reflog
(ver Deshacer un commit: como revertir un cambio para más información sobre git reflog
).git cherry pick
.$ git checkout e157378
Nota: cambiando a 'e157378'.
Te encuentras en estado 'detached HEAD'. ...
# Hago algunos cambios en el .gitignore.
$ git commit -am "ignorar más cosas"
[HEAD desacoplado aec5722] ignorar más cosas
1 file changed, 1 insertion(+)
# Cambio de rama por alguna razón y Git da la señal de
# alarma, indicando ademas como se puede recuperar el commit.
$ git checkout master
Peligro: estás saliendo 1 commit atrás, no está conectado
a ninguna rama:
aec5722 ignorar más cosas
Si quieres conservarlo creando una nueva rama, este es un buen momento
para hacerlo:
git branch <nuevo-nombre-de-rama> aec5722
Cambiado a rama 'master'
# Si por alguna razón no hubiese conservado el hash del
# commit, siempre es posible consultarlo en con git reflog.
$ git reflog
d63cc7b (HEAD -> master, feature/create-home) HEAD@{0}: checkout: moving from aec57222a12d12ca6b87f5329ce67c10b5289d0a to master
aec5722 HEAD@{1}: commit: ignorar más cosas
e157378 HEAD@{2}: checkout: moving from master to e157378
d63cc7b (HEAD -> master, feature/create-home) HEAD@{3}: checkout: moving from e15737895b61e4c7e205a8729abad775b6679f5d to master
e157378 HEAD@{4}: checkout: moving from master to e157378
claudio@jupiter2:~/sandbox/git(master)$ git checkout e157378
# Si quiero crear una rama para poder seguir trabajado a
# partir de él,hago como ha dicho Git
$ git branch nuevo-nombre-de-rama aec5722
$ git checkout feature/configure-project
Cambiado a rama 'feature/configure-project'
$ git status
En la rama feature/configure-project
nada para hacer commit, el árbol de trabajo está limpio
34