git merge
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)Opciones
Elegir la opción adecuada
Estrategias de merge
Cómo controlar el tipo de merge que hace Git
| Comando | Crea commit de merge | Conserva el historial | Ideal para |
|---|---|---|---|
git merge (default) | Si se separaron | Sí | Integración normal de una funcionalidad |
git merge --no-ff | Siempre | Sí | Documentar merges de funcionalidades |
git merge --ff-only | Nunca | Solo lineal | Imponer un historial limpio |
git merge --squash | No (commit normal) | No (aplanado) | Rama main limpia |
Gestionar conflictos
Qué hacer cuando un merge tiene conflictos
| Comando | Acción | Conserva el trabajo | Cuándo usarla |
|---|---|---|---|
(resolve manually) | Editar archivos, git add | Sí | Necesitas partes de ambos lados |
--continue | Completar el merge | Sí | Tras resolver los conflictos |
--abort | Cancelar el merge | Estado previo al merge | No estás listo para resolver ahora |
checkout --ours/--theirs | Elegir un lado | Una sola versión | Un lado es claramente el correcto |
merge frente a rebase
Dos formas de integrar cambios, con ventajas e inconvenientes distintos
| Comando | Historial | Resolución de conflictos | Ideal para |
|---|---|---|---|
git merge | Conserva todos los commits | Una vez | Ramas compartidas, PR |
git rebase | Reescribe en lineal | Por commit | Limpieza local, ramas privadas |
git merge --squash | Un solo commit | Una vez | Funcionalidad con historial desordenado |
Controlar el commit
Opciones para personalizar el commit de merge
| Comando | Hace commit automáticamente | Caso de uso |
|---|---|---|
git merge feature | Sí (si no hay conflictos) | Merge normal |
git merge --no-commit | No (preparado) | Revisar antes del commit |
git merge -m "msg" | Sí (se ignora en fast-forward) | Commits de merge descriptivos |
git merge --squash | No (hay que hacer commit) | Combinar todos los commits en uno |
Ejemplos de flujos de trabajo
git checkout mainCambiarse a la rama main
git pull origin mainTraer los últimos cambios del remoto
git merge --no-ff feature-branchIntegrar la funcionalidad con un commit de merge para el historial
git push origin mainSubir los cambios integrados al remoto
git branch -d feature-branchBorrar la rama de funcionalidad ya integrada
git merge featureIntentar el merge (aparecen conflictos)
git statusVer qué archivos tienen conflictos
(edit conflicted files)Buscar las marcas <<<<<<< y resolver a mano
git add <resolved-files>Preparar los archivos resueltos
git merge --continueCompletar el merge con un commit
git checkout mainCambiarse a la rama main
git merge --squash feature-branchCombinar todos los commits en cambios preparados
git commit -m "Add feature X"Crear un único commit limpio con todos los cambios
git branch -D feature-branchForzar el borrado de la rama de funcionalidad
git merge featureEmpezar el merge (surgen problemas)
git statusVer el estado con conflictos
git merge --abortCancelar y volver al estado previo al merge
git statusComprobar 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
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.
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.
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.
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.
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.
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.