Saltar al contenido

conflictos de fusión

Los conflictos de fusión ocurren cuando varios autores editan el mismo contenido o cuando un desarrollador elimina un archivo mientras otro desarrollador estaba haciendo cambios en él. Para resolver este problema, los desarrolladores trabajan en ramas aisladas. El comando git merge es responsable de combinar ramas aisladas y resolver ediciones en conflicto.

Git hace que el proceso de fusión sea más fácil que la mayoría de los sistemas de control de versiones. Git puede integrar automáticamente los cambios nuevos en muchos casos. Pero en los casos de conflicto, Git no puede determinar automáticamente qué versión es la correcta. Marca el archivo como en conflicto y detiene el proceso de fusión.

mergeconflicts

Interrupciones comunes de la fusión

Los errores pueden ocurrir en dos momentos: al inicio del proceso de fusión o durante él. Ten en cuenta que normalmente se deben a cambios locales no confirmados, más que a conflictos reales de contenido.

Fallo al iniciar la fusión

Git no puede iniciar una fusión porque los cambios pendientes en el directorio de trabajo o en el área de preparación del proyecto serían sobrescritos por los commits que se están fusionando. Esto ocurre debido a cambios locales pendientes. Para tomar control del estado local, se usan los comandos git stash, git checkout, git commit y git reset. El siguiente mensaje aparecerá cuando ocurra un error al inicio:

git conflicts

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

Fallo durante la fusión

El fallo durante la fusión indica que hay un conflicto entre la rama local actual y la rama que se está fusionando. El siguiente mensaje aparecerá cuando ocurra un error durante la fusión:

failure during merge

bash
CONFLICT (content): Merge conflict in example.txt
Automatic merge failed; fix conflicts and then commit the result.

Creación de un conflicto de fusión

Aquí mostraremos una simulación de cómo aparecen los conflictos de fusión.

merge conflicts

bash
mkdir test-dir
cd test-dir
git init .
echo "some content" > example.txt
git add example.txt
git commit -m "initial commit"
[master (root-commit) a45c22d] initial commit
1 file changed, 1 insertion(+)
create mode 100644 example.txt

En el ejemplo dado, creamos un nuevo directorio llamado test-dir. A continuación, creamos el archivo de texto example.txt con algo de contenido y lo añadimos al repositorio y lo confirmamos. Como resultado, tenemos un nuevo repositorio con una rama master y el archivo example.txt. El siguiente paso es crear otra rama para usarla como una fusión en conflicto.

resolving conflicts

bash
git checkout -b branch_to_merge
echo "completely different content to merge later" > example.txt
git commit -m "edit the content of example.txt to make a conflict"
[branch_to_merge 4221135] edit the content of example.txt to make a conflict
1 file changed, 1 insertion(+), 1 deletion(-)

En el ejemplo anterior, creamos y hacemos checkout de la rama branch_to_merge. Después de crearla, sobrescribimos el contenido de example.txt y confirmamos el cambio. Después de hacer todo esto, el commit sobrescribe el contenido de example.txt:

git merging conflicts

bash
git checkout master
Switched to branch 'master'
echo "content to add" >> example.txt
git commit -m "added content to example.txt"
[master 11ab34b] added content to example.txt
1 file changed, 1 insertion(+)

Estos comandos cambian a la rama master, añaden contenido a example.txt y confirman el cambio. Esto coloca al repositorio en un estado en el que la rama master y la rama branch_to_merge tienen cada una un commit único. El paso final es ejecutar el comando git merge, tras el cual ocurrirá el conflicto:

git merge

bash
git merge branch_to_merge
Auto-merging example.txt
CONFLICT (content): Merge conflict in example.txt
Automatic merge failed; fix conflicts and then commit the result.

Identificación de conflictos de fusión

Como ya hemos visto, Git muestra una salida que indica que ha aparecido un conflicto. Ejecuta el comando git status para ver las rutas no fusionadas:

git conflicts

bash
git status
On branch master
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:   example.txt

El archivo example.txt aparece en un estado modificado. Ejecuta el comando cat para mostrar el contenido del archivo example.txt. Podemos ver estos marcadores visuales:

git resolving conflicts

bash
<<<<<<< HEAD
=======
>>>>>>> branch_to_merge

El marcador ======= indica el centro del conflicto. El contenido entre los marcadores <<<<<<< HEAD y ======= pertenece a la rama actual (master) a la que apunta la referencia HEAD. Para cancelar la fusión por completo y volver al estado anterior a la fusión, ejecuta git merge --abort. Lee más sobre los marcadores visuales en la página de git merge.

Resolución de conflictos de fusión

Para resolver un conflicto de fusión debes editar el archivo en conflicto. Abre el archivo example.txt en un editor, elimina los marcadores de conflicto y conserva los cambios deseados. Un archivo resuelto podría verse así:

conflicts in git

bash
some content to mess with
content to add

Ejecuta el comando git add para preparar el nuevo contenido fusionado. A continuación, crea un nuevo commit para completar la fusión:

resolving conflicts in git

bash
git add example.txt
git commit -m "the conflict in example.txt is merged and resolved"

Como alternativa, puedes usar git mergetool para resolver conflictos visualmente usando una herramienta de diff configurada. Por ejemplo, ejecuta git mergetool example.txt para abrir la herramienta para un archivo específico.

ToolDescription
git statusHelps find out conflicted files.
git mergetoolOpens a visual diff tool to resolve conflicts interactively.
git diffShows differences between commits, branches, or files to help identify potential conflicts before merging.
git checkout --ours/--theirsReplaces the conflicted file with content from the current or incoming branch.
git reset --mixedUnstages files but leaves the working directory unchanged.
git merge --abortAborts the current merge and restores the working directory to the state before the merge started.
git resetResets the index to match HEAD, helping to unstage conflicted files.

Práctica

What are the aspects of handling merge conflicts in Git?

¿Te resulta útil?

Vista previa dual-run — compárala con las rutas Symfony en producción.