Accedi
Accedi

Git Rebase: come funziona e perché dovresti usarlo

Git Rebase: come funziona e perché dovresti usarlo
Hostman Team
Technical writer
Sistema Git
23.10.2025
Reading time: 15 min

Nel sistema di controllo di versione Git, esistono due modi per combinare un branch con un altro, rappresentati da comandi diversi:

  • git merge. I commit di un branch vengono trasferiti in un altro creando un commit di unione (merge commit).

  • git rebase. I commit di un branch vengono trasferiti in un altro branch mantenendo l’ordine originale delle modifiche.

In parole semplici: con git merge, i commit di un branch vengono “compressi” in uno solo, mentre con git rebase rimangono intatti, ma i branch vengono comunque combinati.

Il comando git rebase consente quindi di combinare i commit di entrambi i branch formando una cronologia condivisa delle modifiche.

Questa guida illustra il comando git rebase, che serve a riposizionare (rebase) i commit (modifiche) da un branch a un altro.

Tutti gli esempi mostrati utilizzano Git versione 2.34.1, in esecuzione su un server Hostman con sistema operativo Ubuntu 22.04.

Puoi utilizzare queste guide per installare Git sul tuo computer:

Che cos’è Git Rebase

Git Rebase è un potente comando Git utilizzato principalmente per integrare le modifiche di un branch su un altro riscrivendo la cronologia dei commit. A differenza di git merge, che crea un nuovo commit di unione e preserva la cronologia di entrambi i branch, git rebase sposta o “riproduce” una serie di commit da un branch su un altro. Questo processo produce una cronologia lineare, facendo apparire come se il branch delle funzionalità fosse stato sviluppato direttamente a partire dall’ultimo commit del branch di destinazione, ad esempio main o master. In questo modo, si ottiene una cronologia più pulita e leggibile, eliminando i commit di merge non necessari e rendendo la cronologia del progetto più ordinata.

Come funziona Git Rebase

Il modo migliore per comprendere come funziona il rebase in Git è osservare un repository astratto composto da diversi branch, analizzando passo dopo passo l’operazione di rebase.

Creazione dei branch

Supponiamo di aver creato un repository con un solo branch master, contenente un singolo commit. Il branch master appare così:

master
  commit_1

Successivamente, a partire da master, abbiamo creato un nuovo branch chiamato hypothesis, dove abbiamo deciso di testare alcune funzionalità. In questo nuovo branch abbiamo eseguito diversi commit per migliorare il codice. Ora il branch appare così:

hypothesis
  commit_4
  commit_3
  commit_2
  commit_1

Più tardi, abbiamo aggiunto un altro commit al branch master per correggere urgentemente una vulnerabilità. Ora il branch master appare così:

master
  commit_5
  commit_1

A questo punto, il nostro repository contiene due branch:

master
  commit_5
  commit_1

hypothesis
  commit_4
  commit_3
  commit_2
  commit_1

Il branch master è quello principale, mentre hypothesis è secondario (derivato). I commit più recenti sono elencati sopra quelli precedenti, come nell’output del comando git log.

Unione dei branch

Supponiamo di voler continuare a lavorare sulla funzionalità che avevamo spostato nel branch hypothesis. Tuttavia, questo branch non contiene la correzione critica che abbiamo effettuato in master.

Pertanto, vogliamo “sincronizzare” lo stato di hypothesis con master in modo che il commit di correzione appaia anche nel branch delle funzionalità. In altre parole, vogliamo che la struttura del repository appaia così:

master
  commit_5
  commit_1

hypothesis
  commit_4
  commit_3
  commit_2
  commit_5
  commit_1

Come puoi vedere, ora il branch hypothesis ripete esattamente la cronologia di master, anche se era stato creato prima del commit_5. In altre parole, hypothesis ora contiene la cronologia di entrambi i branch: la propria e quella di master.

Per ottenere questo risultato, dobbiamo usare git rebase.

Successivamente, le modifiche apportate in hypothesis possono essere unite a master utilizzando il classico comando git merge, che crea un commit di unione.

La struttura del repository sarà quindi la seguente:

master
  commit_merge
  commit_5
  commit_1

hypothesis
  commit_4
  commit_3
  commit_2
  commit_5
  commit_1

Inoltre, eseguire git merge dopo git rebase può ridurre la probabilità di conflitti.

Pratica: git rebase

