Fusionar o integrar — es la acción de combinar dos ramas en Git, uniendo cambios de una rama a otra. En el desarrollo moderno, el merge es la forma estándar de integrar una rama de funcionalidad en la rama principal del proyecto. Según GitHub Octoverse 2024, diariamente se realizan más de 15 millones de merges. Merge es un mecanismo clave del trabajo colaborativo que permite combinar el esfuerzo de varios desarrolladores en un solo producto.
Puntos Clave
El merge en Git es la operación de combinar dos o más historias de desarrollo en una. Cuando un desarrollador fusiona una rama, Git encuentra automáticamente el ancestro común (base commit) y crea un nuevo commit de fusión que incluye los cambios de ambas ramas. Three-way merge es el algoritmo estándar que compara tres estados: el ancestro común, la primera rama y la segunda rama.
El proceso de merge comienza con el comando git merge. Git determina el punto de divergencia de las ramas y aplica secuencialmente los cambios de la rama origen sobre la rama destino. Si los cambios no entran en conflicto, Git realiza un fast-forward o crea un merge commit según la configuración. Fast-forward es un escenario en el que la rama destino simplemente se mueve a los commits de la rama origen.
# Cambiar a la rama de destino y fusionar
git checkout main
git merge feature/payment-module
# Fusionar con no-fast-forward explícito
git merge --no-ff feature/payment-module
# Cancelar fusión si los conflictos son demasiado complejos
git merge --abort
El flag --no-ff (no fast-forward) fuerza la creación de un merge commit incluso cuando es posible un fast-forward. Esto preserva la información de que los cambios se realizaron en una rama separada. Muchos equipos prefieren este enfoque para mantener el historial de ramificación de forma explícita.
Git tiene tres estrategias principales de fusión de ramas, cada una adecuada para un escenario específico. La elección de la estrategia depende de la cultura del equipo y los requisitos de limpieza del historial del proyecto.
| Estrategia | Resultado | Cuándo usarla |
|---|---|---|
| Standard merge | merge commit + historial completo | equipos que valoran el historial completo |
| Squash merge | un commit, historial comprimido | ramas de funcionalidad con muchos commits pequeños |
| Rebase merge | historial lineal, sin merge commit | ramas de funcionalidad personales, antes de crear un PR |
Standard merge crea un merge commit con dos padres. El historial completo se conserva, pero el grafo de ramificación se vuelve más complejo. Squash merge combina todos los commits de una rama de funcionalidad en uno y lo aplica sobre la rama destino — el historial se vuelve lineal y limpio, pero se pierde información sobre las etapas intermedias.
Rebase, aunque no es una fusión completa, logra el mismo resultado — los cambios de una rama se trasladan sobre otra. La diferencia es que el historial se reescribe: los commits de la rama de funcionalidad se recrean sobre el último commit de la rama destino. Esto da un historial perfectamente lineal, pero requiere force push al enviar.
Un conflicto de merge surge cuando se modifican las mismas líneas de un archivo en dos ramas. Git no puede determinar automáticamente qué versión conservar y requiere la intervención del desarrollador. Los conflictos se muestran en los archivos mediante marcadores especiales: <<<<<<<, =======, >>>>>>>.
El proceso de resolución de conflictos incluye varios pasos. Primero, el desarrollador abre el archivo en conflicto y selecciona manualmente los cambios necesarios. Es importante no solo elegir una versión, sino entender la lógica de ambos cambios y tomar una decisión correcta. Después de editar el archivo, los marcadores de conflicto se eliminan y los cambios se añaden al staging area mediante git add.
# Ver lista de archivos en conflicto
git status
# Iniciar mergetool (p. ej., VS Code, IntelliJ)
git mergetool
# Después de resolver todos los conflictos
git add .
git merge --continue
# O cancelar la fusión por completo
git merge --abort
El uso de herramientas visuales de merge acelera significativamente la resolución de conflictos. VS Code, IntelliJ IDEA y GitKraken proporcionan interfaces con tres paneles: rama actual, rama entrante y resultado. La herramienta git mergetool abre automáticamente el editor configurado para cada archivo en conflicto.
La mejor forma de evitar conflictos complejos es la sincronización regular de la rama de funcionalidad con la principal. Si un desarrollador fusiona main en su rama una vez al día, los conflictos serán pequeños y fáciles de resolver. Acumular cambios durante una semana garantiza conflictos complejos con alto riesgo de errores.
Rebase y merge son dos formas de combinar cambios, y la elección entre ellos a menudo genera debate en los equipos. Rebase traslada commits de una rama sobre otra, reescribiendo el historial. Merge crea un nuevo commit de fusión, conservando el historial de ramificación. Cada enfoque tiene sus ventajas y limitaciones.
Rebase es apropiado cuando un desarrollador trabaja en su rama de funcionalidad local y quiere un historial lineal limpio antes de crear un Pull Request. Después del rebase, todos los commits se ordenan secuencialmente sin commits de merge innecesarios. Sin embargo, rebase requiere force push y no es aplicable a ramas en las que trabajan varias personas simultáneamente.
La regla de oro de Git: no uses rebase en commits que ya se hayan enviado al repositorio compartido. Esto garantiza que el historial en la rama compartida permanezca sin cambios y que otros desarrolladores no se encuentren con commits duplicados o perdidos. Para integrar una rama de funcionalidad en la principal, usa merge mediante Pull Request.
Un proceso de merge adecuado es la base de un desarrollo estable. En el trabajo en equipo moderno, la fusión no se realiza a través de la consola, sino mediante Pull Request en GitHub o Merge Request en GitLab. Un PR pasa por revisión de código, verificaciones automáticas de CI y solo entonces se fusiona en la rama principal.
La primera práctica — fusionar solo después de que todas las verificaciones hayan pasado. El pipeline de CI debe compilar el proyecto, ejecutar pruebas y verificar la calidad del código. Si al menos una verificación falla, el merge se bloquea. Las plataformas modernas (GitHub, GitLab) tienen protección integrada: branch protection rules bloquean automáticamente el merge si el CI falla.
La segunda práctica — nunca fusionar código roto. Antes del merge, el desarrollador debe asegurarse de que sus cambios no rompan la compilación ni regresen funcionalidad existente. Para esto existen pruebas automáticas y revisión de código.
La tercera práctica — limpiar las ramas de funcionalidad después del merge. Una rama que ya se ha fusionado debe eliminarse. Esto evita confusiones y desorden en el repositorio. GitHub ofrece automáticamente eliminar la rama después de fusionar un PR, y la configuración del repositorio se puede ajustar para la eliminación automática.
Preguntas Frecuentes
Un merge es la combinación de dos ramas de Git en una. Los cambios de una rama se transfieren a otra mediante una fusión a tres bandas (three-way merge). El resultado se registra en un nuevo commit de fusión que tiene dos commits padres. Merge commit conserva la información sobre qué ramas se fusionaron.
Merge crea un nuevo commit de fusión, conservando el historial de ramificación. Rebase reescribe el historial trasladando commits sobre otra rama sin crear un merge commit. Rebase proporciona un historial lineal pero requiere force push. Merge es más seguro para ramas compartidas, rebase es mejor para ramas personales.
Abra el archivo en conflicto, encuentre los marcadores <<<<<<<, ======= y >>>>>>>, seleccione los cambios necesarios y elimine los marcadores. Agregue el archivo mediante git add y complete el merge con git merge --continue. Use git mergetool para la resolución visual en VS Code o IntelliJ IDEA.
Pull Request (o Merge Request) es obligatorio al fusionar una rama de funcionalidad en la rama principal del proyecto. Un PR pasa por revisión de código de colegas y verificaciones automáticas de CI. Este es el estándar del desarrollo moderno. El push directo a la rama principal está prohibido en la mayoría de los proyectos.
Squash merge combina todos los commits de una rama de funcionalidad en uno antes de fusionar. Esto proporciona un historial limpio de la rama principal sin commits intermedios de borrador. Use squash merge cuando una rama de funcionalidad contenga muchos commits de utilidad (wip, fixes) y no sea necesario conservar todos los pasos intermedios en el historial.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también