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.

60 min Git e controllo versione

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:

  1. main resta pulito;
  2. commit rumorosi spariscono;
  3. revert della feature è più semplice.

Svantaggi:

  1. perdi granularità;
  2. perdi collegamento naturale tra commit intermedi;
  3. 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:

  1. branch senza divergenza e merge fast-forward;
  2. branch divergente e three-way merge;
  3. 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-ff e --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.