Cómo resolver conflictos de fusión en Git sin perder cambios
Al fusionar dos ramas, Git suele combinar los cambios automáticamente. Sin embargo, si ambas modifican una misma zona de un archivo de forma incompatible, puede detener la operación y pedirte que decidas qué conservar. Encontrar un conflicto no significa que el trabajo haya desaparecido: significa que Git necesita ayuda para construir el resultado.
Resolver conflictos de fusión en Git sin perder cambios requiere algo más que borrar unas marcas. Hay que entender qué hizo cada rama, elegir una solución que mantenga la intención del equipo y comprobar que el proyecto sigue funcionando. En esta guía verás cómo preparar el repositorio, resolver un ejemplo paso a paso y actuar ante situaciones especiales.
Por qué aparecen los conflictos de fusión
Un conflicto surge cuando Git no puede determinar por sí solo cómo combinar ciertos cambios. Suele ocurrir cuando dos ramas modifican las mismas líneas, pero también puede aparecer si una rama elimina un archivo que la otra ha editado, o cuando hay cambios incompatibles en nombres o rutas.
Imagina que trabajas en la rama carrito y quieres incorporar los cambios de feature/envio. Ejecutas:
git switch carrito
git merge feature/envio
Si Git encuentra un conflicto, detiene la fusión y deja el repositorio en un estado intermedio. Los commits de las ramas siguen existiendo, pero debes resolver los archivos afectados antes de completar el proceso. La decisión correcta no siempre consiste en elegir una versión: a veces hay que combinar partes de ambas o escribir una solución nueva.
Antes de empezar: protege el trabajo pendiente
Antes de iniciar una fusión, comprueba en qué rama estás y si tienes cambios sin guardar:
git status
Lo más sencillo es comenzar con el árbol de trabajo limpio. Si tienes cambios que todavía no quieres incorporar a un commit, puedes guardarlos temporalmente:
git stash push -u -m "Trabajo antes de la fusión"
La opción -u incluye archivos no rastreados, pero no los ignorados. Si estos últimos contienen información importante, guárdalos por separado. Otra opción es crear un commit de trabajo en una rama apropiada. En cualquier caso, comprueba que tus cambios quedaron guardados antes de continuar.
Después de completar la fusión, puedes recuperar el trabajo temporal con git stash apply. Revisa el resultado: aplicar un stash también puede generar conflictos. A diferencia de pop, apply conserva la entrada en el stash hasta que decidas eliminarla.
Estos preparativos reducen el riesgo, pero no sustituyen una copia de seguridad cuando hay archivos irremplazables. Si ya estás en medio de una fusión, no ejecutes comandos de limpieza o restauración a ciegas: primero examina el estado y guarda una copia externa de cualquier contenido que necesites preservar.
Identifica los archivos en conflicto
Cuando una fusión se detiene, el primer paso es consultar:
git status
Git mostrará los archivos con cambios sin fusionar y orientaciones para continuar. También puedes obtener una lista breve con:
git diff --name-only --diff-filter=U
Abre cada archivo señalado y busca las marcas de conflicto. En un conflicto de contenido típico verás una estructura similar a esta:
<<<<<<< HEAD
contenido de la rama actual
=======
contenido de la rama que se intenta fusionar
>>>>>>> feature/envio
En una fusión normal, HEAD representa la rama en la que estabas al ejecutar git merge; la sección inferior corresponde a la rama que estás incorporando. Las líneas con <<<<<<<, ======= y >>>>>>> son delimitadores, no código que deba quedar en el resultado final.
Algunas configuraciones también muestran el contenido de un ancestro común entre ambas versiones. Esa referencia adicional puede ayudarte a entender qué cambió cada rama, pero no altera la tarea: decidir cuál debe ser el contenido final.
Resuelve un conflicto paso a paso
Supongamos que ambas ramas modificaron una función de JavaScript que calcula el total. En carrito se añadió un descuento y en feature/envio se añadió el coste de envío:
<<<<<<< HEAD
function calcularTotal(subtotal, descuento, envio) {
return subtotal - descuento;
}
=======
function calcularTotal(subtotal, descuento, envio) {
return subtotal + envio;
}
>>>>>>> feature/envio
Elegir cualquiera de las dos versiones completas descartaría una parte de la funcionalidad. Si los requisitos indican que ambos importes deben aplicarse, el archivo podría quedar así:
function calcularTotal(subtotal, descuento, envio) {
return subtotal - descuento + envio;
}
Este resultado es solo un ejemplo: en un proyecto real habría que confirmar las reglas de negocio, los tipos de datos y los casos límite. Para resolverlo con seguridad:
- Lee las dos versiones y revisa el contexto que las rodea.
- Consulta los commits o pregunta a sus autores si no está claro el propósito de un cambio.
- Edita el archivo para conservar o combinar lo que corresponda.
- Elimina todos los delimitadores de conflicto de ese bloque.
- Guarda el archivo y repite el proceso con los demás conflictos.
Puedes usar un editor con interfaz de resolución, pero revisa igualmente el contenido final. Los botones para aceptar un lado o ambos son cómodos; no garantizan que el resultado tenga sentido ni que el orden de los cambios sea correcto.
Marca la resolución y revisa el resultado
Cuando termines un archivo, añádelo al área de preparación para indicar a Git que el conflicto está resuelto:
git add ruta/al/archivo.js
git status
git add no comprueba que hayas tomado la decisión correcta: solo registra el contenido actual como resolución. Antes de finalizar, revisa lo preparado y busca errores de formato:
git diff --cached
git diff --cached --check
La primera orden muestra los cambios preparados; la segunda detecta problemas habituales de espacios y determinadas marcas de conflicto. Ninguna sustituye una revisión funcional. Además, comprueba que git status ya no indique archivos sin fusionar.
Completa la fusión
Ejecuta las pruebas relevantes, el formateador o las comprobaciones del proyecto antes de cerrar la operación. Para el ejemplo anterior, conviene probar casos con y sin descuento o envío, además de cualquier límite definido por la aplicación.
Si todo está listo, completa la fusión:
git merge --continue
Git puede abrir un editor para confirmar el mensaje del commit de fusión. Tras finalizar, usa git status para verificar el estado del repositorio y revisa el commit resultante. Si guardaste trabajo con stash, recupéralo y comprueba de nuevo que no haya conflictos pendientes.
Casos especiales: archivos eliminados y binarios
No todos los conflictos muestran bloques de texto. Si una rama eliminó un archivo y la otra lo modificó, Git puede pedirte que decidas entre conservarlo o eliminarlo. Revisa por qué se hizo cada cambio y confirma qué necesita el proyecto.
- Para conservar la versión presente y marcarla como resuelta, usa
git add ruta/al/archivodespués de revisarla. - Para aceptar la eliminación, usa
git rm ruta/al/archivo.
Los archivos binarios, como algunas imágenes o documentos, normalmente no pueden combinarse editando delimitadores. Puede ser necesario elegir una versión, recuperar contenido con la herramienta que lo creó o generar un archivo nuevo. Antes de sobrescribir nada, guarda copias de las versiones que necesites y coordina la decisión con sus autores.
También es posible inspeccionar las etapas que Git guarda para un archivo sin fusionar mediante comandos como git show :2:ruta/al/archivo y git show :3:ruta/al/archivo. En una fusión normal corresponden, respectivamente, al lado actual y al lado incorporado. Úsalos con cuidado, especialmente si rediriges la salida: podrías sobrescribir un archivo existente.
Qué hacer si necesitas cancelar
Si la fusión se ha complicado y prefieres volver al estado anterior, puedes ejecutar:
git merge --abort
Este comando intenta reconstruir el estado previo al inicio de la fusión. Sin embargo, si ya había cambios sin confirmar al comenzarla, Git podría no poder restaurarlos perfectamente. Además, abortar puede descartar el trabajo de resolución realizado durante la operación. Por eso, guarda fuera del repositorio cualquier edición que quieras conservar antes de abortar y verifica el resultado con git status.
No confundas abortar con resolver. Tras cancelar, tendrás que preparar de nuevo la integración y repetir la fusión cuando estés listo. Evita recurrir a comandos destructivos como git reset --hard sin entender exactamente qué cambios pueden eliminar.
Si el conflicto aparece durante un rebase
Un conflicto de rebase se parece visualmente a uno de fusión, pero el proceso es distinto: Git está reaplicando commits sobre otra base. Tras editar los archivos, usa git add y continúa con:
git rebase --continue
Para cancelar esa operación se utiliza git rebase --abort, no git merge --abort. Ten especial cuidado con las opciones llamadas ours y theirs: durante un rebase su interpretación puede resultar inversa a la que esperas de una fusión normal. Inspecciona las versiones y el estado antes de elegir un lado completo.
Cómo reducir los conflictos futuros
No se pueden evitar todos, pero sí hacerlos más manejables:
- Integra cambios con frecuencia y mantén las ramas de trabajo acotadas cuando sea práctico.
- Coordina las modificaciones grandes en archivos compartidos.
- Separa cambios de formato masivos de los cambios funcionales para facilitar la revisión.
- Usa pruebas y revisiones de código para detectar combinaciones incorrectas que Git no puede reconocer.
Una fusión automática tampoco garantiza que el programa funcione: dos cambios en líneas distintas pueden ser incompatibles en comportamiento.
Conclusión
Resolver un conflicto consiste en entender las dos intenciones, construir el resultado adecuado y verificarlo antes de completar la operación. Empieza con git status, protege los cambios pendientes, revisa cada archivo y ejecuta las pruebas. La próxima vez que Git detenga una fusión, tómalo como una oportunidad para revisar la integración, no como una señal de que debas elegir una versión deprisa.
