Come risolvere i conflitti in Git senza panico
Cosa sono i conflitti Git, come si leggono i marcatori nel file, la procedura per risolverli passo passo e come ridurne drasticamente la frequenza.
Il primo conflitto in Git è un momento di panico piuttosto universale: il comando fallisce, il file si riempie di simboli strani, e la sensazione è di aver rotto qualcosa di irreparabile. Non è così — un conflitto è semplicemente Git che ti chiede di decidere una cosa che non può decidere lui. In questo articolo trovi come leggerli, come risolverli e come averne molti di meno.
Cos'è un conflitto
Un conflitto si verifica quando due modifiche toccano le stesse righe dello stesso file e Git non può stabilire quale delle due debba prevalere.
Il punto importante: Git risolve da solo la stragrande maggioranza delle unioni. Se tu hai modificato la riga 10 e un collega la riga 200, le combina senza chiederti nulla. Il conflitto arriva solo quando le modifiche si sovrappongono davvero.
E non è un errore. È Git che si rifiuta di indovinare, il che è esattamente il comportamento corretto: nessuno vuole che un sistema decida arbitrariamente quale versione del codice tenere.
Come si presenta
Quando succede, Git modifica il file inserendo dei marcatori:
<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> funzione-login
Si legge così:
- Tra
<<<<<<< HEADe=======→ la versione del ramo su cui ti trovi - Tra
=======e>>>>>>>→ la versione del ramo che stai unendo - Dopo
>>>>>>>→ il nome del ramo di provenienza
Il file in questo stato non è codice valido. Se provi a eseguirlo, fallisce — ed è voluto: serve a impedire che il conflitto passi inosservato.
Come si risolve
La procedura, passo per passo.
1. Guarda la situazione.
git status
Ti elenca i file in conflitto sotto "Unmerged paths".
2. Apri ogni file e decidi. Le opzioni sono quattro:
- Tenere la tua versione
- Tenere la loro
- Combinarle
- Scrivere qualcosa di diverso da entrambe
3. Rimuovi tutti i marcatori. <<<<<<<, =======, >>>>>>> devono sparire. Il file deve restare codice valido e leggibile.
4. Verifica che funzioni. Esegui il codice, lancia i test. È il passaggio che si salta più spesso, ed è quello che conta.
5. Segna come risolto e concludi.
git add file-risolto.js
git commit
Se ti accorgi di aver combinato un pasticcio, puoi sempre annullare tutto e ricominciare:
git merge --abort
Torni allo stato precedente come se non avessi mai iniziato. È la via di fuga da ricordare: nessun conflitto è irreversibile.
Gli strumenti che aiutano
Risolvere i conflitti leggendo i marcatori a mano funziona, ma esistono modi più comodi.
L'editor di codice. VS Code e gli altri editor moderni mostrano il conflitto con un'interfaccia dedicata: pulsanti per accettare l'una, l'altra o entrambe le versioni, e una vista affiancata. Per la maggior parte dei conflitti è il modo più veloce.
Vista a tre pannelli. Gli strumenti dedicati mostrano tre colonne: la tua versione, la loro, e l'antenato comune da cui entrambe derivano. Vedere l'originale è spesso ciò che chiarisce la situazione, perché ti dice cosa ciascuno stava cercando di cambiare.
Attenzione ai pulsanti "accetta tutto". Sono comodi e pericolosi: accettare in blocco una versione senza guardare significa cancellare il lavoro di qualcuno. Va bene solo se hai verificato che quelle modifiche siano davvero da scartare.
Come averne di meno
Qui sta la parte utile: i conflitti si prevengono più facilmente di quanto si risolvano.
Sincronizzati spesso. È la regola numero uno. Un ramo tenuto separato per tre settimane accumula divergenze; uno aggiornato ogni giorno ne accumula poche. La frequenza dei conflitti cresce molto più che proporzionalmente con il tempo di separazione.
Rami di vita breve. Una funzionalità che richiede un mese va spezzata in pezzi integrabili. È anche il motivo per cui molti team preferiscono rami che durano ore o giorni, non settimane.
Commit piccoli e mirati. Un commit che tocca venti file ha più probabilità di scontrarsi di uno che ne tocca due.
Dividetevi il lavoro per area. Due persone sullo stesso file nello stesso giorno è la ricetta del conflitto. È organizzazione, non tecnica.
Concordate la formattazione. Una parte consistente dei conflitti non riguarda la logica ma l'indentazione, le virgolette, i punti e virgola. Un formattatore automatico condiviso elimina un'intera categoria di conflitti — è uno degli interventi con il ritorno più alto per un team.
Comunicate. "Sto rifacendo il modulo pagamenti" detto in chat vale più di qualunque strumento. Vale anche il contrario: proposte di modifica piccole e frequenti riducono i conflitti, come spiego in cos'è una pull request.
Il caso peggiore: i file binari
Su immagini, PDF, documenti di grafica, Git non può combinare nulla: può solo tenere l'uno o l'altro.
git checkout --ours immagine.png # la tua
git checkout --theirs immagine.png # la loro
Non c'è via di mezzo. Su questi file l'unica prevenzione è organizzativa: non lavorateci in due contemporaneamente.
Un caso particolare: i conflitti durante un rebase
Se stai facendo un rebase invece di un merge, i comandi cambiano leggermente:
git rebase --continue # dopo aver risolto
git rebase --abort # per annullare tutto
E c'è una differenza pratica da conoscere: durante un rebase i conflitti si possono ripresentare a ogni commit, perché ciascuno viene riapplicato singolarmente. Su un ramo lungo può diventare laborioso — è uno dei motivi per cui il merge resta l'opzione più tranquilla, come spiego in merge vs rebase.
Una funzione che aiuta
Vale la pena conoscerla:
git config --global rerere.enabled true
Attiva una funzione che ricorda come hai risolto un certo conflitto e riapplica automaticamente la stessa soluzione se si ripresenta identico. Utile soprattutto su rami lunghi che vengono aggiornati più volte.
In sintesi
Un conflitto non è un errore: è Git che ti chiede di decidere quando due modifiche toccano le stesse righe. La grande maggioranza delle unioni avviene senza il tuo intervento.
I marcatori nel file separano la tua versione (sopra) da quella in arrivo (sotto). Si risolve scegliendo, rimuovendo i marcatori, verificando che il codice funzioni e concludendo con git add e git commit.
Due cose da ricordare sempre: git merge --abort annulla tutto e ti riporta al punto di partenza, e git status ti dice sempre dove sei.
Ma la parte più utile è la prevenzione: sincronizzarsi spesso, rami brevi, commit piccoli e un formattatore condiviso eliminano gran parte dei conflitti prima che si presentino.
Se i comandi non ti sono ancora familiari, il quadro è in comandi Git essenziali.