Come capire e risolvere i conflitti in Git

Eccola, la parola che ogni sviluppatore odia vedere: conflitto. 😱 Non c'è modo di aggirare l'occasionale conflitto di unione quando si lavora con Git (o altri sistemi di controllo della versione).

Ma quando parlo con gli sviluppatori, sento spesso che c'è un senso di ansia o disagio intorno all'argomento dei conflitti di fusione.

La gestione dei conflitti rimane spesso un luogo oscuro e misterioso: una situazione in cui le cose sono gravemente rotte e non è chiaro come uscirne (senza peggiorare le cose).

Sebbene sia vero che i conflitti di fusione sono una parte inevitabile della vita di uno sviluppatore, il disagio in queste situazioni è del tutto facoltativo.

La mia intenzione con questo articolo è di portare un po 'di chiarezza su questo argomento: come e quando si verificano in genere i conflitti, cosa sono effettivamente e come risolverli o annullarli.

Quando comprendi correttamente queste cose, sarai in grado di affrontare i conflitti di fusione in un modo molto più rilassato e sicuro. 😍

Come e quando si verificano i conflitti

Il nome lo dice già: "conflitti di unione" possono verificarsi nel processo di integrazione dei commit da una fonte diversa.

Tieni presente, tuttavia, che "integrazione" non si limita solo a "unire rami". Può anche accadere durante il rebasing o il rebasing interattivo, quando si esegue un cherry-pick o un pull, o anche quando si riapplica uno Stash.

Tutte queste azioni eseguono una sorta di integrazione, ed è allora che possono verificarsi conflitti di unione.

Ma ovviamente, queste azioni non si traducono in un conflitto di unione ogni volta (grazie a Dio!). Idealmente, dovresti trovarti in queste situazioni solo raramente. Ma quando si verificano esattamente i conflitti?

In realtà, le capacità di fusione di Git sono uno dei suoi maggiori vantaggi: l'unione di rami funziona senza sforzo per la maggior parte del tempo, perché Git di solito è in grado di capire le cose da solo.

Ma ci sono situazioni in cui sono stati apportati cambiamenti contraddittori e in cui la tecnologia semplicemente non può decidere cosa sia giusto o sbagliato. Queste situazioni richiedono semplicemente una decisione da parte di un essere umano.

Il vero classico è quando la stessa identica riga di codice è stata modificata in due commit, su due rami diversi. Git non ha modo di sapere quale modifica preferisci! 🤔

Ci sono altre situazioni simili, ad esempio quando un file è stato modificato in un ramo ed eliminato in un altro, ma sono un po 'meno comuni.

La GUI desktop Git "Tower" , ad esempio, ha un bel modo di visualizzare questo tipo di situazioni:

Come sapere quando si è verificato un conflitto

Non preoccuparti: Git ti dirà molto chiaramente quando si è verificato un conflitto. 😉  

Innanzitutto, ti informerà immediatamente della situazione , ad esempio quando un'unione o un rebase fallisce a causa di un conflitto:

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

Come puoi vedere dall'esempio sopra, quando ho provato a eseguire un'unione, ho creato un conflitto di unione e Git comunica il problema in modo molto chiaro e tempestivo:

  • Si è verificato un conflitto nel file "index.html".
  • Si è verificato un altro conflitto nel file "error.html".
  • Infine, a causa dei conflitti, l'operazione di unione non è riuscita.

Queste sono le situazioni in cui dobbiamo scavare nel codice e vedere cosa deve essere fatto.

Nell'improbabile caso in cui tu abbia trascurato questi messaggi di avviso quando si è verificato il conflitto, Git ti informa inoltre ogni volta che esegui 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

In altre parole: non preoccuparti di non notare i conflitti di unione. Git si assicura che tu non possa trascurarli.

Come annullare un conflitto in Git e ricominciare da capo

I conflitti di fusione arrivano con una certa aria di urgenza. E giustamente: dovrai affrontarli prima di poter continuare il tuo lavoro.

Ma anche se ignorarli non è un'opzione, "gestire i conflitti di unione" non significa necessariamente che devi risolverli. È anche possibile annullarli !

Potrebbe valere la pena ripeterlo: hai sempre la possibilità di annullare un conflitto di unione e tornare allo stato precedente. Questo è vero anche quando hai già iniziato a risolvere i file in conflitto e ti trovi in ​​un vicolo cieco.

In queste situazioni, è bello tenere a mente che puoi sempre ricominciare da capo e tornare a uno stato pulito prima ancora che si verifichi il conflitto.

A tale scopo, la maggior parte dei comandi viene fornita con --abortun'opzione, ad esempio git merge --aborte git rebase --abort:

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

Questo dovrebbe darti la sicurezza di non poter davvero sbagliare. Puoi sempre abortire, tornare a uno stato pulito e ricominciare da capo.

Che aspetto hanno realmente i conflitti in Git

Ora, con la certezza che nulla può rompersi, vediamo come appare davvero un conflitto sotto il cofano. Questo demistificherà quei piccoli bastardi e, allo stesso tempo, ti aiuterà a perdere il rispetto per loro e ad acquisire fiducia in te stesso.

Ad esempio, esaminiamo il contenuto del file "index.html" (attualmente in conflitto) in un editor:

Git è stato così gentile da contrassegnare l'area problematica nel file, racchiudendola tra <<<<<<< HEADe >>>>>>> [other/branch/name]. Il contenuto che segue il primo marker proviene dal nostro ramo di lavoro corrente. Infine, una riga con =======caratteri separa le due modifiche in conflitto.

Come risolvere un conflitto in Git

Il nostro lavoro come sviluppatori ora è ripulire queste righe: dopo aver finito, il file deve apparire esattamente come vogliamo che appaia.

Potrebbe essere necessario parlare con il compagno di squadra che ha scritto le "altre" modifiche e decidere quale codice è effettivamente corretto. Forse è nostro, forse è loro - o forse un misto tra i due.

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.