Git

Git

Tutorial Git: Resolución de conflictos

Git conflictos: resolución y manejo. Domina la resolución y manejo de conflictos en Git con ejemplos prácticos y detallados.

Aprende Git y certifícate

Por qué ocurren los conflictos: Ediciones concurrentes en el mismo archivo/línea

Los conflictos ocurren cuando varios desarrolladores editan de forma concurrente el mismo archivo o la misma línea de código. Esto es normal cuando un equipo trabaja en paralelo y toca partes similares del código.

Cuando dos o más ramas contienen cambios en las mismas líneas de un archivo, Git no puede fusionarlos automáticamente. Por ejemplo, si en la rama feature-1 se modifica la función calcularPrecio() y simultáneamente en la rama feature-2 se realizan cambios diferentes en esa misma función, al intentar fusionarlas, se generará un conflicto.

Los conflictos también surgen al editar el mismo archivo en distintas ramas sin sincronizar los cambios. Si no se ejecutan comandos como git pull o git fetch para actualizar la copia local con los últimos cambios remotos, se trabaja sobre una versión desactualizada, aumentando la probabilidad de conflictos al hacer git merge.

Cuando Git detecta cambios que no puede combinar automáticamente, añade marcadores en el archivo afectado para señalar las diferencias. Por ejemplo:

<<<<<<< HEAD
def calcular_total(precio, cantidad):
    return precio * cantidad
=======
def calcular_total(precio_unitario, cantidad):
    return precio_unitario * cantidad
>>>>>>> rama-feature

En este caso, los dos cambios modifican la misma línea de la función calcular_total, y ocurre un conflicto.

También hay que tener en cuenta que los conflictos pueden ocurrir por diferencias en el formato de código, como espacios o tabulaciones, o por cambios en el estilo de escritura. Hay herramientas de formateo y linters que pueden ayudar a minimizar estos conflictos al mantener un estilo consistente en todo el proyecto.

Detección de conflictos: Mensajes de error en merge o rebase

Al trabajar con Git, se suelen utilizar comandos como git merge o git rebase para integrar cambios de diferentes ramas. Durante estas operaciones, Git intenta combinar automáticamente las modificaciones. Sin embargo, cuando hay cambios conflictivos en el mismo archivo, Git no puede resolverlos sin intervención humana y genera mensajes de error para indicar la presencia de conflictos.

Al ejecutar git merge y ocurrir un conflicto, Git mostrará un mensaje similar a:

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

Este mensaje indica que se ha detectado un conflicto en el contenido de archivo.txt. Git dice que la fusión automática ha fallado y sugiere corregir los conflictos antes de confirmar los cambios.

Con git rebase, los conflictos también pueden surgir al aplicar commits sobre una nueva base. Al ocurrir un conflicto durante un rebase, se ve un mensaje como:

Applying: Implementación de nueva función
Using index info to reconstruct a base tree...
M       archivo.txt
Falling back to patching base and 3-way merge...
Auto-merging archivo.txt
CONFLICT (content): Merge conflict in archivo.txt
error: Failed to merge in the changes.
Patch failed at 0001 Implementación de nueva función
hint: Use 'git am --show-current-patch' to see the failed patch

En este caso, Git dice que no ha podido aplicar un parche debido a un conflicto en archivo.txt. Además, da sugerencias como usar git am --show-current-patch para ver el parche que ha fallado.

Los indicadores de conflicto en los mensajes de Git permiten ver rápidamente dónde han ocurrido los problemas. Es importante prestar atención a las palabras clave como CONFLICT, Automatic merge failed, o Failed to merge, porque señalan directamente los archivos afectados.

Después de detectar un conflicto, se puede utilizar git status para obtener más detalles. Este comando proporciona información sobre los archivos en conflicto, listándolos bajo la sección "Unmerged paths":

On branch main
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:   archivo.txt

no changes added to commit (use "git add" and/or "git commit -a")

Este output indica que archivo.txt ha sido modificado en ambas ramas y hace falta una resolución. Las instrucciones sugieren cómo actuar para solucionar el conflicto o abortar la operación si se prefiere.

Después de resolver un conflicto, siempre es conveniente revisar el código del proyecto.

Resolución manual vs. herramientas gráficas: Estrategias de fusión

Existen dos enfoques principales para la resolución de conflictos: la resolución manual y el uso de herramientas gráficas.

En la resolución manual, se editan directamente los archivos en conflicto para resolver las diferencias. Git señala las secciones afectadas con indicadores <<<<<<<, ======= y >>>>>>>, permitiendo identificar las diferencias entre versiones. Por ejemplo:

<<<<<<< HEAD
def calcular_total(precio, cantidad):
    return precio * cantidad
=======
def calcular_total(precio_unitario, cantidad):
    return precio_unitario * cantidad
>>>>>>> rama-feature

