git rebase

Questo documento presenta un'analisi approfondita del comando git rebase. Il comando di riassegnazione è stato illustrato anche nelle pagine dedicate alla configurazione di un repository e alla riscrittura della cronologia. In questa pagina analizzeremo più nei dettagli la configurazione e l'esecuzione di git rebase e i casi d'uso e le insidie più comuni del comando di riassegnazione.

La riassegnazione è una delle due utility Git specializzate nell'integrazione delle modifiche da un branch all'altro. L'altra utilità di integrazione delle modifiche è git merge. Il merge è un record delle modifiche che si muove in avanti. Invece, la riassegnazione include efficaci funzioni di riscrittura della cronologia. Per un confronto dettagliato tra merge e riassegnazione, consulta la nostra guida al confronto tra il merge e la riassegnazione. La riassegnazione prevede 2 modalità principali: modalità" manuale" e modalità "interattiva". Di seguito le analizzeremo in modo più dettagliato.

Cos'è git rebase?

La riassegnazione è il processo di spostamento o di unione di una sequenza di commit in un nuovo commit di base. La riassegnazione è molto utile e facilmente visualizzabile nel contesto di un flusso di lavoro di creazione dei branch di funzioni. L'intero processo può essere visualizzato come segue:

Tutorial su Git: git rebase

Dal punto di vista dei contenuti, la riassegnazione cambia la base del branch da un commit all'altro facendo sembrare come se il branch fosse stato creato da un commit diverso. Internamente, Git ottiene questo risultato creando nuovi commit e applicandoli alla base specificata. È molto importante capire che anche se il branch ha lo stesso aspetto, è composto da commit completamente nuovi.

Utilizzo

Il motivo principale della riassegnazione è quello di mantenere una cronologia del progetto lineare. Ad esempio, considera una situazione in cui il branch principale è avanzato da quando hai iniziato a lavorare su un branch di funzioni. Vuoi applicare gli ultimi aggiornamenti del branch principale al branch di funzioni, ma vuoi mantenere pulita la cronologia del branch in modo che sembri che tu abbia lavorato sull'ultima versione del branch principale. Ciò offre il vantaggio di un merge ordinato del branch di funzioni nel branch principale. Perché vogliamo mantenere una cronologia "pulita"? I vantaggi di avere una cronologia pulita diventano tangibili quando si eseguono operazioni Git per indagare sull'introduzione di una regressione. Uno scenario più reale sarebbe:

  1. Viene identificato un bug nel branch principale. Una funzione ha smesso di funzionare.
  2. Uno sviluppatore esamina la cronologia del branch principale usando git log. Grazie alla cronologia "pulita", lo sviluppatore è in grado di ragionare rapidamente sulla cronologia del progetto.
  3. Lo sviluppatore non è in grado di individuare il momento in cui è stato introdotto il bug usando git log, quindi esegue un comando git bisect.
  4. Dal momento che la cronologia di git è pulita, git bisect può mettere a confronto un set perfezionato di commit durante la ricerca della regressione. Lo sviluppatore trova rapidamente il commit che ha introdotto il bug ed è in grado di agire di conseguenza.

Scopri di più su git log e git bisect consultando le pagine singole corrispondenti.

Hai due opzioni per integrare la funzione nel branch principale: eseguire direttamente il merge oppure eseguire prima la riassegnazione e poi il merge. La prima opzione si traduce in un merge a 3 vie e in un commit di merge, mentre la seconda si traduce in un merge con avanzamento rapido e in una cronologia perfettamente lineare. Il diagramma seguente mostra come la riassegnazione sul branch principale faciliti i merge con avanzamento rapido.

Git rebase: creazione di branch sul master

La riassegnazione è un modo comune per integrare le modifiche upstream nel repository locale. Il pull delle modifiche upstream con git merge si traduce in un commit di merge superfluo ogni volta che desideri vedere l'avanzamento del progetto. D'altra parte, eseguire la riassegnazione è come affermare di voler basare le proprie modifiche su ciò che hanno già fatto gli altri membri del team.

Non eseguire la riassegnazione della cronologia pubblica

Come abbiamo discusso in precedenza nella sezione sulla riscrittura della cronologia, non dovresti mai eseguire la riassegnazione dei commit una volta che sono stati inviati a un repository pubblico. La riassegnazione sostituirebbe i commit meno recenti con quelli nuovi dando l'impressione che la parte della cronologia correlata a questi ultimi sia svanita improvvisamente.

Confronto tra git rebase standard e git rebase interattivo

