git merge

Ramas y fusiones

Unir dos o más historiales de desarrollo


El comando 'git merge' incorpora a la rama actual los cambios de los commits indicados (desde que sus historiales se separaron de la rama actual). Git hace un merge «fast-forward» cuando puede (cuando la rama actual es un ancestro de la rama integrada) o crea un «commit de merge» cuando los historiales se han separado. Si hay conflictos entre las ramas, Git se detiene y te pide que los resuelvas antes de completar el merge.

Sinopsis

git merge [--no-ff | --ff-only] [--squash] [--no-commit] [-m <msg>] [--allow-unrelated-histories] [<commit>...]
git merge (--continue | --abort | --quit)
[ ] opcional| o<arg> valor a sustituir... repetible--flag opción

Opciones

Haz clic en una opción para desplegarla

Principiante (5)

Crear un commit de merge aunque el merge pudiera resolverse con fast-forward. Conserva el historial de la rama y deja claro dónde empezó y terminó el trabajo de la funcionalidad.

Cuando haga faltaSiempre registra un commit de merge: una convención de equipo

Ejemplo

git merge --no-ff feature

Negarse a hacer el merge salvo que el HEAD actual ya esté al día o el merge pueda resolverse como fast-forward. Evita commits de merge accidentales.

RecomendadoNunca crea commits de merge inesperados; falla si los historiales divergieron

Ejemplo

git merge --ff-only feature

Cancelar la resolución de conflictos en curso y devolver el repositorio al estado previo al merge. Úsalo para cancelar un merge con conflictos.

RecomendadoSale con seguridad de un merge con conflictos y vuelve al estado previo

Ejemplo

git merge --abort

Tras resolver los conflictos, terminar el merge. Equivale a ejecutar git commit después de resolverlos.

RecomendadoTermina el merge tras resolver y preparar los conflictos

Ejemplo

git merge --continue

Poner un mensaje personalizado al commit de merge. No fuerza un commit de merge: en un fast-forward el mensaje se ignora (combínalo con --no-ff para tener siempre uno).

Cuando haga faltaMensaje propio para el commit de merge; se ignora si el merge es fast-forward

Ejemplo

git merge -m "Integrate login feature" feature

Intermedio (2)

Combinar todos los commits de la rama integrada en un único conjunto de cambios preparados. No crea commit ni registra un merge (no hay MERGE_HEAD): haces el commit a mano, y el resultado es un commit normal con un solo padre.

Cuando haga faltaUn commit limpio, pero no un merge de verdad; luego la rama necesita -D

Ejemplo

git merge --squash feature

Hacer el merge pero detenerse antes de crear el commit. Te permite revisar y modificar el resultado antes de confirmarlo. Aun así se produce el fast-forward; añade --no-ff para garantizar la parada.

Cuando haga faltaRevisa el resultado antes del commit; combínalo con --no-ff

Ejemplo

git merge --no-commit feature

Avanzado (1)

Permitir el merge de historiales sin ningún ancestro común. Útil para unir dos repositorios o proyectos separados.

Cuando haga faltaSolo para unir proyectos separados a propósito

Ejemplo

git merge --allow-unrelated-histories other-project/main

Elegir la opción adecuada

Estrategias de merge

Cómo controlar el tipo de merge que hace Git

ComandoCrea commit de mergeConserva el historialIdeal para
git merge (default)Si se separaronSíIntegración normal de una funcionalidad
git merge --no-ffSiempreSíDocumentar merges de funcionalidades
git merge --ff-onlyNuncaSolo linealImponer un historial limpio
git merge --squashNo (commit normal)No (aplanado)Rama main limpia

Gestionar conflictos

Qué hacer cuando un merge tiene conflictos

ComandoAcciónConserva el trabajoCuándo usarla
(resolve manually)Editar archivos, git addSíNecesitas partes de ambos lados
--continueCompletar el mergeSíTras resolver los conflictos
--abortCancelar el mergeEstado previo al mergeNo estás listo para resolver ahora
checkout --ours/--theirsElegir un ladoUna sola versiónUn lado es claramente el correcto

merge frente a rebase

Dos formas de integrar cambios, con ventajas e inconvenientes distintos

ComandoHistorialResolución de conflictosIdeal para
git mergeConserva todos los commitsUna vezRamas compartidas, PR
git rebaseReescribe en linealPor commitLimpieza local, ramas privadas
git merge --squashUn solo commitUna vezFuncionalidad con historial desordenado

Controlar el commit

Opciones para personalizar el commit de merge

ComandoHace commit automáticamenteCaso de uso
git merge featureSí (si no hay conflictos)Merge normal
git merge --no-commitNo (preparado)Revisar antes del commit
git merge -m "msg"Sí (se ignora en fast-forward)Commits de merge descriptivos
git merge --squashNo (hay que hacer commit)Combinar todos los commits en uno

Ejemplos de flujos de trabajo

1
git checkout main

