Git Merge vs. Git Rebase

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 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:

  1. Historial explícito: El "merge commit" te muestra claramente cuándo se hicieron fusiones entre ramas.
  2. 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:

  1. Historial limpio: Ofrece un historial de commits lineal, lo que puede facilitar la lectura y el seguimiento de la historia del proyecto.
  2. 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 con merge, enfrentas conflictos una sola vez (en el merge commit).

Flujo de trabajo recomendado

  1. Creación y desarrollo en una rama:

    • Crea una rama específica para tu trabajo a partir de la rama principal (por ejemplo, master o main).
    • Realiza commits a medida que avanzas con tu trabajo, conservando así un historial detallado de tus progresos.
  2. 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.
  3. 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.

Consejos adicionales:

  • Si te encuentras con conflictos durante un rebase, resuélvelos y luego usa git rebase --continue para proseguir con el proceso.
  • Si cometes un error durante el rebase, puedes abortar el proceso y regresar a tu estado anterior con git 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

Jack Fiallos

Jack Fiallos

Te gustó este artículo?