Skip to content

13. Risolvere i conflitti di merge

13.1 Quando e perché si verifica un conflitto

Section titled “13.1 Quando e perché si verifica un conflitto”

Un conflitto sorge quando si sta integrando una history in cui due versioni hanno modificato le stesse righe. Può accadere:

  • all’avvio del merge: ci sono modifiche pendenti in working copy o staging; va “pulito” lo spazio di lavoro (con stash, commit, checkout o reset);
  • durante il merge: il conflitto è reale tra i commit del branch corrente (current) e quelli del branch in ingresso (incoming).
Terminal window
mkdir git-merge-test && cd git-merge-test && git init .
echo "initial content to edit later" > merge.txt
git add merge.txt
git commit -m "initial content"
# branch con una modifica alla stessa riga
git checkout -b merge-me
echo "new content to merge later" > merge.txt
git commit -am "edited the content for conflict"
# nel frattempo, su main, un'altra modifica allo stesso punto
git checkout main
echo "content added to previous" >> merge.txt
git commit -am "appended content to merge.txt"
# merge
git merge merge-me
# Auto-merging merge.txt
# CONFLICT (content): Merge conflict in merge.txt
# Automatic merge failed; fix conflicts and then commit the result.

Il file in conflitto contiene i marker di Git:

<<<<<<< HEAD
initial content to edit later
content added to previous
=======
new content to merge later
>>>>>>> merge-me
  • tra <<<<<<< e =======: la versione del branch current (HEAD);
  • tra ======= e >>>>>>>: la versione del branch incoming.

git status elenca i file non risolti e suggerisce i comandi.

  1. Accettare la versione corrente: git checkout --ours merge.txt
  2. Accettare la versione in arrivo: git checkout --theirs merge.txt
  3. Integrare a mano: si modifica il file fino a un contenuto corretto, poi:
Terminal window
git add merge.txt # dichiara il conflitto risolto
git commit # conclude il merge

Al termine, la history mostra il merge commit e i due genitori intatti:

Terminal window
$ git log --pretty=format:'%h %s (%an)' --date=short --graph
* c9802c8 merged content due conflict (Me)
|\
| * 15416df edited the content for conflict (Me)
* | 90640eb appended content to merge.txt (Frank)
|/
* 0a99708 initial content (Someone)

Per annullare tutto: git merge --abort.

Stile diff3 — aggiunge ai marker anche il contenuto del genitore comune:

Terminal window
git config merge.conflictstyle diff3
<<<<<<< HEAD
initial content to edit later
content added to previous
||||||| 0a99708
initial content to edit later
=======
new content to merge later
>>>>>>> merge-me

git log --merge — mostra i commit in conflitto sui due branch, con -p anche i diff:

Terminal window
git log --merge -p merge.txt

Anche gli editor offrono supporto visivo: VSCode, ad esempio, riconosce i marker di conflitto e propone azioni rapide (Accept Current / Accept Incoming / Accept Both), oltre a una vista a confronto.

⚠️ Attenzione alla terminologia: Git usa ours/theirs, le UI spesso current/incoming — che è più esplicita sul “verso” del merge. Nel merge di un feature branch su main, per Git ours sono anche i commit altrui già presenti su main, e theirs i propri commit del branch: non sempre “ours” significa “il mio lavoro”!

Dopo la risoluzione va verificato che il codice funzioni ancora; e se la situazione è ambigua, valutare di interrompere il merge e confrontarsi con i colleghi.