Cambiarse a la rama main

2
git pull origin main

Traer los últimos cambios del remoto

3
git merge --no-ff feature-branch

Integrar la funcionalidad con un commit de merge para el historial

4
git push origin main

Subir los cambios integrados al remoto

5
git branch -d feature-branch

Borrar la rama de funcionalidad ya integrada

1
git merge feature

Intentar el merge (aparecen conflictos)

2
git status

Ver qué archivos tienen conflictos

3
(edit conflicted files)

Buscar las marcas <<<<<<< y resolver a mano

4
git add <resolved-files>

Preparar los archivos resueltos

5
git merge --continue

Completar el merge con un commit

1
git checkout main

Cambiarse a la rama main

2
git merge --squash feature-branch

Combinar todos los commits en cambios preparados

3
git commit -m "Add feature X"

Crear un único commit limpio con todos los cambios

4
git branch -D feature-branch

Forzar el borrado de la rama de funcionalidad

1
git merge feature

Empezar el merge (surgen problemas)

2
git status

Ver el estado con conflictos

3
git merge --abort

Cancelar y volver al estado previo al merge

4
git status

Comprobar que has vuelto a un estado limpio

Solución de problemas

CONFLICT (content): Merge conflict in file.js

Causa: Las dos ramas modificaron las mismas líneas del archivo

Abre el archivo, busca las marcas <<<<<<<, resuélvelo y luego git add y git merge --continue

fatal: refusing to merge unrelated histories

Causa: Las ramas no tienen ningún ancestro común (repositorios separados)

Usa git merge --allow-unrelated-histories si de verdad quieres unir proyectos separados

Already up to date

Causa: La rama que integras ya está incluida en tu rama actual

No hay nada que hacer: tu rama ya contiene todos los commits de la otra

error: Your local changes to the following files would be overwritten by merge

Causa: Tienes cambios sin commit que chocan con el merge

Haz commit de tus cambios, guárdalos con stash (git stash) o descártalos antes del merge

Se hizo el merge pero quería revisarlo antes

Causa: Git hizo el commit del merge automáticamente

La próxima vez usa --no-ff --no-commit. Para rehacerlo: git reset --merge ORIG_HEAD y vuelve a hacer el merge con --no-commit

Consejos y trampas

Buenas prácticas

  • ✓Haz siempre pull de los últimos cambios antes del merge para reducir conflictos
  • ✓Usa --no-ff en las ramas de funcionalidad para conservar el contexto del merge en el historial
  • ✓Escribe mensajes de merge descriptivos que expliquen qué se integró
  • ✓Borra las ramas de funcionalidad tras el merge para mantener limpio el repositorio
  • ✓Prueba tu código después del merge y antes del push para asegurarte de que nada se ha roto
  • ✓Usa git merge --abort si no estás listo para resolver conflictos: no dejes un merge a medias
  • ✓En ramas de larga duración, integra main en tu rama de funcionalidad de vez en cuando para reducir los conflictos del merge final

Errores comunes

  • ✗Hacer merge sin traer antes los últimos cambios del remoto. Haz siempre 'git pull' antes del merge para evitar conflictos.
  • ✗Preparar archivos que aún contienen marcas de conflicto. Git bloquea los commits mientras haya rutas sin resolver, pero en cuanto haces 'git add' de un archivo, incluye las marcas <<<<<<< tal cual.
  • ✗Usar merges fast-forward en ramas de funcionalidad hace perder el historial de la rama. Usa '--no-ff' para conservar el contexto.
  • ✗Ejecutar 'git merge --abort' después de resolver conflictos a mano hace perder todo ese trabajo de resolución.
  • ✗Hacer merge en la rama equivocada. Comprueba siempre con 'git branch' que estás en la rama de destino correcta antes del merge.

Preguntas frecuentes

A:

Merge conserva el historial y crea un commit de merge. Rebase reescribe el historial para que sea lineal. Usa merge en ramas compartidas y rebase para la limpieza local.

A:

Usa --no-ff al integrar ramas de funcionalidad en main. Crea un commit de merge que deja constancia de cuándo se integró la funcionalidad, aunque fuera posible un fast-forward.

A:

Si no se ha subido: git reset --hard ORIG_HEAD (también sirve para fast-forwards; descarta los cambios sin commit). Si ya se subió: git revert -m 1 <merge-commit> para crear un commit nuevo que deshaga el merge.

A:

El fast-forward ocurre cuando tu rama no tiene commits nuevos desde el punto de separación. Git simplemente avanza el puntero en lugar de crear un commit de merge.

A:

Abre los archivos en conflicto, busca las marcas <<<<<<<, edítalos para quedarte con el código que quieras, quita las marcas y luego haz git add de los archivos y git merge --continue.

A:

El merge normal conserva todo el historial de commits. El squash merge lo combina todo en un solo commit. Usa squash cuando la rama de funcionalidad tenga commits WIP desordenados que no quieras en main.