È uscito il Corso Java Completo
Torna al blog

Git merge vs rebase: differenze e quando usare quale

Merge e rebase a confronto: cosa fanno davvero alla storia del progetto, quando conviene l'uno e quando l'altro, e la regola d'oro da non violare mai.

Edoardo Midali

Edoardo Midali

Developer · Content Creator

6 min di lettura

È una delle poche domande su Git capaci di generare discussioni accese nei team. In realtà non c'è una risposta universale: fanno cose diverse, con conseguenze diverse sulla storia del progetto. Quello che esiste è una regola da non violare mai, e a parte quella è una scelta di stile. In questo articolo ti spiego cosa succede davvero in entrambi i casi.

Il problema che risolvono entrambi

Hai creato un ramo per una funzionalità. Mentre ci lavoravi, il ramo principale è andato avanti: altri hanno aggiunto commit.

main:     A---B---C---F
                \
funzione:        D---E

Adesso vuoi che il tuo lavoro (D, E) faccia parte del ramo principale. Merge e rebase sono due modi diversi di ottenerlo. Se il concetto di ramo ti è ancora poco chiaro, parti da cos'è il version control.

Cosa fa il merge

Il merge crea un nuovo commit che unisce le due linee di sviluppo, conservandole entrambe.

main:     A---B---C---F---M
                \       /
funzione:        D---E-/

Il commit M ha due genitori: è il punto in cui le storie si ricongiungono.

Cosa ottieni: la storia registra esattamente com'è andata. Si vede che è esistito un ramo, quando è nato e quando è stato riunito. Nessun commit viene modificato: D ed E restano identici a come li hai creati.

Il costo: su un progetto con molti rami, il grafico della storia diventa intricato — quello che viene chiamato "a spaghetti".

git switch main
git merge funzione

Cosa fa il rebase

Il rebase riscrive i tuoi commit come se fossero stati fatti a partire dallo stato attuale del ramo principale.

main:     A---B---C---F
                       \
funzione:               D'---E'

Nota gli apici: D' ed E' non sono D ed E. Sono commit nuovi, con lo stesso contenuto ma identificatori diversi, ricostruiti su una base diversa.

Cosa ottieni: una storia lineare, che si legge come una sequenza ordinata di cambiamenti.

Il costo: la storia non racconta più com'è andata davvero. Sembra che tu abbia lavorato a partire da F, cosa che non è vera. E i commit originali non esistono più.

git switch funzione
git rebase main

Il confronto

MergeRebase
StoriaFedele alla realtàLineare e pulita
Commit esistentiIntattiRiscritti
GraficoRamificatoRettilineo
ConflittiSi risolvono una voltaPossibili a ogni commit
Su rami condivisiSicuroPericoloso
Tracciabilità del ramoConservataPersa

Un punto pratico spesso sottovalutato: con il rebase i conflitti si possono ripresentare commit per commit, perché ogni commit viene riapplicato singolarmente. Su un ramo con quindici commit e modifiche sovrapposte, può diventare laborioso.

La regola d'oro

Non fare mai rebase su commit che hai già condiviso con altri.

È l'unica regola non negoziabile dell'articolo, e il motivo è concreto.

Il rebase riscrive i commit dando loro nuovi identificatori. Se un collega ha già scaricato i commit originali e tu li sostituisci, la sua copia e la tua raccontano storie incompatibili. Nel tentativo di riallinearsi, il suo Git ricreerà i vecchi commit accanto ai nuovi — con il risultato di duplicati, confusione e lavoro potenzialmente perso.

La formulazione pratica: il rebase va bene sui tuoi rami locali, prima di condividerli. Mai su main o su un ramo su cui lavora anche qualcun altro.

Se ti accorgi di aver fatto un rebase su un ramo condiviso, la cosa peggiore che puoi fare è forzare l'invio senza avvisare nessuno. Parlane con il team prima.

Quando usare cosa

Usa il rebase quando:

  • Vuoi aggiornare il tuo ramo di lavoro con le novità del principale, prima di proporre le modifiche
  • Vuoi riordinare i tuoi commit locali prima di condividerli
  • Il ramo è solo tuo e non l'hai ancora inviato

Usa il merge quando:

  • Unisci un ramo completato nel principale
  • Il ramo è condiviso
  • Vuoi che resti traccia dell'esistenza del ramo
  • Hai il minimo dubbio: il merge è l'opzione sicura

Il flusso che usano molti team

Nella pratica non si sceglie l'uno o l'altro: si usano entrambi, ciascuno dove ha senso.

  1. Lavori sul tuo ramo
  2. Ogni tanto rebase dal principale, per restare aggiornato — il ramo è tuo, nessun problema
  3. Prima di proporre le modifiche, rebase interattivo per riordinare i commit
  4. Merge del ramo nel principale

Il risultato è una storia leggibile che conserva comunque la traccia dei rami.

Il rebase interattivo

Merita una menzione, perché è la funzione più utile del rebase e la meno conosciuta:

git rebase -i HEAD~5

Ti apre un elenco degli ultimi cinque commit e permette di riordinarli, unirli, riscriverne i messaggi o eliminarli.

L'uso tipico: hai lavorato tutto il giorno producendo commit come "wip", "prova", "fix del fix". Prima di condividere, li unisci in due o tre commit sensati con messaggi decenti.

Vale la stessa regola: solo su commit non ancora condivisi.

Il terzo modo: squash

Molte piattaforme offrono, al momento di integrare le modifiche, l'opzione di comprimere tutti i commit del ramo in uno solo.

Il vantaggio: un commit per funzionalità nel ramo principale, storia pulitissima e facile da annullare.

Il costo: si perde il dettaglio di come ci sei arrivato.

È la scelta più diffusa nei progetti dove il ramo principale deve leggersi come un elenco ordinato di funzionalità.

Cosa conta davvero

Una nota di realismo, perché su questo si spreca parecchia energia nei team.

Merge e rebase producono lo stesso codice. La differenza è solo su come si legge la storia. Nessuna delle due scelte rende il software migliore.

Quello che conta davvero è:

  • Che il team faccia tutti la stessa cosa, qualunque essa sia
  • Che i messaggi di commit siano comprensibili
  • Che nessuno faccia rebase su rami condivisi

Se il tuo team ha una convenzione, seguila. Se non ce l'ha, sceglierne una qualsiasi e metterla per iscritto vale più di qualunque discussione su quale sia superiore.

Vale lo stesso principio dei messaggi di commit: la coerenza conta più della scelta specifica, come spiego in conventional commits.

In sintesi

Il merge unisce due linee di sviluppo creando un commit di unione: conserva la storia reale, al prezzo di un grafico ramificato. Il rebase riscrive i tuoi commit su una base aggiornata: ottieni una storia lineare, al prezzo di perdere la traccia di com'è andata davvero.

La regola non negoziabile è una: mai rebase su commit già condivisi. Il rebase va bene sui tuoi rami locali, il merge è sempre sicuro.

Il flusso più diffuso li usa entrambi: rebase per tenere aggiornato il proprio ramo e riordinare i commit, merge per integrarlo nel principale.

E la cosa da tenere presente sopra tutte: producono lo stesso codice. È una scelta di leggibilità, non di qualità — quindi conta più che il team sia coerente di quale delle due sia "giusta".

Se i comandi ti sono ancora poco familiari, il quadro pratico è in comandi Git essenziali.