Deshaciendo git rebase y fixup

Hace unos días publiqué cómo trabajar con Git y rebase, utilizando el comando squash para mezclar commits y agregarlos en uno solo. He estado trabajando bastante más con el tema y tengo un par de cosas interesantes que contaros.

No solamente existe squash

Cuando estamos haciendo un rebase de dos o más commits, hay múltiples comandos que podemos utilizar, siendo squash el más útil para realizar una operación manual. Vamos a verlos con ejemplos:

Volvemos a nuestro repositorio de pruebas: Spoon-Knife del que os recomiendo hacer un fork para vuestras pruebas y hacemos unos cuantos commits a un fichero:

touch mifichero.txt 
echo 'Primer cambio' >> mifichero.txt
git commit -am "Commit inicial con el primer cambio"
echo 'Segundo cambio' >> mifichero.txt
git commit -am "Commit con el segundo cambio"
echo 'Tercer cambio' >> mifichero.txt
git commit -am "Commit con el tercer cambio"

Nota: Con git commit -am hacemos lo mismo que con git commit -a -m que viene a ser lo mismo que hacer git add . y git commit.

El resultado sería más o menos así, con tres commits en nuestro historial:

Ya hemos visto que la utilidad de git rebase es juntar estos cambios en uno solo, para ello vamos a mirar cual es el commit anterior a los nuestros, yo os recomiendo hacerlo con git log:

Y usamos ese hash para nuestro git rebase.

git rebase -i bdd3996d38d885e18e5c5960df1c2c06e34d673f

Ahora nos fijaremos en todas las opciones que nos ofrece git al pedirle un rebase interactivo (-i).

  • p, pick = use commit. Esta es la opción por defecto, conserva el commit y el mensaje.
  • r, reword = use commit, but edit the commit message. Sirve para cambiar el mensaje del commit sin alterarlo.
  • e, edit = use commit, but stop for amending. Es igual que la anterior pero deshace el commit para que podamos cambiar ficheros, mensaje, etc.
  • s, squash = use commit, but meld into previous commit. Junta los commits, es el ejemplo visto en el post anterior sobre git y rebase.
  • f, fixup = like "squash", but discard this commit's log message. Mi nuevo favorito y en el que me voy a fijar ahora, hace un "squash automático" en el sentido que elimina los mensajes de commit.
  • x, exec = run command (the rest of the line) using shell. Ejecuta un comando de shell, no he encontrado ejemplos o utilidad a este todavía pero podrías hacer un listado de ficheros al final por ejemplo.

Utilizando fixup en un git rebase

La operación que más busco últimamente al hacer un rebase, es juntar todos los commits que voy realizando con el primero, normalmente conservando el mensaje inicial, para eso sirve fixup, aglutina todos los cambios de los commits marcados y conserva el mensaje del primero:

git rebase -i bdd3996d38d885e18e5c5960df1c2c06e34d673f

Y al guardar el fichero no nos preguntará nada más, habrá juntado todo el código y conservado el primer mensaje:

Si necesitáis cambiar los mensajes os recomiendo continuar con el método squash, pero fixup os puede ahorrar algunos pasos si no necesitáis modificar nada.

Deshaciendo git rebase

Una de las mayores ventajas que le encuentro a Git es que antes de que hagas push de tus cambios, puedes deshacer todo lo que has hecho, y aunque git rebase junte commits en uno solo, te da la posibilidad de investigar qué ha pasado y deshacer tus cambios, incluso los rebase. Os presento git reflog.

Una vez hecho nuestro rebase anterior, si utilizamos git reflog nos da una salida como esta:

Ya podréis ver que es un histórico bastante adecuado de todo lo que ha pasado en nuestra línea de comandos, permitiéndonos lanzar comandos como el siguiente:

git reset --hard HEAD@{8}

Este comando nos dejará justo después de hacer el tercer commit, pero mucho cuidado que destruirá todos los cambios posteriores. De esta manera podremos empezar de nuevo nuestro rebase o corregir el error que necesitábamos revisar. Podéis encontrar más información práctica sobre git reflog en este hilo de stackoverflow.

Añadir nuevo comentario