modulo 03 / lezione 12
Branch e merge
git merge: fast-forward vs three-way
Capire la differenza tra fast-forward, merge commit e squash merge per scegliere consapevolmente.
git merge: fast-forward vs three-way
Fare merge significa integrare la storia di un branch in un altro. Ma non tutti i merge lasciano la stessa traccia. A volte Git può spostare solo un puntatore. A volte deve creare un commit con due genitori. A volte il team sceglie di schiacciare tutto in un commit.
La scelta influenza la leggibilità della storia.
Perché questa lezione conta
Molti team litigano su merge commit, squash e rebase come se ci fosse una risposta universale. In realtà ogni scelta ottimizza qualcosa: granularità, linearità, auditabilità, semplicità del log, facilità di revert.
Capire i tre casi ti permette di scegliere una policy invece di subire il default della piattaforma.
Obiettivo operativo
Alla fine della lezione devi saper riconoscere fast-forward, three-way merge e squash merge nel grafo, e spiegare quando usare ciascuno.
Fast-forward
Succede quando il branch corrente è antenato diretto del branch da integrare.
main: A -- B
feat: C -- D
Se main punta a B e feat prosegue da lì, Git può spostare main a D.
git switch main
git merge feat
Risultato:
A -- B -- C -- D main
Nessun commit di merge. Storia lineare.
Three-way merge
Succede quando i branch sono divergenti:
C -- D feat
/
A -- B -- E main
Git usa tre punti: base comune B, punta di main E, punta di feat D. Se riesce, crea un merge commit:
C -- D
/ \
A -- B -- E -- M main
M ha due genitori. Conserva l’informazione che feat è stato integrato come unità.
Forzare o impedire fast-forward
Per forzare merge commit anche se fast-forward sarebbe possibile:
git merge --no-ff feat
Per accettare solo fast-forward e fallire altrimenti:
git merge --ff-only feat
--ff-only è utile su main quando vuoi evitare merge accidentali durante pull.
Squash merge
git merge --squash feat
git commit -m "feat: aggiungi login"
Git prende il risultato finale del branch e lo staged come una singola modifica. La storia dei commit intermedi del branch non entra in main.
Vantaggi:
mainresta pulito;- commit rumorosi spariscono;
- revert della feature è più semplice.
Svantaggi:
- perdi granularità;
- perdi collegamento naturale tra commit intermedi;
- bisect può diventare meno preciso.
Criteri di scelta
Fast-forward. Buono per branch locali, piccoli, già lineari.
Merge commit. Buono quando vuoi preservare il contesto della PR o feature.
Squash. Buono quando il branch contiene molti WIP o commit non significativi.
Rebase + fast-forward. Buono quando vuoi storia lineare mantenendo commit logici.
La regola deve essere di team, non scelta casuale per ogni PR.
Laboratorio guidato
Crea tre scenari demo:
- branch senza divergenza e merge fast-forward;
- branch divergente e three-way merge;
- branch con tre commit WIP e squash merge.
Dopo ogni scenario esegui:
git log --graph --oneline --decorate --all
Confronta il grafo e scrivi cosa perdi o guadagni.
Output atteso
Una policy breve:
Branch piccoli e lineari: rebase + ff-only.
PR con storia utile: merge commit.
PR rumorose: squash merge.
main accetta solo integrazioni via PR.
Adattala al tuo team, ma rendila esplicita.
Errori comuni
Squashare commit importanti. Se i commit raccontano migrazioni separate, perderli peggiora la storia.
Usare merge commit per ogni micro-branch. Il grafo diventa rumoroso.
Non sapere cosa fa la piattaforma. GitHub/GitLab possono avere bottoni con comportamenti diversi.
Confondere merge e rebase. Merge integra storie; rebase riscrive commit su altra base.
Checklist di verifica
- so disegnare fast-forward e three-way merge;
- so usare
--ff-only,--no-ffe--squash; - so leggere un merge commit con due genitori;
- so spiegare trade-off tra squash e merge commit;
- il team ha una policy di merge scritta.
Collegamenti
- Modulo: Branch e merge — lezione 12 del corso.
- I conflitti della prossima lezione possono apparire sia in merge sia in rebase.