Conflicten in Git begrijpen en oplossen

Daar is het, het woord dat elke ontwikkelaar haat om te zien: conflict. ? Er is gewoon geen manier om het incidentele samenvoegconflict te omzeilen bij het werken met Git (of andere versiebeheersystemen).

Maar als ik met ontwikkelaars spreek, hoor ik vaak dat er een gevoel van angst of ongemak heerst rond het onderwerp samenvoegconflicten.

Het omgaan met conflicten blijft vaak een duistere, mysterieuze plek: een situatie waarin de zaken ernstig kapot zijn en het onduidelijk is hoe je eruit komt (zonder de zaken erger te maken).

Hoewel het waar is dat samenvoegconflicten een onvermijdelijk onderdeel zijn van het leven van een ontwikkelaar, is het ongemak in deze situaties volledig optioneel.

Mijn bedoeling met dit artikel is om wat duidelijkheid te scheppen in dit onderwerp: hoe en wanneer conflicten zich doorgaans voordoen, wat ze werkelijk zijn, en hoe ze kunnen worden opgelost of ongedaan gemaakt.

Als u deze dingen goed begrijpt, kunt u op een veel meer ontspannen en zelfverzekerde manier omgaan met samenvoegconflicten. ?

Hoe en wanneer conflicten optreden

De naam zegt het al: "merge conflicten" kunnen optreden tijdens het integreren van commits van een andere bron.

Houd er echter rekening mee dat "integratie" niet beperkt is tot alleen "samenvoegen van branches". Het kan ook gebeuren bij rebasen of interactief rebasen, bij het uitvoeren van een cherry-pick of een pull, of zelfs bij het opnieuw toepassen van een stash.

Al deze acties voeren een soort van integratie uit - en dat is wanneer samenvoegingsconflicten kunnen optreden.

Maar deze acties resulteren natuurlijk niet elke keer in een samenvoegconflict (godzijdank!). Idealiter zou u zich slechts zelden in deze situaties bevinden. Maar wanneer doen zich precies conflicten voor?

Eigenlijk zijn de merging-mogelijkheden van Git een van de grootste voordelen: het samenvoegen van branches werkt meestal moeiteloos, omdat Git meestal in staat is om dingen zelf uit te zoeken.

Maar er zijn situaties waarin tegenstrijdige wijzigingen zijn aangebracht - en waarin technologie eenvoudigweg niet kan beslissen wat goed of fout is. Deze situaties vereisen eenvoudigweg een beslissing van een mens.

De echte klassieker is wanneer exact dezelfde regel code werd gewijzigd in twee commits, op twee verschillende branches. Git kan niet weten welke wijziging u verkiest! ?

Er zijn een aantal andere, vergelijkbare situaties - bijvoorbeeld wanneer een bestand werd gewijzigd in de ene branch en verwijderd in een andere - maar ze komen iets minder vaak voor.

De "Tower" Git desktop GUI heeft bijvoorbeeld een leuke manier om dit soort situaties te visualiseren:

Hoe te weten wanneer er een conflict is opgetreden

Maak je geen zorgen: Git zal je heel duidelijk vertellen wanneer er een conflict is gebeurd. ?  

Ten eerste laat het u onmiddellijk weten in de situatie , bijvoorbeeld wanneer een samenvoeging of rebase mislukt vanwege een conflict:

$ 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.

Zoals je kunt zien aan de hand van het bovenstaande voorbeeld, creëerde ik, toen ik probeerde een merge uit te voeren, een merge-conflict - en Git communiceert het probleem heel duidelijk en onmiddellijk:

  • Er is een conflict opgetreden in het bestand "index.html".
  • Er is een ander conflict opgetreden in het bestand "error.html".
  • En tot slot is de samenvoegbewerking mislukt vanwege de conflicten.

Dit zijn de situaties waarin we in de code moeten graven en kijken wat er moet gebeuren.

In het onwaarschijnlijke geval dat je deze waarschuwingsberichten over het hoofd hebt gezien toen het conflict zich voordeed, informeert Git je bovendien wanneer je draait 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

Met andere woorden: maak u geen zorgen over het niet opmerken van samenvoegconflicten. Git zorgt ervoor dat je ze niet over het hoofd kunt zien.

Een conflict in Git ongedaan maken en opnieuw beginnen

Samenvoegconflicten hebben een zekere urgentie. En terecht: je krijgt ermee te maken voordat je verder kunt met je werk.

Maar hoewel het negeren ervan geen optie is, betekent "omgaan met samenvoegconflicten" niet noodzakelijk dat u ze moet oplossen. Ongedaan maken is ook mogelijk!

Dit is misschien voor herhaling vatbaar: je hebt altijd de mogelijkheid om een ​​samenvoegconflict ongedaan te maken en terug te keren naar de vorige staat. Dit geldt zelfs als u al bent begonnen met het oplossen van de conflicterende bestanden en u zich op een doodlopende weg bevindt.

In deze situaties is het goed om in gedachten te houden dat u altijd opnieuw kunt beginnen en naar een schone staat kunt terugkeren voordat het conflict zich heeft voorgedaan.

Voor dit doel hebben de meeste opdrachten een --abortoptie, bijvoorbeeld git merge --aborten git rebase --abort:

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

Dit zou je het vertrouwen moeten geven dat je echt niet kunt verknoeien. U kunt altijd afbreken, terugkeren naar een schone staat en opnieuw beginnen.

Hoe conflicten er echt uitzien in Git

Nu, veilig in de wetenschap dat niets kan breken, laten we eens kijken hoe een conflict er echt uitziet onder de motorkap. Dit zal die kleine buggers demystificeren en tegelijkertijd helpen om het respect voor hen te verliezen en vertrouwen in jezelf te krijgen.

Laten we als voorbeeld eens kijken naar de inhoud van het (momenteel conflicterende) "index.html" -bestand in een 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.