Una volta coperto l’aspetto teorico del comando git rebase, possiamo passare alla pratica testandolo in un repository reale di un progetto dimostrativo. La struttura del repository sarà la stessa dell’esempio teorico precedente.

Creazione di un repository

Per prima cosa, creiamo una directory separata per contenere il repository:

mkdir rebase

Poi entriamoci:

cd rebase

Ora possiamo inizializzare il repository:

git init

Nella console apparirà un messaggio informativo standard:

hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
...

E nella directory corrente apparirà una cartella nascosta .git, che puoi visualizzare con il seguente comando:

ls -a

Il flag -a significa all e consente di visualizzare il file system in modalità estesa. Il suo contenuto sarà:

.  ..  .git

Prima di eseguire i commit, dobbiamo specificare alcune informazioni di base sull’utente.

Prima, il nome:

git config --global user.name "NAME"

Poi l’email:

git config --global user.email "NAME@HOST.COM"

Popolamento del branch master

Utilizzando semplici file di testo, simuleremo l’aggiunta di diverse funzioni al progetto. Ogni nuova funzione sarà rappresentata come un commit separato.

Crea un file per la prima funzione improvvisata:

nano function_1

Inserisci il seguente contenuto:

Function 1

Ora indicizza le modifiche effettuate nel repository:

git add .

Per sicurezza, controlla lo stato di indicizzazione:

git status

Nella console dovrebbe apparire il seguente messaggio, che mostra le modifiche indicizzate:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   function_1

Ora possiamo eseguire il commit:

git commit -m "commit_1"

La console dovrebbe mostrare un messaggio che conferma il commit riuscito in master:

[master (root-commit) 4eb7cc3] commit_1
 1 file changed, 1 insertion(+)
 create mode 100644 function_1

Popolamento del branch hypothesis

Ora creiamo un nuovo branch chiamato hypothesis:

git checkout -b hypothesis

Il flag -b serve per passare immediatamente al nuovo branch.

La console mostrerà un messaggio di conferma:

Switched to a new branch 'hypothesis'

Successivamente, dobbiamo eseguire tre commit in sequenza con tre file, in modo analogo a master:

  • commit_2 with file function_2 and content: Function 2

  • commit_3 with file function_3 and content: Function 3

  • commit_4 with file function_4 and content: Function 4

  • commit_2 con il file function_2 e contenuto: Function 2
  • commit_3 con il file function_3 e contenuto: Function 3
  • commit_4 con il file function_4 e contenuto: Function 4

Se poi controlliamo l’elenco dei commit:

git log --oneline

La console mostrerà la seguente sequenza:

d3efb82 (HEAD -> hypothesis) commit_4
c9f57b7 commit_3
c977f16 commit_2
4eb7cc3 (master) commit_1

Qui, il flag --oneline viene utilizzato per visualizzare le informazioni sui commit in formato compatto.

Aggiunta di un commit al branch master

L’ultimo passaggio è aggiungere un altro commit al branch principale master. Passiamo a esso:

git checkout master

La console confermerà il cambio:

Switched to branch 'master'

Ora creiamo un altro file di funzione:

nano function_5

Con il seguente contenuto:

Function 5

Successivamente, indiciamo le modifiche:

git add .

E creiamo il nuovo commit:

git commit -m "commit_5"

Se controlliamo l’elenco dei commit:

git log --oneline

Il branch master avrà ora due commit:

3df7a00 (HEAD -> master) commit_5
4eb7cc3 commit_1

Unione dei branch con git rebase

Per eseguire il rebase, dobbiamo prima passare al branch hypothesis:

git checkout hypothesis

E poi eseguire il rebase:

git rebase master

Dopo questo, la console mostrerà un messaggio che conferma il successo dell’operazione:

Successfully rebased and updated refs/heads/hypothesis.

Ora possiamo verificare l’elenco dei commit:

git log --oneline

La console mostrerà un elenco contenente i commit di entrambi i branch nell’ordine originale:

8ecfd58 (HEAD -> hypothesis) commit_4
f715aba commit_3
ee47470 commit_2
3df7a00 (master) commit_5
4eb7cc3 commit_1

Ora il branch hypothesis contiene la cronologia completa dell’intero repository.

Risoluzione dei conflitti

Come con git merge, anche quando si utilizza il comando git rebase possono verificarsi conflitti che richiedono una risoluzione manuale.

