Contexto técnico
Git es un sistema de control de versiones distribuido. Al ejecutar git merge main desde la rama desarrollo, Git intenta integrar la historia de main en desarrollo. Como ambas ramas han modificado la misma región del fichero index.php, Git no puede aplicar una fusión automática (no hay fast-forward posible y el three-way merge detecta cambios solapados) y detiene la operación dejando el repositorio en estado MERGING, a la espera de que el desarrollador resuelva el conflicto manualmente.
Cuestión 1 — Pasos para resolver el conflicto y completar la fusión
Paso 1. Lanzar el merge e identificar el estado.
git checkout desarrollo
git merge main
Salida típica:
Auto-merging index.php
CONFLICT (content): Merge conflict in index.php
Automatic merge failed; fix conflicts and then commit the result.
Paso 2. Diagnosticar qué ficheros están en conflicto.
git status
On branch desarrollo
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.php
El estado both modified indica que el fichero fue modificado en ambas ramas. Para ver solo los ficheros en conflicto de forma compacta:
git diff --name-only --diff-filter=U
Paso 3. Abrir index.php e interpretar los marcadores de conflicto.
Git inserta en el fichero los marcadores que delimitan ambas versiones:
<?php
echo "Bienvenido a la aplicación";
<<<<<<< HEAD
$titulo = "Versión de la rama desarrollo";
=======
$titulo = "Versión de la rama main";
>>>>>>> main
Interpretación de los marcadores:
<<<<<<< HEAD ... ======= → contenido de tu rama actual (desarrollo, apuntada por HEAD).
======= ... >>>>>>> main → contenido de la rama entrante (main).
Para ver también la versión del ancestro común es útil activar el estilo diff3, que ayuda a decidir mejor:
git config merge.conflictstyle diff3
Paso 4. Editar el fichero para dejar la versión definitiva.
Se decide qué código debe quedar: la versión de desarrollo, la de main, una combinación de ambas o una redacción nueva. Lo esencial es eliminar por completo los tres marcadores (<<<<<<<, =======, >>>>>>>). Resultado final, por ejemplo combinando ambas aportaciones:
<?php
echo "Bienvenido a la aplicación";
$titulo = "Versión consolidada (desarrollo + main)";
Alternativamente, si se quiere aceptar en bloque una de las dos versiones sin editar a mano:
# Quedarse con la versión de desarrollo (rama actual)
git checkout --ours index.php
# Quedarse con la versión de main (rama entrante)
git checkout --theirs index.php
Para conflictos complejos puede usarse una herramienta visual de fusión (Meld, KDiff3, o el editor integrado de conflictos de VS Code), invocable con:
git mergetool
Paso 5. Marcar el conflicto como resuelto (añadir al staging).
git add index.php
Verificación de que ya no quedan rutas sin fusionar:
git status
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Paso 6. Confirmar la fusión.
git commit
Git abre el editor con un mensaje de merge prerredactado (Merge branch 'main' into desarrollo), que se acepta o edita. También puede hacerse en una línea:
git commit -m "Merge branch 'main' into desarrollo: resuelto conflicto en index.php"
Paso 7. Verificar el resultado.
git log --oneline --graph --decorate -5
grep -nR "<<<<<<<\|=======\|>>>>>>>" index.php # debe no devolver nada
El historial mostrará el commit de fusión con dos padres (el de desarrollo y el de main), confirmando una integración correcta. Conviene además ejecutar las pruebas o cargar la aplicación para comprobar que el código fusionado funciona.
Justificación técnica: un conflicto de contenido aparece porque el algoritmo de fusión a tres vías (recursive/ort) detecta cambios incompatibles en la misma región respecto al ancestro común; al no poder elegir automáticamente, Git protege la integridad delegando la decisión en el desarrollador. El git add reinterpreta el fichero como resuelto y el git commit materializa el nodo de fusión en el grafo dirigido acíclico (DAG) de la historia.
Cuestión 2 — Qué hace git merge --abort
git merge --abort
git merge --abort cancela la fusión en curso y restaura el repositorio al estado exacto que tenía justo antes de ejecutar git merge, como si la operación nunca se hubiera iniciado:
- Elimina los marcadores de conflicto del árbol de trabajo y revierte
index.php (y cualquier otro fichero afectado) a su contenido previo al merge.
- Devuelve
HEAD, el área de staging (índice) y el directorio de trabajo a la posición anterior, descartando la fusión a medias.
- Sale del estado MERGING; tras ejecutarlo
git status vuelve a mostrar la rama desarrollo limpia.
Condiciones y matices: solo funciona mientras hay una fusión sin concluir (existe MERGE_HEAD). Equivale en la práctica a git reset --merge. Es la opción correcta cuando se decide no incorporar los cambios en ese momento o cuando el conflicto es demasiado grande para resolverlo ahora. Advertencia: si antes de iniciar el merge había cambios locales sin commitear, --abort intenta preservarlos, pero por seguridad conviene tener el árbol limpio (todo confirmado) antes de fusionar.
Buenas prácticas para minimizar conflictos
- Hacer
git pull/sincronizar main con frecuencia para que las ramas no diverjan demasiado.
- Trabajar con commits atómicos y ramas de vida corta.
- Coordinar con el equipo para no editar simultáneamente las mismas regiones de un fichero.
- Revisar siempre con
git status y git diff antes de confirmar, y ejecutar las pruebas tras toda fusión.