Cómo comprender y resolver conflictos en Git

Ahí está, la palabra que todo desarrollador odia ver: conflicto. ? Simplemente no hay forma de evitar el conflicto de fusión ocasional cuando se trabaja con Git (u otros sistemas de control de versiones).

Pero cuando hablo con los desarrolladores, a menudo escucho que hay una sensación de ansiedad o incomodidad en torno al tema de los conflictos de fusión.

Manejar los conflictos a menudo sigue siendo un lugar oscuro y misterioso: una situación en la que las cosas están muy mal y no está claro cómo salir de ella (sin empeorar las cosas).

Si bien es cierto que los conflictos de fusión son una parte inevitable de la vida de un desarrollador, la incomodidad en estas situaciones es completamente opcional.

Mi intención con este artículo es aportar algo de claridad a este tema: cómo y cuándo ocurren normalmente los conflictos, qué son en realidad y cómo resolverlos, o deshacerlos.

Cuando comprenda adecuadamente estas cosas, podrá lidiar con los conflictos de fusión de una manera mucho más relajada y segura. ?

Cómo y cuándo ocurren los conflictos

El nombre ya lo dice: "conflictos de fusión" pueden ocurrir en el proceso de integración de confirmaciones de una fuente diferente.

Sin embargo, tenga en cuenta que la "integración" no se limita únicamente a "fusionar ramas". También puede suceder al reajustar o reajustar interactivamente, al realizar una selección o un tirón, o incluso al volver a aplicar un Stash.

Todas estas acciones realizan algún tipo de integración, y es entonces cuando pueden ocurrir conflictos de fusión.

Pero, por supuesto, estas acciones no resultan en un conflicto de fusión cada vez (¡gracias a Dios!). Idealmente, debería encontrarse en estas situaciones sólo en raras ocasiones. Pero, ¿cuándo ocurren exactamente los conflictos?

En realidad, las capacidades de fusión de Git son una de sus mayores ventajas: la fusión de ramas funciona sin esfuerzo la mayor parte del tiempo, porque Git suele ser capaz de resolver las cosas por sí solo.

Pero hay situaciones en las que se realizaron cambios contradictorios y en las que la tecnología simplemente no puede decidir qué está bien o qué está mal. Estas situaciones simplemente requieren una decisión de un ser humano.

El verdadero clásico es cuando se cambió exactamente la misma línea de código en dos confirmaciones, en dos ramas diferentes. ¡Git no tiene forma de saber qué cambio prefiere! ?

Existen otras situaciones similares, por ejemplo, cuando un archivo se modificó en una rama y se eliminó en otra, pero son un poco menos comunes.

La GUI de escritorio Git "Tower" , por ejemplo, tiene una forma agradable de visualizar este tipo de situaciones:

Cómo saber cuándo ha ocurrido un conflicto

No se preocupe: Git le dirá muy claramente cuándo ha ocurrido un conflicto. ?  

Primero, le informará inmediatamente de la situación , por ejemplo, cuando una fusión o rebase falla debido a un conflicto:

$ git merge develop Auto-merging index.html CONFLICT (content): Merge conflict in index.html CONFLICT (modify/delete): error.html deleted in HEAD and modified in develop. Version develop of error.html left in tree. Automatic merge failed; fix conflicts and then commit the result.

Como puede ver en el ejemplo anterior, cuando intenté realizar una fusión, creé un conflicto de fusión, y Git comunica el problema de manera muy clara y rápida:

  • Se produjo un conflicto en el archivo "index.html".
  • Ocurrió otro conflicto en el archivo "error.html".
  • Y finalmente, debido a los conflictos, la operación de fusión falló.

Estas son las situaciones en las que tenemos que profundizar en el código y ver qué se debe hacer.

En el caso poco probable de que haya pasado por alto estos mensajes de advertencia cuando ocurrió el conflicto, Git también le informa cada vez que ejecuta git status:

$ git status 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/rm ..." as appropriate to mark resolution) deleted by us: error.html both modified: index.html

