Git Merge vs. Git Rebase
Recientemente he leído un tweet en el que explicaban el uso tanto git merge
como git rebase
, un hilo conciso y muy poco explicado, a partir de eso es que decidí escribir este artículo donde abordo lo mismo, pero esta vez he escrito la versión extendida y de la forma en que yo la entendí, considerando que ambos métodos pero tienen enfoques y resultados diferentes.
Git Rebase vs Git Merge!
— Rakesh Jain (@devops_tech) September 30, 2023
A debate which can be puzzling for many. Let's explore it with practical examples.
A Thread 👇 pic.twitter.com/zKSAxhCag6
Git Merge
El comando git merge
une dos ramas en una nueva "instantánea" o "commit".
Por ejemplo:
Supongamos que tienes dos ramas: master
y feature
.
graph LR
A[master] --> B((commit1))
B --> C((commit2))
D[feature] --> E((commitA))
E --> F((commitB))
Al hacer git merge
desde master
con feature
:
$ git checkout master
[/master]$ git merge feature
El historial queda así:
graph LR
A[master] --> B((commit1))
B --> C((commit2))
D[feature] --> E((commitA))
E --> F((commitB))
C & F --> G((merge commit))
G --> H[master]
Un nuevo commit merge commit, une los cambios.
Y al observar el historial con herramientas como git log --graph
, podrás ver líneas que indican la procedencia de los commits, mostrando cómo las ramas se fusionaron a través del "merge commit".
Para ejemplificarlo, si haces un git log
en master
después de un git merge
, verías algo similar a:
* Merge commit (G)
* commit2 (C)
* commit1 (B)
Sin embargo, si haces un git log --graph
, la visualización incluiría la rama feature
:
* Merge commit (G)
|\
| * commitB (F)
| * commitA (E)
* commit2 (C)
* commit1 (B)
Ventajas de git merge
:
- Historial explícito: El "merge commit" te muestra claramente cuándo se hicieron fusiones entre ramas.
- Seguro: Si cometes un error durante el proceso de fusión, es más fácil revertir un merge que un rebase.
El "merge commit" creado por
git merge
es un commit especial que tiene dos (o a veces más) commits padres. Representa la unificación de dos líneas de desarrollo. Todos los cambios de la rama que se fusiona están incluidos en ese commit unificado, por eso no es necesario duplicar los commits individuales en la rama principal.
Git Rebase
El comando git rebase
toma todos los cambios de una rama y los reaplica sobre otra.
Por ejemplo:
Usando las mismas ramas master
y feature
:
graph LR
A[master] --> B((commit1))
B --> C((commit2))
D[feature] --> E((commitA))
E --> F((commitB))
Al hacer git rebase
de feature
sobre master
:
$ git checkout feature
$ git rebase master
El historial queda así:
graph LR
A[master] --> B((commit1))
B --> C((commit2))
C --> E'((commitA))
E' --> F'((commitB))
F' --> D[feature]
Los commits de feature
se han "trasladado" para que parezca que se desarrollaron después de los últimos commits en master
.
Ventajas de git rebase
:
- Historial limpio: Ofrece un historial de commits lineal, lo que puede facilitar la lectura y el seguimiento de la historia del proyecto.
- Evita "merge commits" innecesarios: Algunos equipos prefieren evitar los "merge commits" a menos que estén fusionando una rama completa (como una característica o corrección de errores).
Diferencias Principales
-
Historial: Con
merge
, se mantiene un historial de commits explícito y muestra cuándo se realizó una fusión mediante un "merge commit".rebase
proporciona un historial lineal, como si todos los cambios hubieran ocurrido en una única secuencia. -
Conflictos: Con
rebase
, es posible que enfrentes conflictos por cada commit que estás reaplicando, mientras que conmerge
, enfrentas conflictos una sola vez (en el merge commit).
Flujo de trabajo recomendado
-
Creación y desarrollo en una rama:
- Crea una rama específica para tu trabajo a partir de la rama principal (por ejemplo,
master
omain
). - Realiza commits a medida que avanzas con tu trabajo, conservando así un historial detallado de tus progresos.
- Crea una rama específica para tu trabajo a partir de la rama principal (por ejemplo,
-
Preparación para la integración:
- Antes de integrar tu trabajo en la rama principal, asegúrate de que tu rama esté actualizada con los últimos cambios de la rama principal. Esto ayudará a evitar conflictos.
- Usa
git rebase
para trasladar tu rama sobre la última versión de la rama principal, lo que te permite "reaplicar" tus cambios sobre ella. Esto es ideal para limpiar y linearizar tu historial local antes de la integración.
-
Integración en la rama principal:
- Una vez que hayas rebasado tu rama, puedes proceder a fusionarla (con
git merge
) en la rama principal y luego enviar (push) tus cambios.
- Una vez que hayas rebasado tu rama, puedes proceder a fusionarla (con
Consejos adicionales:
- Si te encuentras con conflictos durante un
rebase
, resuélvelos y luego usagit rebase --continue
para proseguir con el proceso. - Si cometes un error durante el
rebase
, puedes abortar el proceso y regresar a tu estado anterior congit rebase --abort
. - El "merge commit" creado al fusionar tu rama en la principal actúa como un punto claro en el historial, lo que facilita la identificación de la introducción de tu trabajo. Además, al conservar el historial completo, facilita la tarea de revertir cambios si es necesario en el futuro.
Conclusión
Ambos métodos, git merge
y git rebase
, tienen sus pros y contras, y la elección entre ellos dependerá de tu flujo de trabajo y preferencias personales. Si buscas un historial limpio y lineal, rebase
podría ser tu opción ideal. Por otro lado, si prefieres tener un registro explícito de las fusiones y un historial detallado de cómo se desarrollaron las cosas, entonces merge
es el camino a seguir.
No se puede decir que uno sea estrictamente mejor que el otro. Personalmente, encuentro que git merge
es valioso cuando quiero conservar un historial completo, donde cada fusión y cada decisión queda registrada.
Por otro lado, tiendo a usar git rebase
especialmente antes de presentar un "pull request" o "merge request". Es útil para asegurar un historial limpio y que la rama se integre sin problemas a la principal. Es especialmente útil cuando estoy en una rama local y deseo incorporar los cambios más recientes de la rama principal antes de hacer nuevos commits.
Happy coding! :D
Photo by Denys Nevozhai on Unsplash