Tutorial sobre cómo resolver conflictos de fusión en Git
- ¿Qué es un conflicto de fusión Git?
- Tipos de fusión
- Tipos de conflictos Git Merge
- Comandos para resolver conflictos de fusión Git
- Herramientas de Fusión Visual
- Cómo resolver un conflicto de fusión Git
- Conclusión
¿Qué es un conflicto de fusión Git?
El sistema de control de versiones Git consiste en trabajar en equipo y contribuir a los proyectos. Los desarrolladores suelen trabajar en ramas aisladas y, cuando terminan, fusionan los cambios con la rama principal. Este tipo de trabajo en equipo es muy productivo y eficaz para encontrar fallos. A veces varios desarrolladores trabajan en la misma línea de código, y cuando intentan fusionar los cambios, surgen conflictos.
Ejemplo sencillo de conflicto Git
El diagrama anterior es un ejemplo perfecto de cómo se produce un típico conflicto de fusión Git. La rama principal tiene un archivo que contiene el texto "¡HOLA, MUNDO!". El nombre de usuario abid bifurca la rama principal, y cambia el texto a "¡HOLA, GATO!". Mientras abid realiza los cambios, la rama principal original también se modifica a "¡HOLA, PERRO!". Fusionar estas ramas provocará un problema de conflicto de fusión y detendrá el proceso.
La función principal del comando `git merge` es combinar dos ramas y resolver automáticamente los conflictos. Sin embargo, de vez en cuando surgen conflictos en los que dos personas han cambiado la misma línea de código o han eliminado archivos críticos en los que estaba trabajando otro desarrollador. Git marcará estos cambios y detendrá el proceso de fusión. En este caso, el conflicto no se ha resuelto automáticamente, sino que el programador tiene que hacer cambios manualmente o utilizar herramientas para resolverlo.
Conviértete en Ingeniero de Datos
Tipos de fusión
Git merge y rebase son las dos formas de integrar los commits de la rama destino en la rama origen. Además, la fusión Git realiza una fusión con avance rápido o sin avance rápido. Si la cabecera de la rama de destino existe en la rama de origen, entonces, por defecto, el tipo de fusión será una fusión rápida y, si falta, una fusión no rápida. Git rebase es otro tipo de fusión que vuelve a secuenciar el historial de confirmaciones de la rama de destino.
Fusión rápida
Por defecto, la fusión de Git utiliza el avance rápido para integrar las confirmaciones que faltan en la rama de destino. Por ejemplo, se utiliza para actualizar la rama local desde un servidor remoto mediante el comando pull. El avance rápido no plantea problemas de conflictos de fusión, ya que Git no lo aplicará si falta la cabecera de la rama de destino en la rama de origen.
Fusión sin avance rápido
Una fusión sin avance rápido también se denomina fusión a tres o fusión verdadera. Crea una nueva confirmación en una rama de destino integrando los cambios tanto en la rama de origen como en la de destino. Los cambios se mezclan después de la última confirmación común en ambas ramas. En nuestro caso, está después de la C. Este tipo de fusión provocará un conflicto de fusión Git si la rama de origen está en disputa con la rama de destino. En el diagrama anterior, la confirmación de fusión (X) se crea integrando la rama de origen y la de destino, donde K y E son los padres de la confirmación de fusión.
Rebase
Git rebase es un poco diferente de otros tipos. Cambia la secuencia del historial de confirmaciones de la rama de destino. El rebase integra la rama origen de tal forma que la rama destino contiene todos los cambios de la rama origen, seguidos de todos los commits de la rama destino posteriores al último commit común. En nuestro caso, la última confirmación común es C, mientras que D y E son de la rama fuente. La confirmación K* es la misma que K con un identificador de confirmación diferente. En lugar de enlazar C, se enlazará E. De forma similar a una fusión sin avance rápido, si hay problemas de compatibilidad en la rama de origen y la de destino, Git planteará una incidencia para resolver el conflicto antes de finalizar el rebase.
Tipos de conflictos Git Merge
Existen dos tipos de conflictos de fusión de Git: al inicio y durante el proceso de fusión - Atlassian. En esta sección, conoceremos ambos tipos y las formas de resolver cada escenario.
Al inicio de la fusión
La fusión Git fallará al inicio si hay cambios en el directorio de trabajo o en el área de preparación. Falla al principio para evitar que los cambios sean sobrescritos por las confirmaciones de fusión entrantes. Esto ocurre debido a conflictos con cambios locales, no con otras ramas o desarrolladores. Para estabilizar el estado local, puedes utilizar comandos como git stash
, git commit
, git checkout
, o git reset
.
Durante la Fusión
Un fallo durante la fusión significa que hay un conflicto entre la rama de origen y la de destino en el que varios desarrolladores han modificado el mismo archivo. Si la fusión automática falla, Git te pedirá que resuelvas los problemas manualmente. También puedes utilizar herramientas de terceros que te ayuden a visualizar e integrar los cambios.
Comandos para resolver conflictos de fusión Git
En esta sección, conoceremos varios comandos nativos para visualizar y resolver los conflictos de fusión de Git.
Comandos comunes
El estado de Git es el comando más utilizado para mostrar el estado de los archivos modificados, el área de preparación y las confirmaciones. Durante el proceso de fusión, se utiliza para identificar los archivos conflictivos.
git status
El registro de Git con argumentos --merge produce la lista de confirmaciones que están en conflicto con la rama fuente.
git log --merge
Por defecto, la opción git diff
te mostrará la diferencia entre los cambios no comprometidos y las confirmaciones anteriores. Git diff se utiliza para comparar ramas, confirmaciones y archivos. Es útil para evitar futuros conflictos de fusión.
git diff
Comandos para Fusiones fallidas al inicio
La comprobación se utiliza para deshacer cambios o cambiar a una rama nueva o antigua.
git checkout
El reinicio de Git sirve para revertir los cambios en el directorio de trabajo y en el área de preparación.
git reset --mixed
Comandos para conflictos durante la fusión
El argumento --abort detendrá el proceso de fusión y revertirá los cambios a su estado original antes de que comenzara la fusión.
git merge --abort
Git reset se suele utilizar durante el proceso de fusión para revertir los archivos en conflicto a su estado original.
git reset
Resolver conflictos entre archivos borrados y modificados
Se producirá un conflicto Git si has eliminado el archivo en la rama actual, y otra persona lo ha modificado en otra rama. En este caso, puedes añadir un archivo y confirmarlo,
git add <filename>
o puedes eliminar el archivo y confirmarlo.
git rm <filename>
Herramientas de Fusión Visual
Las herramientas de fusión son herramientas visuales fáciles de usar para identificar y resolver todo tipo de conflictos de fusión. Algunas de las herramientas admiten funciones adicionales, como la comparación de cambios, las operaciones Git y la gestión de proyectos y repositorios. Hay dos tipos de herramientas de fusión de Git: las de terminal y las basadas en GUI. Las herramientas basadas en terminal se abren dentro de PowerShell o Bash, y las herramientas basadas en GUI se abren en un entorno de ventanas.
Para comprobar la lista de herramientas instaladas y válidas, utiliza:
git mergetool --tool-help
La lista consta de todas las herramientas válidas que pueden instalarse e integrarse con comandos git.
Por ejemplo, tenemos vim y nvim instalados por defecto, y si quieres ver la diferencia entre un archivo no confirmado y un confirmado anterior, escribe:
git difftool --tool=vimdiff3
La herramienta vimdiff3 resalta los cambios y te permite comparar commits dentro del terminal.
Diferencia entre dos versiones del mismo archivo en Vimdiff3
Fusiona
Meld es una herramienta gratuita y de código abierto que lleva la resolución de conflictos de fusión a otro nivel. Para integrarlo con Git, primero tienes que descargar e instalar la configuración desde el sitio oficial. A continuación, añádelo a la configuración global para que, por defecto, Git lance Meld para resolver conflictos.
Los siguientes comandos de configuración sólo son aplicables a los usuarios de Windows. El único cambio que tienes que hacer es cambiar la ruta del archivo instalado de Meld para Mac o Linux.
git config --global merge.tool meld
git config --global mergetool.meld.path "C:/Program Files (x86)/Meld/Meld.exe"
git config --global diff.tool meld
git config --global difftool.meld.path "C:/Program Files (x86)/Meld/Meld.exe"
Después de configurar los valores por defecto, puedes escribir git difftool
dentro del directorio local de Git para lanzar la versión de Windows de Meld, o puedes git mergetool
para resolver los conflictos de fusión como se muestra a continuación.
Resolver un conflicto de fusión con Meld
VSCode
VSCode proporciona la forma mejor y más popular de resolver el conflicto de fusión. Cuando Git no consigue fusionar archivos automáticamente, el VSCode resaltará el código en conflicto y te dará cuatro opciones: aceptar los cambios actuales, aceptar los cambios entrantes, aceptar ambos cambios y comparar los cambios. Puedes utilizar estas opciones para limpiar tu archivo y resolver todos los problemas pendientes.
Resolver un conflicto de fusión con VSCode
Si buscas una solución completa para tus operaciones Git, prueba GitKraken. Viene con un cliente gratuito, la extensión VSCode, y proporciona una herramienta integrada para resolver conflictos de fusión.
Cómo resolver un conflicto de fusión Git
En esta sección, vamos a aprender a crear un conflicto de fusión Git y a resolverlo. El tutorial se divide en dos partes. En la primera parte, aprenderemos a resolver conflictos Git localmente; la segunda parte trata sobre la resolución de conflictos con un servidor remoto (GitHub).
Conflicto de fusión local
Crear conflictos de fusión nos ayudará a aprender cómo surgen estos problemas en primer lugar. A continuación, podemos utilizar formas creativas de resolver estos problemas o incluso evitar que se produzcan en el futuro.
Ahora crearemos un repositorio Git con un único archivo y crearemos nuestro primer commit para empezar.
- Crea una carpeta llamada datacamp.
- Cambia el directorio a datacamp.
- Inicializa Git.
- Crea un archivo README.md con el título dado.
- Etapa y confirma los cambios en un archivo.
mkdir datacamp
cd datacamp
git init
echo "# How to Resolve Git Merge Conflict" > README.md
git add README.md
git commit -m "first commit"
>>> [main (root-commit) 8199ea2] first commit
>>> 1 file changed, 1 insertion(+)
>>> create mode 100644 README.md
A continuación, crearemos una nueva rama readme y cambiaremos el título de "..Git Merge.." a "..Git..". Añade el archivo y crea la confirmación utilizando el argumento -am.
git checkout -b readme
echo "# How to Resolve Git Conflict" > README.md
git commit -am "new branch conflict added"
>>> [readme 155f694] new branch conflict added
>>> 1 file changed, 1 insertion(+), 1 deletion(-)
Vuelve a la rama principal y añade una nueva línea al archivo README.md utilizando >>. Al guardar los cambios y crear confirmaciones, hemos conseguido formar un conflicto entre dos versiones del mismo archivo.
git checkout main
echo "New change in base branch" >> README.md
git commit -am " a line added to base branch Readme file"
>>> [main f1f1874] a line added to base branch Readme file
>>> 1 file changed, 1 insertion(+)
Como podemos ver, al fusionar la rama readme, Git ha mostrado un mensaje diciendo que la fusión automática ha fallado, y que tenemos que hacer los cambios manualmente y luego confirmar el resultado.
git merge readme
>>> Auto-merging README.md
>>> CONFLICT (content): Merge conflict in README.md
>>> Automatic merge failed; fix conflicts and then commit the result.
Resolveremos el problema manualmente abriendo y editando el archivo en el Bloc de Notas. La imagen de abajo muestra la flecha con HEAD, un divisor y una flecha de dirección diferente con un readme. La parte HEAD muestra los cambios existentes en la rama principal, y la parte readme es la rama que queremos fusionar, que consiste en un encabezamiento diferente.
Resolver manualmente un conflicto de fusión
Para resolver el problema, eliminaremos la parte de la rama readme, las flechas y el divisor. La versión final del archivo debe tener un aspecto limpio, como se muestra a continuación.
Conflicto resuelto
Después de añadir el archivo y crear una confirmación, se resolverá el conflicto de fusión. Es la forma más habitual y sencilla de resolver los problemas. También puedes utilizar un entorno de desarrollo integrado (IDE) para resolver los problemas más rápidamente.
git commit -am "conflict resolved in file README.md"
>>> [main 9994a29] conflict resolved in file README.md
Conflicto de Fusión Remota
Para crear y resolver conflictos de fusión remota, necesitamos crear un nuevo repositorio en GitHub.
Crear un nuevo repositorio en GitHub
A continuación, añade el nombre remoto (origen) con la dirección al repositorio y empuja todos los cambios de un repositorio local a la rama principal remota utilizando upstream.
git remote add origin https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
git push --set-upstream origin main
>>> Enumerating objects: 12, done.
>>> Counting objects: 100% (12/12), done.
>>> Delta compression using up to 4 threads
>>> Compressing objects: 100% (6/6), done.
>>> Writing objects: 100% (12/12), 998 bytes | 499.00 KiB/s, done.
>>> Total 12 (delta 2), reused 0 (delta 0), pack-reused 0
>>> remote: Resolving deltas: 100% (2/2), done.
>>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
>>> * [new branch] main -> main
>>> branch 'main' set up to track 'origin/main'.
Para crear un conflicto, tenemos que hacer cambios en el archivo README.md remoto y local. Puedes utilizar el editor de archivos de GitHub para cambiar "..Git merge.." por "..Sit-Merge.." y luego confirmar los cambios.
Hacer cambios en el editor de GitHub
Después, en el repositorio local, cambia el archivo README.md para añadir sólo un título sencillo y confirma los cambios.
echo "# How to Resolve Merge Conflicts in Git Tutorial" > README.md
git commit -am "local branch changes in README.md"
>>> [main c677a13] local branch changes in README.md
>>> 1 file changed, 1 insertion(+), 4 deletions(-)
Por último, envía los cambios al servidor remoto. Observa que Git ha planteado el error con pistas sobre cómo eliminar el problema.
git push
>>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
>>> ! [rejected] main -> main (fetch first)
>>> error: failed to push some refs to 'https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git'
>>> hint: Updates were rejected because the remote contains work that you do
>>> hint: not have locally. This is usually caused by another repository pushing
>>> hint: to the same ref. You may want to first integrate the remote changes
>>> hint: (e.g., 'git pull ...') before pushing again.
>>> hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Seguiremos la sugerencia más sencilla, que consiste en extraer el archivo del servidor remoto antes de empujarlo.
La extracción del archivo ha fallado debido a un conflicto de fusión en el archivo README.md. Podríamos arreglarlo manualmente utilizando el Bloc de Notas, pero esta vez utilizaremos una herramienta visual que nos ayude en este proceso.
git pull
>>> remote: Enumerating objects: 5, done.
>>> remote: Counting objects: 100% (5/5), done.
>>> remote: Compressing objects: 100% (2/2), done.
>>> remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
>>> Unpacking objects: 100% (3/3), 681 bytes | 75.00 KiB/s, done.
>>> From https://github.com/kingabzpro/DataCamp-Git-Merge-Guide
>>> aaf149d..49b7d14 main -> origin/main
>>> Auto-merging README.md
>>> CONFLICT (content): Merge conflict in README.md
>>> Automatic merge failed; fix conflicts and then commit the result.
La herramienta de fusión Meld identificará los archivos en conflicto y los mostrará en la aplicación GUI Meld.
git mergetool
>>> Merging:
>>> README.md
>>> Normal merge conflict for 'README.md':
>>> {local}: modified file
>>> {remote}: modified file
Hay tres columnas: README_LOCAL_473.md, README.md y README_LOCAL_473.md. Si crees que los cambios remotos son válidos, haz clic en la flecha negra de la columna remota; y si quieres que persistan los cambios locales, haz clic en la flecha negra de la columna local. Es así de sencillo.
Conflicto resuelto con mergetool Meld
Tras realizar los cambios, guarda el archivo y confírmalo. Como puedes ver, al enviar un archivo a un servidor remoto no se produce un error de conflicto de fusión.
git commit -am "remote main branch conflict resolved"
git push
>>> Enumerating objects: 16, done.
>>> Counting objects: 100% (16/16), done.
>>> Delta compression using up to 4 threads
>>> Compressing objects: 100% (6/6), done.
>>> Writing objects: 100% (10/10), 1.08 KiB | 550.00 KiB/s, done.
>>> Total 10 (delta 2), reused 0 (delta 0), pack-reused 0
>>> remote: Resolving deltas: 100% (2/2), completed with 1 local object.
>>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
>>> 49b7d14..8f5c3aa main -> main
Hemos resuelto con éxito los conflictos de fusión locales y remotos. Los científicos de datos y los ingenieros de aprendizaje automático se enfrentan diariamente a estos conflictos. Para mejorar tus habilidades en las operaciones de Git, haz un curso de Introducción a Git.
Conclusión
Resolver los conflictos de fusión de Git es una tarea compleja y muy arriesgada, ya que puedes romper el software al fusionar código defectuoso. Las herramientas de fusión proporcionan un entorno fácil de usar con una forma más segura de detectar y resolver los conflictos de fusión. En este tutorial, hemos aprendido por qué se producen los conflictos Git y cómo resolverlos. También hemos cubierto varios tipos de fusiones y conflictos, comandos Git útiles y herramientas visuales. En la sección final, creamos un conflicto de fusión y lo resolvimos en un repositorio local y otro remoto.
Si eres nuevo en Git y quieres aprender cómo funciona, entonces lee: Introducción a Git y Tutorial de GitHub.
Certifícate en el puesto de Ingeniero de Datos de tus sueños
Nuestros programas de certificación te ayudan a destacar y a demostrar que tus aptitudes están preparadas para el trabajo a posibles empleadores.