Modifichiamo il repository in modo da creare artificialmente un conflitto di rebase.

Creiamo un altro file nel branch hypothesis:

nano conflict

E scriviamo il seguente testo al suo interno:

There must be a conflict here!

Indichiamo le modifiche:

git add .

E creiamo un commit:

git commit -m "conflict_1"

Ora passiamo al branch master:

git checkout master

Creiamo un file simile:

nano conflict

E aggiungiamo il seguente contenuto:

There must NOT be a conflict here!

Indichiamo nuovamente le modifiche:

git add .

E creiamo un commit:

git commit -m "conflict_2"

Riapriamo il file creato:

nano conflict

E modifichiamone il contenuto con:

There definitely must NOT be a conflict here!

Indichiamo di nuovo le modifiche:

git add .

E creiamo un altro commit:

git commit -m "conflict_3"

Ora torniamo al branch hypothesis:

git checkout hypothesis

E eseguiamo nuovamente il rebase:

git rebase master

La console mostrerà un messaggio di conflitto:

Auto-merging conflict
CONFLICT (add/add): Merge conflict in conflict
error: could not apply 6003ed7... conflict_1
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 6003ed7... conflict_1

Git suggerisce di modificare il file di conflitto, indicizzare le modifiche con git add e poi continuare il rebase utilizzando il flag --continue.

Questo è esattamente ciò che faremo:

nano conflict

Il file conterrà due versioni in conflitto racchiuse tra marcatori speciali:

<<<<<<< HEAD
There definitely must NOT be a conflict here!
=======
There must be a conflict here!
>>>>>>> 6003ed7 (conflict_1)

Il nostro compito è rimuovere le parti non necessarie e riempire il file con una versione finale del testo:

There must absolutely definitely unanimously NOT be any conflict here!

Ora indichiamo le modifiche:

git add .

E continuiamo il rebase:

git rebase --continue

Dopo di ciò, la console aprirà un editor di testo suggerendo di modificare il messaggio di commit originale del commit in cui si è verificato il conflitto:

conflict_1

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto bd7aefc
# Last commands done (4 commands done):
#    pick 8ecfd58 commit_4
#    pick 6003ed7 conflict_1
# No commands remaining.
# You are currently rebasing branch 'hypothesis' on 'bd7aefc'.
#
# Changes to be committed:
#       modified:   conflict
#

La console mostrerà quindi un messaggio che conferma il completamento riuscito del processo di rebase:

[detached HEAD 482db49] conflict_1
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/hypothesis.

Ora, se controlli l’elenco dei commit nel branch hypothesis:

git log --oneline

Vedrai la sequenza originale di tutte le modifiche effettuate:

482db49 (HEAD -> hypothesis) conflict_1
bd5d036 commit_4
407e245 commit_3
948b41c commit_2
bd7aefc (master) conflict_3
d98648d conflict_2
3df7a00 commit_5
4eb7cc3 commit_1

Nota che i commit conflict_2 e conflict_3, creati nel branch master, appaiono nella cronologia prima del commit conflict_1. Tuttavia, questo vale per qualsiasi commit creato nel branch master.

Rebase di un repository remoto

Oltre a lavorare con branch locali, è possibile eseguire un rebase anche quando si scaricano modifiche da un repository remoto. Per farlo, è necessario aggiungere il flag --rebase al comando pull standard:

git pull --rebase remote branch

Dove:

  • remote è il repository remoto

  • branch è il branch remoto

Fondamentalmente, questa configurazione di pull è equivalente al comando git rebase, con la differenza che le modifiche (commit) applicate al branch corrente provengono dal repository remoto.

Principali vantaggi di Git Rebase

  • Linearità

Il comando git rebase consente di creare una cronologia lineare del branch di destinazione, composta da commit eseguiti in sequenza. Una sequenza senza ramificazioni rende la cronologia più facile da comprendere e analizzare.

  • Meno conflitti 

Eseguire git rebase in anticipo può ridurre significativamente la probabilità di conflitti durante l’unione dei branch con git merge. I conflitti sono più facili da risolvere nei commit sequenziali rispetto a quelli uniti in un unico commit di merge. Questo è particolarmente utile quando si inviano i branch a repository remoti.

Svantaggi di Git Rebase

  • Modifica della cronologia 

A differenza di merge, rebase riscrive parzialmente la cronologia del branch di destinazione, rimuovendo elementi di cronologia non necessari.

  • Rischio di errori 