Si parla di git rebase interattivo quando git rebase accetta un argomento -- i, che sta per "interattivo". Senza argomenti, il comando viene eseguito in modalità standard. In entrambi i casi, supponiamo di aver creato un branch di funzioni separato.

# Create a feature branch based off of main 
git checkout -b feature_branch main
# Edit files 
git commit -a -m "Adds new feature" 

Git rebase in modalità standard prenderà automaticamente i commit nel branch di lavoro corrente e li applicherà alla base del branch inviato.

git rebase <base>

Consente di eseguire la riassegnazione automatica del branch corrente su , che può essere un qualsiasi tipo di riferimento di commit (ad esempio un ID, un nome di branch, un tag o un riferimento relativo a HEAD).

L'esecuzione di git rebase con il flag -i avvia una sessione di riassegnazione interattiva. Invece di spostare ciecamente tutti i commit nella nuova base, la riassegnazione interattiva ti dà l'opportunità di modificare i singoli commit durante il processo. Ciò consente di ripulire la cronologia rimuovendo, dividendo e modificando una serie esistente di commit. È come il comando Git commit --amend, ma con una marcia in più.

git rebase --interactive <base>

Consente di eseguire la riassegnazione del branch corrente su , ma utilizza una sessione di riassegnazione interattiva. Viene aperto un editor in cui è possibile immettere i comandi (descritti di seguito) per ogni commit da riassegnare. Questi comandi determinano il modo in cui i singoli commit verranno trasferiti alla nuova base. Puoi inoltre riordinare l'elenco dei commit per cambiare l'ordine dei commit stessi. Dopo aver specificato i comandi per ogni commit nella riassegnazione, Git inizierà a riprodurre i commit applicando i comandi di riassegnazione. I comandi di modifica della riassegnazione sono i seguenti:




pick 2231360 some old commit
pick ee2adc2 Adds new feature


# Rebase 2cf755d..ee2adc2 onto 2cf755d (9 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

Comandi rebase aggiuntivi

Come descritto nei dettagli nella pagina relativa alla riscrittura della cronologia, la riassegnazione può essere utilizzata per modificare commit meno recenti e duplicati, file sottoposti a commit e messaggi duplicati. Sebbene queste siano le applicazioni più comuni, git rebase dispone inoltre di opzioni di comando aggiuntive che possono essere utili in applicazioni più complesse.

  • git rebase -- d significa che durante la riproduzione il commit verrà scartato dal blocco di commit unito finale.
  • git rebase -- p lascia il commit invariato. Non modificherà il messaggio o il contenuto del commit, che verrà comunque indicato come commit singolo nella cronologia dei branch.
  • git rebase -- x durante la riproduzione esegue uno script della shell della riga di comando su ogni commit contrassegnato. Un esempio utile potrebbe essere quello di eseguire la suite di test della base di codice su commit specifici, per facilitare l'individuazione delle regressioni durante una riassegnazione.

Riepilogo

La riassegnazione interattiva dà il controllo completo sull'aspetto della cronologia del progetto. Ciò offre molta libertà agli sviluppatori, poiché consente loro di eseguire il commit di una cronologia "disordinata", mentre sono concentrati sulla scrittura di codice, e di tornare indietro e ripulirla quando portano a termine il lavoro.

La maggior parte degli sviluppatori preferisce utilizzare la riassegnazione interattiva per perfezionare un branch di funzioni prima di eseguirne il merge alla base di codice principale. Questo dà loro l'opportunità di eseguire lo squash dei commit insignificanti, eliminare quelli obsoleti e assicurarsi che tutto il resto sia in ordine prima di eseguire il commit nella cronologia "ufficiale" del progetto. A tutti gli altri, sembrerà che l'intera funzione sia stata sviluppata in un'unica serie di commit ben pianificati.

Il vero potere della riassegnazione interattiva è evidente osservando la cronologia del branch principale risultante. A tutti gli altri, sembrerà che tu sia uno sviluppatore brillante che ha implementato la nuova funzione al primo colpo utilizzando il numero perfetto di commit. Ecco come la riassegnazione interattiva è in grado di mantenere pulita e pertinente la cronologia di un progetto.

Opzioni di configurazione

Ci sono alcune proprietà di riassegnazione che possono essere impostate usando git config. Queste opzioni modificheranno l'aspetto dell'output di git rebase.

  • rebase.stat: un valore booleano impostato su false per impostazione predefinita. L'opzione attiva o disattiva la visualizzazione del contenuto diffstat visivo che mostra cosa è cambiato dall'ultima riassegnazione.
  • rebase.autoSquash: un valore booleano che attiva o disattiva il comportamento --autosquash.
  • rebase.missingCommitsCheck: può essere impostato su più valori che cambiano il comportamento di riassegnazione in caso di commit mancanti.
