W3docs

git rebase

Scopri il significato del comando git rebase, esempi d'uso e la differenza tra rebase standard e rebase interattivo.

Cosa fa git rebase

Il rebasing significa spostare una serie di commit su un nuovo commit base. In altre parole, git rebase cambia il punto di partenza del branch corrente da un commit a un altro, come se avessi creato il branch da un punto diverso della cronologia.

La cosa fondamentale da capire: rebase non sposta i tuoi commit originali. Crea nuovi commit da zero con le stesse modifiche e gli stessi messaggi di commit, ma con commit genitore diversi e quindi hash di commit (SHA) diversi. I vecchi commit diventano irraggiungibili, anche se il branch sembra lo stesso.

git rebase

Questa pagina tratta il rebase standard, il rebase interattivo, la forma --onto, la risoluzione dei conflitti e come recuperare quando un rebase va storto.

Rebase vs. merge

Sia git rebase che git merge integrano le modifiche da un branch in un altro, ma modellano la cronologia in modo diverso:

  • Merge crea un nuovo commit di merge che collega le due cronologie dei branch. La cronologia è non lineare ma completamente preservata — nulla viene riscritto.
  • Rebase riproduce i tuoi commit sopra il branch di destinazione. La cronologia rimane lineare (nessun commit di merge), ma i commit originali vengono riscritti.

Usa rebase quando vuoi una cronologia pulita e lineare per un feature branch prima di condividerlo. Usa merge quando vuoi preservare la cronologia esatta di come i branch si sono uniti, o quando il branch è già pubblico.

Rebase standard

In modalità standard, git rebase prende i commit unici del tuo branch corrente e li riproduce sopra <base>. Il <base> può essere un nome di branch, un tag o un ID di commit.

git rebase <base>

Il flusso di lavoro tipico: master è andato avanti da quando hai creato il branch, e vuoi le ultime modifiche di master sotto il tuo lavoro sul feature senza un commit di merge.

# you are on your feature branch
git switch feature
# replay feature's commits on top of the current tip of master
git rebase master

Prima del rebase, la cronologia appare così (feature è stato creato da un master precedente):

      A---B---C feature
     /
D---E---F---G master

Dopo git rebase master, i commit del feature vengono ricreati sopra G:

              A'--B'--C' feature
             /
D---E---F---G master

A', B' e C' portano le stesse modifiche di A, B, C, ma sono nuovi commit con nuovi hash.

Non fare mai il rebase della cronologia pubblica

Non fare mai il rebase di commit che sono già stati inviati (push) e su cui altri potrebbero aver basato il proprio lavoro. Poiché rebase sostituisce i commit con nuovi, chiunque abbia eseguito il pull dei vecchi commit troverà la propria cronologia fuori sincronia — sembrerà come se parte del progetto fosse scomparsa, e otterranno commit duplicati o in conflitto al prossimo pull.

Attenzione

La regola d'oro del rebasing: esegui il rebase solo dei commit che esistono esclusivamente sul tuo branch locale e che non sono stati condivisi. Il rebase di commit già pubblicati è il modo più comune in cui i team si rompono reciprocamente i repository.

Il confine sicuro è semplice: esegui il rebase del lavoro privato liberamente; non eseguire mai il rebase del branch condiviso master/main o di qualsiasi branch su cui altri stanno attivamente lavorando. Questa è la stessa cautela che si applica a git reset e git commit --amend.

Rebase interattivo

La modalità interattiva (-i, abbreviazione di "interactive") ti permette di modificare, riordinare, unire o eliminare singoli commit durante la loro riproduzione. Questo è lo strumento a cui gli sviluppatori ricorrono per ripulire un feature branch prima del merge — combinando piccoli commit "fix typo", riformulando messaggi poco chiari ed eliminando esperimenti senza esito.

git rebase -i <base>

Per esempio, per sistemare gli ultimi 3 commit del tuo branch:

git rebase -i HEAD~3

Questo apre il tuo editor con una lista "todo" — una riga per commit, con il più vecchio in cima:

pick 11a1456 Add login form
pick a23db19 Fix typo in label
pick 31d332c Add password validation

# Rebase d4e5f6a..31d332c onto d4e5f6a (3 commands)
#
# Commands:
# p, pick   = use commit
# r, reword = use commit, but edit the commit message
# e, edit   = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup  = like "squash", but discard this commit's log message
# x, exec   = run command (the rest of the line) using shell
# d, drop   = remove commit

Per unire la correzione del typo nel commit del form di login e riformulare il commit di validazione, dovresti cambiare la lista in:

pick 11a1456 Add login form
fixup a23db19 Fix typo in label
reword 31d332c Add password validation

Salva e chiudi l'editor; Git riproduce i commit applicando ogni istruzione nell'ordine.

Comandi del rebase interattivo

Ogni riga nella lista todo inizia con uno di questi comandi:

  • pick — mantieni il commit com'è. Questo è il valore predefinito per ogni riga.
  • reword — mantieni le modifiche del commit, ma fermati per modificarne il messaggio.
  • edit — fermati a questo commit in modo da poter correggerne il contenuto (dividerlo, aggiungere file, ecc.), poi git rebase --continue.
  • squash — unisci questo commit al precedente e combina entrambi i messaggi in uno.
  • fixup — come squash, ma scarta il messaggio di questo commit (mantieni solo quello precedente).
  • drop — rimuovi completamente il commit dalla cronologia.
  • exec — esegui un comando shell dopo il commit precedente (utile per eseguire test a ogni step).

