Rebase è un’operazione Git che sposta i commit da un ramo alla punta di un altro, creando una cronologia lineare senza commit di merge non necessari. A differenza dell’unione, rebase riscrive la cronologia: ogni commit spostato ottiene un nuovo hash perché il suo genitore cambia. Secondo la documentazione di Git (2026), rebase viene utilizzato per sincronizzare i rami feature con lo stato attuale di main prima di creare una pull request. Il comando git rebase è uno degli strumenti principali per mantenere una cronologia pulita nei progetti che utilizzano Git Flow.
Punti Chiave
Rebase è un comando Git che basa nuovamente il ramo corrente su un ramo specificato: prende tutti i commit del ramo corrente, li salva temporaneamente, sposta il puntatore del ramo sul commit di destinazione e applica sequenzialmente i commit salvati sopra di esso. Il risultato — la cronologia appare come se lo sviluppatore avesse lavorato direttamente dall’ultimo commit del ramo di destinazione.
La sintassi di base: git rebase main — trovandosi in un ramo feature, questo comando sposta tutti i commit feature sulla punta di main. Git utilizza una strategia di merge a tre vie per ogni singolo commit. Se il commit A è già presente nel ramo di destinazione (determinato dall’hash), Git lo salta automaticamente, evitando modifiche duplicate.
Rebase supporta anche la modalità onto per spostare un sottoinsieme di commit: git rebase --onto target start end — questa forma consente di estrarre un intervallo di commit da un ramo e applicarli sopra un altro. Ad esempio, git rebase --onto main feature~3 feature sposta gli ultimi tre commit del ramo feature sopra main.
# Switch to feature branch
git checkout feature
# Rebase feature onto main
git rebase main
# After successful rebase — history is linear
git log --oneline --graph
# Move last 3 commits to main
git rebase --onto main HEAD~3 HEAD
Rebase e merge risolvono lo stesso compito — combinare modifiche da rami diversi — ma in modi fondamentalmente diversi. Merge preserva la cronologia completa delle unioni creando un commit di merge con due genitori. Rebase riscrive la cronologia, rendendola lineare. La scelta tra di essi dipende dal flusso di lavoro del team e dalle regole di gestione del repository.
La differenza principale è come viene registrato il fatto dell’unione. Merge preserva: “in questo punto abbiamo unito feature in main” — questo è informativo per la cronologia del progetto ma intasa il registro con unioni frequenti. Rebase mostra: “i commit feature sono stati eseguiti sequenzialmente dall’ultimo stato di main” — questo è pulito ma nasconde il fatto che lo sviluppo è stato fatto in parallelo.
La seconda differenza è la gestione dei conflitti. Con merge, i conflitti vengono risolti una volta e la soluzione viene registrata nel commit di merge. Con rebase, possono verificarsi conflitti per ogni commit spostato, ciascuno richiede una risoluzione separata. Ciò richiede più lavoro ma consente un controllo più preciso su quali modifiche finiscono nella versione finale.
| Criterio | Rebase | Merge |
|---|---|---|
| Cronologia | Lineare, senza commit di merge | Non lineare, con commit di merge |
| Hash dei commit | Riscritti (nuovi) | Originali preservati |
| Conflitti | Per ogni commit separatamente | Una volta nel commit di merge |
| Rami pubblici | Vietato | Consentito |
| Comando di annullamento | git rebase --abort | git merge --abort |
Rebase interattivo (git rebase -i) è una modalità in cui Git apre un editor con un elenco di commit e le azioni disponibili per ciascuno. Lo sviluppatore può riscrivere la cronologia prima di inviare a un repository remoto. Questo è lo strumento principale per mantenere commit puliti in un ramo feature.
Comandi disponibili in modalità interattiva: pick (mantenere il commit così com’è), reword (cambiare il messaggio del commit), edit (fermarsi per modifiche), squash (combinare con il commit precedente, mantenendo entrambi i messaggi), fixup (combinare, scartando il messaggio), drop (eliminare il commit). Ogni comando viene posizionato prima dell’hash del commit nell’editor aperto.
Squash e fixup sono i comandi più utilizzati per combinare i commit. Se uno sviluppatore ha fatto 5 piccoli commit di correzione durante il lavoro, squash li unisce in un unico commit logico con un messaggio significativo. Fixup è utile per correggere errori di battitura: le modifiche finiscono nel commit precedente senza mantenere il proprio messaggio.
# Open editor for last 4 commits
git rebase -i HEAD~4
# Editor will show:
pick a1b2c3d Add authentication
pick e4f5g6h Fix typo in login
squash i6j7k8l Additional login fixes
pick m9n0o1p Add auth tests
# After saving — Git performs rebase
# and opens editor for squashed commit message
# Auto-squash without opening editor
git rebase -i HEAD~4 --autosquash
Il flag --autosquash dispone automaticamente fixup/squash per i commit i cui messaggi iniziano con fixup! o squash!. Questo accelera il lavoro se lo sviluppatore pre-marca i commit per la successiva combinazione. Il flag --committer-date-is-author-date preserva la data originale del commit durante il rebasamento — utile per mantenere l’ordine cronologico nella cronologia.
I conflitti durante rebase si verificano quando Git non riesce ad applicare automaticamente un commit spostato a causa di contraddizioni con le modifiche nel ramo di destinazione. A differenza di merge, dove il conflitto viene risolto una volta, con rebase ogni commit può causare un conflitto e deve essere risolto sequenzialmente per ogni commit dal più vecchio al più recente.
Quando si verifica un conflitto, Git mette in pausa il rebase e segnala quale commit ha causato il problema. Lo sviluppatore apre il file in conflitto (Git segna le aree di conflitto con marcatori <<<<<<<, =======, >>>>>>>), lo modifica, lo aggiunge all’indice (git add) e continua il rebase con git rebase --continue. Se non viene trovata soluzione — git rebase --abort annulla completamente il rebase.
Suggerimento: con conflitti multipli, è più efficiente utilizzare git mergetool, che apre un editor visivo per risolvere i conflitti. Si può anche saltare il commit problematico (git rebase --skip), ma questo rimuove le sue modifiche dalla cronologia finale, cosa che raramente è la decisione giusta.
# Start rebase with conflict
git rebase main
# Auto-merging file.txt
# CONFLICT (content): Merge conflict in file.txt
# Check status
git status
# both modified: file.txt
# Edit conflicted sections → git add → continue
git add file.txt
git rebase --continue
# If uncertain — abort
git rebase --abort
La regola d’oro di rebase: non rebasare mai commit che sono già stati inviati a un repository remoto e sono disponibili per altri sviluppatori. Poiché rebase riscrive gli hash dei commit, i colleghi incontreranno conflitti durante il tentativo di sincronizzazione — la loro cronologia locale divergerà dalla cronologia remota riscritta.
Una situazione in cui rebase è categoricamente vietato: se qualcuno ha già creato un ramo basato sui tuoi commit (ad esempio, un collega ha creato un ramo dal tuo ramo feature), riscrivere la cronologia distruggerà il suo lavoro. In questi casi, usa merge. Inoltre, non è consigliato fare rebase poco prima di una scadenza — un errore durante la risoluzione dei conflitti potrebbe richiedere più tempo del previsto e bloccare il rilascio.
Eccezione: se il ramo è utilizzato da un solo sviluppatore (ramo feature personale, non pubblicato o pubblicato in modalità bozza), rebase prima del push è una pratica standard. Dopo la pubblicazione e l’inizio del lavoro collaborativo — solo merge. GitHub e GitLab offrono per impostazione predefinita squash merge come compromesso: combina i commit in uno ma non riscrive la cronologia del ramo di destinazione.
I team moderni utilizzano più spesso un flusso di lavoro orientato a rebase combinato con GitHub Flow. Il processo è il seguente: lo sviluppatore crea un ramo feature da main, ci lavora, si sincronizza periodicamente tramite git rebase main e prima di creare una pull request esegue un rebase interattivo per pulire la cronologia.
Dopo aver creato una PR (se è necessario tirare nuove modifiche da main), viene utilizzato git pull --rebase main invece di un normale git pull. Questo tira le modifiche senza creare un commit di merge non necessario. Git pull con il flag --rebase equivale a git fetch + git rebase — Git prima scarica i nuovi commit, poi rebasa le modifiche locali sopra di essi.
Git consente di configurare rebase come comportamento predefinito per pull: git config --global pull.rebase true. Dopo questa impostazione, git pull esegue sempre rebase invece di merge. Se è necessario un pull normale — si usa git pull --no-rebase. Molti team attivano anche autostash: git config --global rebase.autoStash true — questo nasconde automaticamente le modifiche non committate prima di rebase e le ripristina dopo.
Domande Frequenti
Fare rebase significa eseguire git rebase: spostare i commit dal ramo corrente alla punta di un altro. Di conseguenza, la cronologia diventa lineare, ogni commit ottiene un nuovo hash e i commit di merge non vengono creati. Il comando viene utilizzato per sincronizzare i rami senza punti di unione non necessari nel registro.
Merge crea un commit di merge con due genitori, preservando la cronologia parallela e gli hash originali. Rebase riscrive la cronologia — i commit ottengono nuovi hash e la cronologia diventa lineare. Merge è più sicuro per i rami pubblici, rebase fornisce un registro più pulito.
Il comando git rebase -i HEAD~N apre un editor con gli ultimi N commit. Per ogni commit si può scegliere un’azione: pick (mantenere), reword (rinominare), edit (modificare), squash (combinare con il precedente), fixup (combinare senza messaggio), drop (eliminare). Dopo il salvataggio, Git applica le modifiche scelte.
Rebase riscrive gli hash dei commit, rendendo la cronologia incompatibile con le copie degli stessi commit sulle macchine di altri sviluppatori. Se un collega ha già ottenuto i tuoi commit tramite git pull e poi tu li hai rebasati, il suo git push verrà rifiutato e git pull creerà commit duplicati e conflitti.
Prima del completamento — git rebase --abort annulla completamente. Dopo il completamento, è possibile ripristinare lo stato precedente tramite git reflog — trovare l’hash del commit prima del rebase ed eseguire git reset --hard su di esso. Reflog memorizza la cronologia degli spostamenti di HEAD per 30 giorni per impostazione predefinita.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche