comando git rebase: --continue, --abort, cancel, --interactive, squash
El tema de este artículo es el comando git rebase
.
El comando git rebase
, junto con el comando git merge
, es la forma principal de fusionar dos o más ramas.
Vamos a cubrir los conceptos básicos de su uso, y algunas opciones de uso común.
1. Getting git rebase right
Como mencioné en el post anterior sobre git merge
, fusionar dos o más ramas usando el comando git rebase
te da un historial de commits directo.
A continuación se muestra un diagrama de cómo funciona rebase.
Por ejemplo, digamos que quieres hacer un rebase desde la rama feature-a
a la rama main
.
Git fusionará todos los commits de la rama feature-a
que provengan del ancestro común de las dos ramas en el último commit de la rama main
.
Al mismo tiempo, borrará todos los commits de la antigua rama feature-a
que eran dos ramas.
El resultado es una nueva rama feature-a
, que comienza en la última rama de la rama main
.
Esto cambia el historial de confirmaciones para crear un único historial en lugar de dos.
El comando que usamos para hacer esto es
A diferencia del comando git merge
, vamos a la rama source
y ejecutamos el comando contra la rama target
.
En el ejemplo anterior se vería así
$ git switch feature-a
$ git rebase main
Esto es lo que parece
El rebase ha fusionado las ramas develop
y main
, que tienen un ancestro común, el commit 6519
.
Como resultado, se ha creado una nueva rama develop
, que parte de main
, y la antigua rama develop
ha desaparecido.
Si se produce un conflicto durante el proceso de rebase, se muestra el siguiente mensaje
$ git rebase main
Resultado:
Auto-merging 1.md
CONFLICT (content): Merge conflict in 1.md
error: could not apply 7fc042b... 1.md edited in develop
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm ", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 7fc042b... 1.md edited in develop
Si quieres terminar el rebase aquí, resuelve los conflictos y prepara los archivos con el comando git add. Luego usa las opciones para continuar el proceso de rebase.
Las opciones para continuar el proceso de rebase son
$ git rebase --continue
Si desea ver los conflictos y revertir el rebase, escriba el siguiente comando para volver al estado anterior al rebase.
$ git rebase --abort
Veremos cada una de estas opciones con más detalle en secciones posteriores.
2. Abortar un rebase con --abort cuando ocurre un conflicto
Cuando Git está en medio de un rebase, hará una pausa si ve un conflicto.
Entonces nos dará la opción de resolver el conflicto y continuar el rebase, o abortarlo.
En este punto, si queremos abortar, tenemos la opción --abort
.
Si utilizas esta opción, el árbol de tareas volverá al estado en el que se encontraba antes de ejecutar el rebase. Esto puede ser útil si te encuentras con conflictos o problemas que hacen que no sea razonable continuar con el rebase.
Este comando se utiliza de la siguiente manera
$ git rebase --abort
Veamos los resultados reales de la ejecución para ver en qué situaciones se puede utilizar.
Mirando el mensaje de registro, podemos ver que el archivo 1.md
ha sido modificado por dos ramas.
En esta situación, el comando rebase fue ejecutado y se detectó un conflicto, causando que el rebase se detuviera por un tiempo.
Cuando abortamos el rebase con la opción --abort
, volvió al status quo.
3. Completando el rebase con la opción --continue cuando ocurre un conflicto
A continuación, veremos cómo utilizar la opción --continue
para resolver un conflicto y completar el proceso de rebase.
El proceso de resolución de conflictos es el mismo que el proceso git merge
.
Tendrás que abrir los archivos en conflicto en un editor y hacer tus selecciones.
Consulta el post git merge para más información.
Una vez que hayas arreglado los archivos, escenifícalos usando el comando git add. Entonces, en lugar de hacer un nuevo commit como en una fusión, continuamos este proceso de rebase usando la opción del comando rebase.
Úsalo así
$ git rebase --continue
Veamos los resultados de ejecutarlo en un caso de fallo real.
Mirando el mensaje de registro, vemos que el archivo 1.md
ha sido modificado por ambas ramas.
Cuando ejecutamos rebase, se confirma el conflicto y Git pausa el proceso de rebase.
He limpiado las líneas conflictivas con el editor, las he preparado y he usado la opción --continue
.
Como resultado, podemos ver que el rebase se completó con éxito.
4. Deshacer un rebase con git reset
Si quieres deshacer un rebase que ya se ha hecho, necesitas usar los comandos git reflog
y git reset
.
Como vimos en git commit post, las confirmaciones normales también pueden deshacerse o borrarse usando el ID de confirmación que muestra el comando git log
.
Sin embargo, si has ejecutado un git rebase
, ya has realizado cambios en una confirmación existente, por lo que no puedes revertir la información en el historial de confirmaciones actual.
El comando git reflog
muestra un registro de lo que has hecho a todos los valores almacenados como ref
, incluyendo ramas, etiquetas, etc.
Puedes verlo como un git log
más detallado para depuración.
Gracias a esto, puedes volver a un commit anterior, incluso si has ejecutado un comando git rebase
.
Aquí está la parte del registro generado por el comando git reflog
relacionado con el rebase que ejecutamos en Sección 3.
$ git reflog
Resultado:
69fd9e0 (HEAD -> develop) HEAD@{0}: rebase (finish): returning to refs/heads/develop
69fd9e0 (HEAD -> develop) HEAD@{1}: rebase (continue): 1.md edited in develop
5e110f7 (main) HEAD@{2}: rebase (start): checkout main
7fc042b HEAD@{3}: rebase (abort): returning to refs/heads/develop
A partir de los registros, podemos ver que el inicio del rebase que acabamos de ejecutar fue en HEAD@{2}
, y que tenemos que volver a HEAD@{3}
para volver antes de eso.
Ahora que sabes dónde volver, ejecuta el comando git reset
.
Usa la opción --mixed
para mantener los cambios que desaparecen en el árbol de trabajo, o la opción --hard
para volver atrás con todo borrado.
Aquí está el resultado de usar la opción --mixed
También puedes ver que los cambios de los commits borrados permanecen en el árbol de trabajo después del rebase.
5. Modificar el historial de confirmaciones a voluntad con la opción --interactive (feat. squash)
La opción --interactive
o -i
del comando git rebase
es una opción para ejecutar una sesión interactiva de rebase.
En esta sesión podemos modificar confirmaciones en la rama actual, aplastarlas, reordenarlas, etc.
Como resultado, cambiamos el historial de commits de la rama actual.
Es importante tener en cuenta que, a diferencia del comando git rebase
que vimos antes, sólo estamos manipulando los commits de una rama.
Ahora veamos los resultados en acción.
Para ejecutar una sesión, necesitarás introducir el ID del último commit que quieres manipular, así
$ git rebase -i [commit-hash]
El historial de confirmaciones actual tiene este aspecto
Aquí, el comando anterior abrirá una ventana como la siguiente.
Aquí, todos los comentarios que empiezan por #
son instrucciones.
La parte superior sin comentar es la lista de confirmaciones que son objeto de esta sesión rebase, ordenadas por antigüedad.
pick 7fc042b 1.md edited in develop
pick 6d80db8 1.md edited in develop 2
En nuestro ejemplo es esta parte. Puedes reemplazar la parte pick
con cualquier otro comando, guardarlo, y hacer lo que quieras con él.
5.1. Comandos clave y cómo usarlos
pick
: Guarda el estado actualreword
: Cambia sólo el mensaje de confirmaciónedit
: Cambiar detalles como autor, fecha, etc.squash
: Crea un nuevo mensaje de confirmación, fusionándolo con la confirmación anteriorfixup
: Utilizar el último mensaje de confirmación, fusionándolo con la confirmación anterior.drop
: Eliminar una confirmación
Por ejemplo, para cambiar el mensaje de la confirmación 7fd0
y fusionar la confirmación 6d80
con la anterior, realice los siguientes cambios, guarde y cierre el editor.
reword 7fc042b 1.md edited in develop
fixup 6d80db8 1.md edited in develop 2
Cuando realices una acción que requiera nueva información, como reword
, edit
, o squash
, Git abrirá tantos nuevos editores como sea necesario para pedir la información necesaria.
La pantalla de arriba muestra la ventana del editor pidiendo un nuevo mensaje de confirmación, tras el comando reword.
El comentario de abajo muestra que actualmente estamos trabajando en reword (Last command done
),
y que a continuación ejecutaremos la operación fixup (Next command to do
).
Si nos fijamos en los resultados, podemos ver que los comandos que escribimos anteriormente han completado la tarea de modificar el mensaje de confirmación y fusionar la confirmación anterior.
Como hemos visto en el comando anterior git commit --amend, incluso para modificaciones simples del mensaje, Git utiliza el método de crear un nuevo commit y reemplazarlo. Por lo tanto, debes usar todos los comandos en rebase con cuidado cuando colabores.
6. Reflexiones finales
El comando git rebase
tiene la capacidad de cambiar el historial de confirmaciones, una de las reglas no escritas de Git.
Tan poderoso como es este comando, también es lo suficientemente poderoso como para causar un caos inesperado en un proceso colaborativo.
Por esta razón, git rebase
debería usarse siempre públicamente, de acuerdo con las convenciones de tu equipo.