La possibilità di ristrutturare significativamente la cronologia dei commit può portare a errori irreversibili nel repository. Ciò significa che alcuni dati potrebbero andare definitivamente persi.

Quando utilizzare Git Rebase

Git rebase è particolarmente utile quando si lavora su piccoli branch o branch di funzionalità individuali che verranno successivamente uniti in un branch principale condiviso. È anche ottimo per mantenere una cronologia pulita e lineare, il che è particolarmente vantaggioso nei progetti open source o quando è necessario mantenere una cronologia dei commit chiara per facilitare il debug e la comprensione del progetto.

Tuttavia, negli ambienti di team con più collaboratori, rebase dovrebbe essere utilizzato con cautela per evitare problemi legati alla riscrittura della cronologia pubblica. È importante comunicare con il team su quando è appropriato utilizzare rebase e assicurarsi che tutti siano consapevoli del potenziale rischio di conflitti. In molti casi, l’uso di git merge per integrare i branch può essere più sicuro e semplice, soprattutto quando si lavora su branch condivisi o quando una cronologia non lineare è accettabile.

Considerazioni importanti

  • Riscrittura della cronologia

Uno degli aspetti fondamentali di git rebase è che riscrive la cronologia dei commit, il che significa che gli hash SHA-1 dei commit rebasati cambiano. Ciò può causare problemi negli ambienti collaborativi, specialmente quando si esegue un rebase su un branch che è già stato inviato a un repository remoto condiviso. La riscrittura della cronologia può portare a conflitti con altri sviluppatori che hanno basato il proprio lavoro sulla cronologia precedente. Può anche causare problemi durante il push del branch rebasato, poiché il repository remoto riconoscerà che la cronologia locale non corrisponde più a quella remota.

  • Evitare di rebasare branch pubblici

Una pratica comune consigliata è quella di evitare di rebasare branch pubblici che sono già stati condivisi con altri. Poiché rebase modifica la cronologia dei commit, rebasare branch pubblici su cui si basano più sviluppatori può generare cronologie divergenti, causando confusione e conflitti di merge difficili da risolvere. In generale, git rebase è più appropriato per i branch locali o per preparare un branch di funzionalità alla fusione finale in un branch principale. I branch pubblici, soprattutto quelli su cui lavorano più persone, dovrebbero di norma essere uniti con merge invece che rebasati.

  • Conflitti potenziali

Durante un rebase, se ci sono modifiche in conflitto sia nel branch delle funzionalità che in quello di destinazione, Git si fermerà e chiederà di risolvere il conflitto manualmente. Sebbene la risoluzione dei conflitti durante un rebase sia simile a quella di un merge, il rebase richiede di risolvere i conflitti per ogni commit che deve essere riapplicato, rendendo il processo potenzialmente più laborioso, soprattutto con branch di grandi dimensioni. Una volta risolti i conflitti, è possibile continuare il rebase con il comando git rebase --continue.

Conclusione

L’unione di due branch utilizzando il rebase, implementata con il comando git rebase, è fondamentalmente diversa dall’unione classica eseguita con il comando git merge.

  • git merge trasforma i commit di un branch in un unico commit in un altro.

  • git rebase sposta i commit di un branch alla fine di un altro mantenendo l’ordine originale delle modifiche.

Un effetto di rebase simile può essere ottenuto anche utilizzando il comando git pull con il flag aggiuntivo --rebase.

Da un lato, il comando git rebase consente di ottenere una cronologia dei commit più pulita e comprensibile nel branch principale, aumentando la manutenibilità del repository.

Dall’altro, git rebase riduce il livello di dettaglio delle modifiche all’interno del branch, semplificando la cronologia e rimuovendo alcune delle sue registrazioni.

Per questo motivo, il rebase è una funzionalità destinata agli utenti più esperti che comprendono a fondo come funziona Git.

Nella maggior parte dei casi, il comando git rebase viene utilizzato insieme al comando git merge, consentendo di ottenere una struttura del repository e dei branch quanto più ottimale possibile.

Sistema Git
23.10.2025
Reading time: 15 min

Simili

Hai domande,
commenti o dubbi?

I nostri professionisti sono disponibili per assisterti in ogni momento,
che tu abbia bisogno di aiuto o non sappia da dove iniziare.
Inviaci un'email
Hostman's Support