Hay que analizar el código entre <<<<<<< HEAD y ======= (la versión actual), y entre ======= y >>>>>>> rama-feature (la versión entrante), para decidir cuál mantener o cómo combinarlos. Una vez resuelto el conflicto, se añaden los cambios con git add archivo y se confirman con git commit.

El enfoque manual es más preciso pero puede ser muy costoso en conflictos muy complejos. Por eso, las herramientas gráficas se utilizan para simplificar el proceso. Aplicaciones como Visual Studio Code, Sourcetree, GitKraken o Meld tienen interfaces visuales que facilitan la comparación y fusión de cambios.

Por ejemplo, en Visual Studio Code, al abrir un archivo en conflicto, se muestran las versiones en conflicto de forma destacada, ofreciendo opciones como:

  • Accept Current Change: Se conserva la versión local.
  • Accept Incoming Change: Se acepta la versión entrante.
  • Accept Both Changes: Se combinan ambas versiones.

Estas herramientas permiten visualizar fácilmente las diferencias y decidir cómo resolverlas sin editar manualmente los indicadores de conflicto.

Las estrategias de fusión dependen del flujo de trabajo y las políticas del equipo. Las más comunes son:

  • Fusión directa (git merge): Se combina el historial de dos ramas, creando un commit de fusión que refleja la unión de ambas líneas de desarrollo.
  • Rebase (git rebase): Se reescribe el historial de commits, aplicando los cambios de una rama sobre otra, lo que resulta en un historial lineal sin commits de fusión.
  • Fusión por squash (git merge --squash): Se fusionan los cambios pero no se crea un commit de fusión automático, permitiendo juntar múltiples commits en uno solo.

La elección entre estas estrategias afecta al historial del repositorio y puede influir en la detección de conflictos en un futuro. Por ejemplo, al utilizar rebase se puede tener un historial más limpio, pero hay que tener cuidado para evitar conflictos y asegurarse de no sobrescribir cambios compartidos.

Algunos consejos para manejar conflictos y fusiones son:

  • Realizar commits pequeños y frecuentes para aislar cambios y simplificar la resolución de conflictos.
  • Sincronizar con regularidad con la rama principal para minimizar divergencias.
  • Hacer uso de capacidades visuales de las herramientas gráficas para entender el contexto de los cambios.
  • Documentar las decisiones tomadas durante la resolución de conflictos para referencia futura.

Prevención de conflictos: Comunicación, commits pequeños y revisar antes de fusionar

La Comunicación entre los miembros del equipo, realizar commits pequeños y revisar detalladamente los cambios antes de fusionar son prácticas clave para evitar conflictos.

La comunicación constante permite que los desarrolladores estén al tanto de las partes del código en las que otros están trabajando. Se pueden usar canales de chat, reuniones diarias o sistemas de seguimiento de tareas para reducir la probabilidad de modificar simultáneamente las mismas secciones de código.

Hacer commits pequeños y frecuentes facilita la integración de cambios y limita el área de impacto de cada modificación. Los commits concisos son más fáciles de revisar y revertir en caso necesario, lo que disminuye las posibilidades de generar conflictos complejos durante las fusiones. Además, los commits deben ser atómicos, es decir, cada commit debe representar una única funcionalidad o corrección.

Para detectar posibles conflictos antes de que ocurran conviene revisar los cambios antes de fusionarlos. Realizar pull o fetch con frecuencia ayuda a mantener el repositorio local actualizado con los cambios remotos. Antes de confirmar una fusión, se recomienda revisar las diferencias con la rama objetivo utilizando comandos como git diff. Esto permite identificar discrepancias y resolverlas antes de completar la fusión.

También se pueden hacer revisiones de código mediante pull requests. Al someter los cambios a revisión por otros miembros del equipo, se pueden detectar conflictos potenciales.

Establecer convenciones de estilo de código y utilizar herramientas de formateo automáticas puede prevenir conflictos relacionados con diferencias en la estructura o formato del código. Herramientas como Prettier o ESLint aplican un estilo consistente en todo el proyecto, reduciendo cambios innecesarios que podrían provocar conflictos.

Es aconsejable trabajar en ramas específicas para cada funcionalidad o corrección. Para hacer más fácil la integración de los cambios se recomienda mantener las ramas actualizadas con la rama principal mediante fusiones o rebase.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende Git online

Ejercicios de esta lección Resolución de conflictos

Evalúa tus conocimientos de esta lección Resolución de conflictos con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de Git

Accede a todas las lecciones de Git y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Git y certifícate

Certificados de superación de Git

Supera todos los ejercicios de programación del curso de Git y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender la importancia de la resolución de conflictos en GitHub Desktop.
  2. Identificar escenarios de conflicto.
  3. Aprender la resolución manual de conflictos.
  4. Aplicar buenas prácticas para evitar conflictos.