Riordinare le righe riordina i commit; eliminare una riga equivale a drop.

La forma --onto

Il flag --onto ti dà un controllo preciso su quali commit vengono spostati e dove atterrano:

git rebase --onto <newbase> <oldbase> <branch>

Prende i commit presenti in <branch> ma non in <oldbase>, e li riproduce su <newbase>. Questo è il modo per spostare un branch da una base di cui non ha più bisogno.

Supponiamo che featureY sia stato creato da featureX, ma è in realtà indipendente dalle modifiche di featureX e appartiene a master:

                          o---o---o featureY
                         /
            o---o---o---o featureX
           /
o---o---o---o master

Esegui:

git rebase --onto master featureX featureY

Qui featureX è il <oldbase>, master è il <newbase> e featureY è il branch di cui si esegue il rebase. Git riproduce solo i commit propri di featureY su master, staccandoli da featureX:

                  o'--o'--o' featureY
                 /
o---o---o---o---o master
           \
            o---o---o---o featureX

Risolvere i conflitti durante un rebase

Poiché rebase riapplica i tuoi commit uno alla volta, un conflitto può fermare il processo a qualsiasi commit. Quando ciò accade, Git si mette in pausa e ti indica quali file sono in conflitto.

Il flusso di lavoro per superarlo:

# 1. fix the conflicted files in your editor, then stage them
git add <resolved-file>

# 2. continue replaying the remaining commits
git rebase --continue

Altri controlli mentre un rebase è in pausa:

  • git rebase --skip — salta il commit corrente e vai avanti (usa con cautela; perdi le modifiche di quel commit).
  • git rebase --abort — interrompi tutto e ripristina il branch esattamente com'era prima di iniziare.

Un branch longevo che si è molto allontanato da master produce il maggior numero di conflitti, a volte lo stesso conflitto su più commit. Due abitudini riducono il disagio: eseguire il rebase su master frequentemente anziché una sola volta alla fine, e mantenere i commit piccoli e focalizzati.

Opzioni di configurazione

Alcune impostazioni predefinite di rebase possono essere configurate con git config. Queste cambiano il comportamento di git rebase e cosa stampa:

  • rebase.stat — un boolean (predefinito false) che attiva/disattiva un diffstat visivo delle modifiche dall'ultimo rebase.
  • rebase.autoSquash — un boolean che attiva/disattiva il comportamento --autosquash (riordinamento automatico dei commit fixup!/squash! durante il rebase interattivo).
  • rebase.missingCommitsCheck — controlla cosa succede quando i commit vengono rimossi dalla lista todo. Accetta uno di:
ValoreComportamento
ignoreIl valore predefinito. Eventuali avvisi sui commit mancanti vengono ignorati.
warnUn avviso viene stampato in modalità interattiva sui commit rimossi.
errorIl rebase si interrompe e stampa messaggi di avviso sui commit rimossi.
  • rebase.instructionFormat — una string nel formato git log usata per formattare ogni riga di commit mostrata nella lista todo interattiva.

Recuperare da un rebase fallito

Un rebase può sembrare distruttivo: con squash o drop, i commit scompaiono dal log del branch e sembra che siano andati per sempre. Non è così. Git conserva un registro di dove puntava il tuo branch prima di ogni operazione nel git reflog.

Per annullare un rebase, trova la voce appena prima di esso e reimposta il branch a quella posizione:

# see where the branch was before the rebase
git reflog

# example output:
# a23db19 HEAD@{0}: rebase (finish): returning to refs/heads/feature
# 31d332c HEAD@{5}: rebase (start): checkout master
# c0ffee1 HEAD@{6}: commit: the state you want back

# move the branch back to the pre-rebase commit
git reset --hard HEAD@{6}

Questa è la tua rete di sicurezza — finché riesci a leggere il reflog, nessun rebase è veramente irreversibile.

Recuperare da un rebase upstream

Se un collega esegue il rebase e un force-push di un branch su cui stai anche tu lavorando, un semplice git pull cercherà di riconciliare i tuoi commit con il tip remoto riscritto e può lasciarti con una cronologia duplicata o aggrovigliata.

La soluzione usa il reflog del branch di remote-tracking per trovare dove puntava prima del rebase, poi riproduce il tuo lavoro sul nuovo tip con --onto:

# find the old tip of origin/feature in the remote-tracking reflog
git reflog show origin/feature

# replay your local commits from the old base onto the new one
git rebase --onto origin/feature <old-origin-tip> feature

Questo sposta solo i tuoi commit sul tip con force-push, senza trascinare i vecchi commit ormai riscritti.

Argomenti correlati

  • git merge — l'alternativa non distruttiva per integrare i branch.
  • git reflog — il tuo log di annullamento per recuperare da un rebase errato.
  • git reset — sposta il puntatore di un branch, anche a uno stato precedente al rebase.
  • git cherry-pick — riproduce singoli commit senza eseguire il rebase dell'intero branch.

Esercitati

Pratica
Quali sono le affermazioni corrette riguardo al comando " `git rebase` come descritto nel W3Docs Git Tutorial?
Quali sono le affermazioni corrette riguardo al comando " `git rebase` come descritto nel W3Docs Git Tutorial?
Was this page helpful?