En otras palabras: no se preocupe por no notar conflictos de fusión. Git se asegura de que no puedas pasarlos por alto.

Cómo deshacer un conflicto en Git y empezar de nuevo

Los conflictos de fusión vienen con cierto aire de urgencia. Y con razón: tendrás que lidiar con ellos antes de poder continuar con tu trabajo.

Pero aunque ignorarlos no es una opción, "lidiar con los conflictos de fusión" no significa necesariamente que deba resolverlos. ¡Deshacerlos también es posible!

Vale la pena repetir esto: siempre tiene la opción de deshacer un conflicto de fusión y volver al estado anterior. Esto es cierto incluso cuando ya ha comenzado a resolver los archivos en conflicto y se encuentra en un callejón sin salida.

En estas situaciones, es bueno tener en cuenta que siempre puede comenzar de nuevo y volver a un estado limpio antes de que ocurriera el conflicto.

Para este propósito, la mayoría de los comandos vienen con una --abortopción, por ejemplo git merge --aborty git rebase --abort:

$ git merge --abort $ git status On branch main nothing to commit, working tree clean

Esto debería darte la confianza de que realmente no puedes equivocarte. Siempre puede abortar, volver a un estado limpio y empezar de nuevo.

Cómo se ven realmente los conflictos en Git

Ahora, sabiendo que nada se puede romper, veamos cómo se ve realmente un conflicto bajo el capó. Esto desmitificará a esos pequeños cabrones y, al mismo tiempo, te ayudará a perder el respeto por ellos y a ganar confianza en ti mismo.

Como ejemplo, veamos el contenido del archivo "index.html" (actualmente en conflicto) en un editor:

Git was kind enough to mark the problem area in the file, enclosing it in <<<<<<< HEAD and >>>>>>> [other/branch/name]. The content that comes after the first marker originates from our current working branch. Finally, a line with ======= characters separates the two conflicting changes.

How to Solve a Conflict in Git

Our job as developers now is to clean up these lines: after we're finished, the file has to look exactly as we want it to look.

It might be necessary to talk to the teammate who wrote the "other" changes and decide which code is actually correct. Maybe it's ours, maybe it's theirs - or maybe a mixture between the two.

This process - cleaning up the file and making sure it contains what we actually want - doesn't have to involve any magic. You can do this simply by opening your text editor or IDE and starting to making your changes.

Often, however, you'll find that this is not the most efficient way. That's when dedicated tools can save time and effort:

  • Git GUI Tools: Some of the graphical user interfaces for Git can be helpful when solving conflicts. The Tower Git GUI, for example, offers a dedicated "Conflict Wizard" that helps visualize and solve the situation:
  • Dedicated Merge Tools: For more complicated conflicts, it can be great to have a dedicated "Diff & Merge Tool" at hand. You can configure your tool of choice using the "git config" command. (Consult your tool's documentation for detailed instructions.) Then, in case of a conflict, you can invoke it by simply typing git mergetool. As an example, here's a screenshot of "Kaleidoscope" on macOS:

After cleaning up the file - either manually or in a Git GUI or Merge Tool - we have to commit this like any other change:

  • By using git add on the (previously) conflicted file, we inform Git that the conflict has been solved.
  • When all conflicts have been solved and added to the Staging Area, you need to complete the resolution by creating a regular commit.

How to Become More Confident and Productive

Many years ago, when I started using version control, merge conflicts regularly freaked me out: I was afraid that, finally, I had managed to break things for good. ?

Only when I took the time to truly understand what was going on under the hood was I able to deal with conflicts confidently and efficiently.

The same was true, for example, when dealing with mistakes: only once I learned how to undo mistakes with Git was I able to become more confident and productive in my work.

I highly recommend taking a look at the free "First Aid Kit for Git", a collection of short videos about how to undo and recover from mistakes with Git.

Have fun becoming a better programmer!

About the Author

Tobias Günther is the CEO of Tower, the popular Git desktop client that helps more than 100,000 developers around the world to be more productive with Git.