warn Stampa l'output di avviso in modalità interattiva per avvertire della rimozione dei commit

error

Arresta la riassegnazione e stampa i messaggi di avviso relativi ai commit rimossi

ignore

Configurato per impostazione predefinita, ignora eventuali avvisi di commit mancanti
  • rebase.instructionFormat: una stringa di formato git log che verrà utilizzata per formattare la visualizzazione della riassegnazione interattiva

Applicazione avanzata di riassegnazione

L'argomento della riga di comando --onto può essere inviato a git rebase. Nella modalità --onto di git rebase, il comando si espande in:

 git rebase --onto <newbase> <oldbase>

Il comando --onto abilita un modulo o una riassegnazione più efficace che consente di inviare riferimenti specifici da usare come punte di una riassegnazione.
Supponiamo di avere un repository di esempio con branch come il seguente:


   o---o---o---o---o  main
        \
         o---o---o---o---o  featureA
              \
               o---o---o  featureB

featureB si basa su featureA, tuttavia, ci rendiamo conto che featureB non dipende da nessuna delle modifiche in featureA e potrebbe essersi semplicemente distaccato dal branch principale.

 git rebase --onto main featureA featureB

featureA è la < oldbase >. main diventa la < newbase > e featureB è il riferimento per ciò a cui punterà HEAD della < newbase >. I risultati sono quindi:

 
                      o---o---o  featureB
                     /
    o---o---o---o---o  main
     \
      o---o---o---o---o  featureA
                           

Conoscere i pericoli della riassegnazione

Un avvertimento da considerare quando si usa git rebase è che i conflitti di merge possono diventare più frequenti durante un flusso di lavoro di riassegnazione. Ciò si verifica se si dispone di un branch di lunga durata che si è allontanato da quello principale. Alla fine, sarà necessario eseguire la riassegnazione sul branch principale che in quel momento potrebbe contenere molti nuovi commit con cui le modifiche apportate al branch potrebbero entrare in conflitto. È possibile risolvere facilmente questo problema eseguendo spesso la riassegnazione del branch su quello principale ed eseguendo commit più frequenti. Gli argomenti della riga di comando --continue e --abort possono essere inviati a git rebase per far avanzare o ripristinare la riassegnazione durante la gestione dei conflitti.

Una precisazione più importante sulla riassegnazione riguarda i commit persi in seguito alla riscrittura interattiva della cronologia. Se vengono eseguiti la riassegnazione in modalità interattiva e i sottocomandi come lo squash o il drop, i commit verranno rimossi dal log immediato del branch. A prima vista, potrebbe sembrare che i commit siano stati eliminati definitivamente. Tramite git reflog, è possibile ripristinare questi commit e annullare l'intera riassegnazione. Per maggiori informazioni sull'uso di git reflog per trovare i commit persi, consulta la nostra pagina di documentazione di Git reflog.

Il comando git rebase in sé non è seriamente pericoloso. I veri casi di pericolo sorgono quando si esegue la riscrittura della cronologia con riassegnazioni interattive e si forza il push dei risultati su un branch remoto condiviso da altri utenti. Questo è uno schema da evitare in quanto ha la capacità di sovrascrivere il lavoro di altri utenti remoti quando eseguono il pull.

Ripristino dalla riassegnazione upstream

Se un altro utente ha eseguito la riassegnazione e forzato il push sul branch in cui stai eseguendo il commit, il comando git pull sovrascriverà tutti i commit che hai basato su quel branch precedente con la punta di cui è stato forzato il push. Fortunatamente, tramite git reflog puoi ottenere il log di riferimento del branch remoto, in cui puoi trovare il riferimento risalente a prima della riassegnazione. Potrai quindi eseguire la riassegnazione del branch in base a tale riferimento remoto utilizzando l'opzione --onto, come illustrato in precedenza nella sezione Applicazione avanzata di riassegnazione.

Riepilogo

In questo articolo abbiamo trattato l'utilizzo di git rebase. Abbiamo illustrato casi d'uso di base e avanzati e analizzato esempi più avanzati. Alcuni argomenti chiave sono:

  • Confronto tra git rebase standard e le modalità interattive
  • Opzioni di configurazione di git rebase
  • git rebase --onto
  • Commit persi di git rebase

Abbiamo esaminato l'utilizzo di git rebase con altri strumenti come git reflog, git fetch e git push. Visita le pagine corrispondenti per ulteriori informazioni.

Pronto per imparare a utilizzare Git?

Prova questo tutorial interattivo.

Inizia ora