Git 10
🔀 Git & GitHub · Modulo 2 · Lezione 10
Gestire i conflitti di merge ⚔️
Come nascono · Come si presentano · Marker <<< === >>> · Risoluzione passo per passo · Esercitazione pratica
⚔️ I conflitti di merge sono la cosa che spaventa di più i principianti. Ma una volta capito il meccanismo, diventano routine — un piccolo inconveniente che si risolve in pochi minuti. Un conflitto non è un errore: è Git che ti dice “ho trovato due modifiche sulla stessa riga e non so quale tenere — decidi tu”. In questa lezione impari a riconoscere, leggere e risolvere i conflitti con sicurezza.
🎯 Obiettivi della lezione
- Capire quando e perché nasce un conflitto di merge
- Riconoscere lo stato “merge in corso” nel terminale
- Leggere i marker di conflitto nel file (
<<<,===,>>>) - Risolvere un conflitto manualmente: scegliere, combinare, pulire
- Completare il merge dopo la risoluzione
- Annullare un merge in corso con
git merge --abort - Usare VS Code per risolvere i conflitti visualmente
📖 1. Teoria
1.1 — Quando nasce un conflitto
Nella Lezione 09 hai visto che Git è bravissimo a combinare automaticamente le modifiche di due branch. Ma c’è un caso in cui non può farcela da solo: quando due branch hanno modificato la stessa riga dello stesso file in modo diverso.
style.cssFeature modifica la riga 20 di
style.cssGit combina automaticamente: righe diverse dello stesso file, nessun problema.
color: blue;Feature modifica la riga 5:
color: red;Git non può scegliere — entrambe le versioni sono valide. Chiede a te di decidere.
| Situazione | Cosa fa Git | Conflitto? |
|---|---|---|
| Un file è stato modificato solo su un branch | Prende la versione modificata | No |
| Un file è stato modificato su entrambi, ma in righe diverse | Combina automaticamente le modifiche | No |
| Un file nuovo è stato creato solo su un branch | Aggiunge il file | No |
| Un file è stato modificato su entrambi, nelle stesse righe | Si ferma e chiede aiuto a te | ⚔️ Sì |
📌 I conflitti sono rari nella pratica. Se ogni persona lavora su file o sezioni diverse, i merge vanno lisci automaticamente. I conflitti nascono quando due persone toccano lo stesso punto dello stesso file — cosa che succede soprattutto con file centrali come index.html o style.css che tutti modificano. La prevenzione migliore è comunicare con il team: “sto lavorando su style.css — voi non toccatelo per adesso”.
1.2 — Cosa succede quando Git trova un conflitto
Quando fai git merge e Git trova un conflitto, succedono tre cose:
Auto-merging style.css
CONFLICT (content): Merge conflict in style.css
Automatic merge failed; fix conflicts and then commit the result.
(main|MERGING).<<<<<<<, =======, >>>>>>>) che mostrano le due versioni in competizione.git add e poi git commit per completare il merge.studente@pc ~/progetto (main|MERGING)$
# git status mostra i file in conflitto
$ 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 <file>…” to mark resolution)
both modified: style.css
1.3 — I marker di conflitto: anatomia
Quando apri un file con un conflitto, trovi dei marker che separano le due versioni. Ecco come si presentano:
margin: 0;
<<<<<<< HEAD
color: blue;
font-size: 16px;
=======
color: red;
font-weight: bold;
>>>>>>> feature/stili
}
| Marker | Significato |
|---|---|
| <<<<<<< HEAD | Inizio del conflitto. Qui sotto c’è la versione del branch corrente (HEAD = main, il branch su cui sei). |
| (righe in mezzo — sezione HEAD) | Il codice come lo ha scritto il branch corrente (main). |
| ======= | Separatore. Divide la versione di HEAD dalla versione dell’altro branch. |
| (righe in mezzo — sezione feature) | Il codice come lo ha scritto il branch in arrivo (feature/stili). |
| >>>>>>> feature/stili | Fine del conflitto. Dopo questa riga il file torna normale. |
📌 Con merge.conflictstyle diff3 (configurato nella Lezione 02) vedrai anche una terza sezione ||||||| base che mostra la versione originale (prima delle modifiche di entrambi i branch). Questo aiuta enormemente a capire cosa è cambiato. Se non l’hai configurato: git config --global merge.conflictstyle diff3.
1.4 — Come risolvere un conflitto: procedura
Identifica
git status per vedere quali file hanno conflitti (appaiono come both modified).Apri
<<<<<<<. Ogni blocco di marker è un conflitto da risolvere.Decidi
Pulisci
<<<, ===, >>>). Il file deve contenere solo codice valido — nessun marker deve restare.Completa
git add file per marcarlo come risolto, poi git commit per completare il merge.1.5 — Le 4 scelte possibili per ogni conflitto
Per ogni blocco di conflitto, hai 4 opzioni. Ecco come si presenta il file dopo la tua scelta (tutti i marker rimossi):
margin: 0;
color: blue;
font-size: 16px;
}
margin: 0;
color: red;
font-weight: bold;
}
margin: 0;
color: blue;
font-size: 16px;
font-weight: bold;
}
margin: 0;
color: navy;
font-size: 18px;
font-weight: 600;
}
1.6 — Completare o annullare il merge
$ git add style.css
$ git commit
git add marca il file come “risolto”. git commit (senza -m) apre l’editor con un messaggio di merge predefinito. Salva e chiudi per completare.
--abort annulla tutto e riporta il repository allo stato precedente al merge. Nessuna modifica viene persa — è come se il merge non fosse mai iniziato.
⚠️ Errore critico: lasciare i marker nel file. Se fai git add e git commit senza aver rimosso i marker <<<<<<<, Git non protesta — committa il file così com’è, marker inclusi. Il risultato è codice rotto con caratteri strani nel mezzo. Sempre verifica che i marker siano stati rimossi prima di completare il merge.
1.7 — VS Code: risoluzione visuale
VS Code riconosce automaticamente i conflitti e li evidenzia con colori e pulsanti cliccabili:
📌 I pulsanti di VS Code sono comodi ma non pensano per te. “Accept Both” ad esempio mette le due versioni una dopo l’altra — che spesso produce codice duplicato o non funzionante. Leggi sempre il risultato dopo aver cliccato un pulsante e verifica che il codice abbia senso.
1.8 — Riepilogo: il flusso completo di un merge con conflitto
CONFLICT!
both modified: file
Scegli / combina
Rimuovi marker
💻 2. Esempi guidati
Esempio A — Creare un conflitto (passo per passo)
$ mkdir lab-conflitto && cd lab-conflitto && git init
$ cat > style.css <<EOF
body {
margin: 0;
color: black;
}
EOF
$ git add . && git commit -m “Setup: CSS base con colore nero”
# === BRANCH FEATURE: cambia colore in rosso ===
$ git switch -c feature/stili
$ sed -i ‘s/color: black/color: red/’ style.css # macOS: sed -i ‘’ ‘s/…’
$ git add . && git commit -m “Cambiato colore in rosso”
# === MAIN: cambia colore in blu (stessa riga!) ===
$ git switch main
$ sed -i ‘s/color: black/color: blue/’ style.css
$ git add . && git commit -m “Cambiato colore in blu”
# === MERGE: conflitto! ===
$ git merge feature/stili
Auto-merging style.css
CONFLICT (content): Merge conflict in style.css
Automatic merge failed; fix conflicts and then commit the result.
Esempio B — Risolvere il conflitto manualmente
$ git status
Unmerged paths:
both modified: style.css
# Passo 2: guarda il file con conflitto
$ cat style.css
body {
margin: 0;
<<<<<<< HEAD
color: blue;
=======
color: red;
>>>>>>> feature/stili
}
# Passo 3: risolviamo — vogliamo “navy” (né blue né red)
$ cat > style.css <
body {
margin: 0;
color: navy;
}
EOF
# Passo 4: marca come risolto e completa il merge
$ git add style.css
$ git commit -m “Merge feature/stili: scelto colore navy come compromesso”
# Verifica
$ git log –oneline –graph
* a1b2c3d (HEAD -> main) Merge feature/stili: scelto colore navy come compromesso
|
| * d4e5f6a (feature/stili) Cambiato colore in rosso
* | b7c8d9e Cambiato colore in blu
|/
* e4f5a6b Setup: CSS base con colore nero
Esempio C — Annullare un merge in corso
# Siamo nello stato (main|MERGING) con un conflitto aperto…
# “Troppo complicato, ci penso dopo”
$ git merge –abort
$ git status
On branch main
nothing to commit, working tree clean
🏋️ 3. Esercizi
🟢 Esercizio 1 — Il tuo primo conflitto (Facile)
titolo.txt con il testo “Titolo: Progetto originale”.b) Sul branch feature, cambia in “Titolo: Progetto Alfa”.
c) Su main, cambia in “Titolo: Progetto Beta”.
d) Fai il merge. Osserva l’errore.
e) Apri il file e leggi i marker. Cosa c’è nella sezione HEAD? E nella sezione feature?
f) Risolvi scegliendo “Titolo: Progetto Alfa-Beta”.
g) Rimuovi i marker, fai
git add e git commit. Verifica con git log --graph.
🔵 Esercizio 2 — Conflitto multiplo (Medio)
index.html di 10 righe (una struttura HTML base).b) Su
feature/header: modifica il <title> (riga ~4) e aggiungi un <header> (riga ~7).c) Su main: modifica lo stesso
<title> con un testo diverso e aggiungi un <nav> nello stesso punto del <header>.d) Fai il merge. Quanti blocchi di conflitto ci sono? (Probabilmente 2)
e) Risolvi entrambi: per il title, scegli il testo di feature. Per header/nav, tieni entrambi (header sopra, nav sotto).
f) Completa il merge e verifica che il file sia valido HTML.
🟠 Esercizio 3 — Abort e riprova (Medio)
b) Quando Git mostra il conflitto, non risolverlo. Esegui
git merge --abort.c) Verifica con
git status che sei tornato a “clean”.d) Il file ha ancora i marker? (No — abort ripristina tutto.)
e) Ora rifai il merge. Questa volta risolvilo scegliendo la versione di HEAD (main).
f) Completa il merge. Verifica il risultato.
🟣 Esercizio 4 — Simulazione lavoro di gruppo (Difficile)
Simula una giornata di lavoro in team dove si verificano conflitti:
index.html, style.css, README.md. Commit iniziale.b) “Marco” su
feature/hero: modifica il <body> di index.html aggiungendo un hero section. Modifica style.css aggiungendo stili per .hero. 2 commit.c) “Giulia” su
feature/intro (partendo da main): modifica lo stesso punto del <body> di index.html aggiungendo un paragrafo introduttivo. Modifica style.css nella stessa zona aggiungendo stili per p. 2 commit.d) Torna su main e fai merge di
feature/hero (nessun conflitto — main non è cambiato).e) Ora fai merge di
feature/intro. Conflitto! Entrambi hanno toccato le stesse zone.f) Risolvi i conflitti: tieni l’hero section E il paragrafo introduttivo, combinandoli nell’ordine corretto. Combina anche gli stili CSS.
g) Completa il merge. Verifica che index.html e style.css siano corretti. Pulisci i branch.
❓ 4. Quiz di verifica
1. Quando nasce un conflitto di merge?
Mostra risposta
Un conflitto nasce quando due branch hanno modificato la stessa riga dello stesso file in modo diverso. Git non può decidere autonomamente quale versione tenere, quindi si ferma e chiede a te di risolvere. Se i due branch hanno modificato file diversi, o righe diverse dello stesso file, Git combina automaticamente le modifiche senza conflitto.
2. Cosa significano i marker <<<<<<< HEAD, ======= e >>>>>>> feature/x?
Mostra risposta
Delimitano le due versioni in competizione. Tra <<<<<<< HEAD e ======= c’è la versione del branch corrente (HEAD, di solito main). Tra ======= e >>>>>>> feature/x c’è la versione del branch che stai integrando. Devi scegliere quale tenere (o combinarle), poi rimuovere tutti i marker. I marker non sono codice — sono solo indicatori messi da Git. Se li lasci nel file, il codice sarà rotto.
3. Dopo aver risolto il conflitto modificando il file, quale sequenza di comandi completa il merge?
Mostra risposta
git add file-risolto seguito da git commit. Il git add dice a Git “ho risolto il conflitto in questo file — la versione attuale è quella corretta”. Il git commit completa il merge creando il merge commit. Se non specifichi -m, Git apre l’editor con un messaggio predefinito (“Merge branch ‘…'”) che puoi personalizzare. Se ci sono più file in conflitto, devi fare git add per ciascuno prima del commit.
4. Il merge è troppo complicato e vuoi annullarlo. Come fai?
Mostra risposta
git merge --abort. Questo annulla il merge in corso e riporta il repository allo stato precedente — come se non avessi mai eseguito git merge. I file tornano alla versione di main prima del merge, senza marker di conflitto. Puoi usare --abort in qualsiasi momento durante la risoluzione dei conflitti, anche se hai già modificato alcuni file. Tutto viene ripristinato. Puoi poi riprovare il merge quando sei pronto.
5. Cosa succede se fai git commit senza rimuovere i marker <<< dal file?
Mostra risposta
Git committa il file così com’è, marker inclusi. Git non verifica che i marker siano stati rimossi — si fida di te. Il risultato è un file con caratteri come <<<<<<< e ======= nel mezzo del codice, che quasi certamente romperà l’applicazione. Ecco perché è importante sempre verificare il contenuto del file dopo aver risolto un conflitto, e prima di fare git add e git commit.
6. In VS Code, cosa fa il pulsante “Accept Both Changes”?
Mostra risposta
Mette entrambe le versioni nel file, una dopo l’altra: prima la versione di HEAD, poi quella del branch in arrivo. I marker vengono rimossi automaticamente. Attenzione: il risultato potrebbe non avere senso — ad esempio se entrambe le versioni definiscono la stessa proprietà CSS, avrai una proprietà duplicata. Dopo aver cliccato “Accept Both”, verifica sempre che il codice risultante sia logicamente corretto. Se non lo è, modifica manualmente il risultato.
📚 Riepilogo della lezione
- Un conflitto nasce quando due branch modificano la stessa riga dello stesso file
- Git si ferma in stato
(main|MERGING)e segna i conflitti con marker nel file - Marker:
<<<<<<< HEAD(tua versione) ·=======(separatore) ·>>>>>>> feature(versione dell’altro) - 4 scelte: tieni HEAD · tieni feature · tieni entrambi · riscrivi
- Procedura: status → apri → scegli → rimuovi marker → add → commit
git merge --abort— annulla tutto e torna allo stato precedente- Mai lasciare i marker nel file — Git non li controlla, committa tutto
- VS Code evidenzia i conflitti con colori e pulsanti — comodo ma verifica sempre il risultato
Prossima lezione →
Lezione 11 — Rebase
Differenza concettuale merge vs rebase. git rebase interattivo.
La regola d’oro: mai rebase su branch pubblici.
Corso Git & GitHub · Per studenti e insegnanti · Lezione 10 di 45