Guida all’Interattivo Rebase di Git, con Esempi Pratici

Il controllo delle versioni con Git è diventato di default in ogni cinturino da lavoro di ogni sviluppatore moderno. Comandi come commit, push e pull sono entrati nella memoria muscolare delle nostre dita. Tuttavia, relativamente pochi sviluppatori conoscono le funzionalità “più avanzate” di Git — e quanto possano essere incredibilmente preziose! In questo articolo, esploreremo “l’interattivo rebase”, uno dei più potenti strumenti di Git.

Perché l’Interattivo Rebase dovrebbe far parte dell’arsenale di ogni sviluppatore

In poche parole, e senza esagerazione, l’interattivo rebase può aiutarti a diventare uno sviluppatore migliore, consentendoti di creare una cronologia dei commit pulita e ben strutturata nei tuoi progetti.

Perché è importante una cronologia dei commit ben strutturata? Immagina il contrario: una cronologia dei commit difficile da leggere, dove non hai idea di cosa i tuoi colleghi effettivamente abbiano fatto con i loro recenti cambiamenti. Sempre più “angoli oscuri” iniziano a emergere in un progetto del genere, e capisci solo le piccole parti che hai lavorato tu stesso.

Contrasta questo con una cronologia dei commit pulita e ben strutturata: aiuta a rendere il codice di un progetto più leggibile e più facile da capire. Questa è una componente essenziale per un progetto sano e duraturo!

Cosa può fare per te l’Interattivo Rebase

L’Interattivo Rebase ti aiuta a ottimizzare e pulire la tua cronologia dei commit. Copre molti diversi casi d’uso, alcuni dei quali ti consentono di fare quanto segue:

  • modificare un messaggio di commit vecchio
  • eliminare un commit
  • unire/combinare più commit
  • riordinare i commit
  • riparare vecchi commit
  • suddividere/riaprire vecchi commit per la modifica

Quando Usare il Rebase Interattivo (e Quando No!)

Come alcuni altri strumenti di Git, il rebase interattivo “riscrive la storia”. Ciò significa che, quando manipoli una serie di commit utilizzando il rebase interattivo, questa parte della tua storia dei commit sarà riscritta: i codici SHA-1 dei commit saranno cambiati. Sono completamente nuovi oggetti di commit, per così dire.

Questo fatto richiede una semplice ma importante regola da seguire: non usare il rebase interattivo (o altri strumenti che riscrivono la storia) su commit che hai già condiviso con i tuoi colleghi in un repository remoto. Invece, usa questo strumento per pulire i tuoi commit locali, come in una delle tue proprie feature branches, prima di integrarli in una branch di squadra.

Il Meccanismo Base di un’Operazione di Rebase Interattivo

Sebbene ci siano molte cose diverse che il rebase interattivo può fare, il flusso di lavoro base è sempre lo stesso. Una volta che hai compreso fermamente questo meccanismo base, il rebase interattivo perderà il suo aspetto di “complessa misteriosità” e diventerà un elemento prezioso e accessibile nel tuo cinturino degli strumenti.

Passo 1: Da dove iniziare la sessione?

La prima domanda che devi rispondere è: “Quale parte della mia storia dei commit voglio manipolare?” Questo ti dice da dove dovresti iniziare la tua sessione di rebase interattivo. Facciamo un esempio pratico e diciamo che vorremmo modificare un messaggio di commit vecchio (che è ciò che faremo effettivamente in pratica tra poco).

La nostra situazione iniziale è illustrata di seguito, dove stiamo modificando un messaggio di commit vecchio tramite rebase interattivo.

Per poter cambiare il messaggio di commit in C2, dobbiamo iniziare la nostra sessione di rebase interattivo dal suo commit genitore (o anche prima, se si vuole). In questo caso specifico, useremmo C1 come punto di partenza per la nostra sessione di rebase interattivo.

Passo 2: inizio della sessione vera e propria!

Iniziare la sessione vera e propria è abbastanza semplice:

$ git rebase -i HEAD~3

Stiamo utilizzando il comando git rebase con la bandiera -i (per indicare che vogliamo che sia effettivamente “interattivo”) e forniamo il commit base (che abbiamo identificato nel nostro primo passo sopra). In questo esempio, ho utilizzato HEAD~3 per specificare il commit che è “3 indietro rispetto al commit HEAD”. In alternativa, avrei potuto fornire un hash SHA-1 specifico.

Passo 3: dicendo a Git cosa si desidera fare

Dopo aver avviato la sessione di rebase interattivo, verrà presentato un editor di testo dove Git elenca una serie di commit — dall’ultimo commit fino a (ma non inclusa) quella che si è scelta come commit base nel Passo 1.

Ci sono due cose importanti da tenere a mente in questo passo:

  1. I commit sono elencati in ordine inverso! L’ultimo commit, che ci aspetteremmo di vedere in cima, apparirà in fondo all’elenco. Non preoccuparti: il tuo repository Git è in perfetta forma! 🥳 Ricorda che stiamo eseguendo un’operazione di rebase interattivo, e ciò richiede a Git di riapplicare i commit dall’ultimo al più recente alla fine dell’operazione.
  2. Non apportare le tue modifiche effettive in questa finestra di editor! Sebbene potresti avere la tentazione di procedere e modificare il messaggio di commit in questa finestra di editor (dopo tutto, è quello che effettivamente vogliamo fare…), devi mostrare un po’ di pazienza. Qui, stiamo solo andando a dire a Git cosa vogliamo fare — ma non apportare la modifica effettiva. Illustrerò questo punto praticamente tra poco!

Ora che abbiamo chiarito questa panoramica teorica, immergiamoci insieme in alcuni casi pratici!

Modifica di un Messaggio di Commit Vecchio

Uno dei casi d’uso molto popolari dell’interattivo rebase è che puoi modificare un messaggio di commit vecchio successivamente. Potresti sapere che git commit --amend ti permette anche di cambiare il messaggio di un commit — ma solo se è il commit più recente. Per qualsiasi commit più vecchio di quello, dobbiamo usare il rebase interattivo!

Diamo un’occhiata a uno scenario concreto. Di seguito è riportata un’immagine di un cattivo messaggio di commit che deve essere corretto.

Nota: Per una migliore panoramica e una visualizzazione più chiara, sto usando il client desktop Tower Git in alcuni dei miei screenshot. Non è necessario Tower per seguire questo tutorial.

Per il nostro esempio, diciamo che vorremmo modificare il messaggio del commit attualmente intitolato “Ottimizzare la struttura di markup in index…”

Il nostro primo passo è determinare il commit base per iniziare questa sessione di rebase interattivo. Poiché dobbiamo (almeno) tornare al genitore del nostro “commit cattivo”, iniziamo la nostra sessione a HEAD~3 (tre commit dietro al commit HEAD, che è quello intitolato “Modifica titoli…”):

$ git rebase -i HEAD~3

Subito dopo aver eseguito questo comando, il tuo editor preferito si aprirà e presenterà l’elenco dei commit che hai appena selezionato (fornendo un commit base).

Come promemoria: anche se potresti essere tentato di farlo, noi non cambiamo il messaggio del commit qui. Noi solo segnaliamo la riga corrispondente con un “parola chiave azione”. In questo caso, vogliamo riscrivere il commit (il che significa che vorremmo modificare il messaggio del commit, ma lasciare il resto del commit invariato).

Praticamente, tutte le parole chiave azione disponibili sono documentate nella parte inferiore di questa finestra, quindi non c’è bisogno di ricordare nulla a memoria!

Una volta sostituita la parola chiave standard pick (che significa “prendere il commit così com’è”) con la tua parola chiave azione preferita, puoi semplicemente salvare e chiudere la finestra.

Dopo averlo fatto, si aprirà una nuova finestra di editor che contiene il messaggio del commit attuale. Infine, siamo autorizzati a fare ciò che abbiamo intenzione di fare in primo luogo: modificare questo vecchio messaggio del commit!

Dopo aver apportato la nostra modifica e poi aver salvato e chiuso la finestra dell’editor, la sessione di rebase interattivo è completa e il nostro messaggio del commit è aggiornato! 🎉

Eliminazione di un Commit Indesiderato

Interactive rebase ti consente anche di eliminare un vecchio commit dalla tua storia che non ti serve (o vuoi) più. Immagina di aver accidentalmente incluso una password personale in un recente commit: informazioni sensibili come questa, in molti casi, non dovrebbero essere incluse in un codebase.

Ricorda anche che semplicemente eliminare le informazioni e committare di nuovo non risolve veramente il tuo problema: ciò significherebbe che la password è ancora salvata nel repository, sotto forma del tuo vecchio commit. Ciò che vuoi veramente è eliminare pulitamente e completamente questa informazione dal repository!

Iniziamo determinando il commit base per la nostra sessione di rebase interattivo. Poiché abbiamo bisogno di partire almeno dal genitore del commit problematico, usiamo il commit “Optimize markup structure…” come base:

$ git rebase -i 6bcf266b

Nota che, questa volta, ho usato un hash SHA-1 concreto nel comando git rebase -i. Invece del hash del commit, ovviamente, avrei potuto usare HEAD~2 per riferirmi a quel commit.

Dopo aver eseguito questo comando, ci viene presentata una lista di commit.

Questa volta, usiamo la parola chiave azione drop per sbarazzarci del commit indesiderato. In alternativa, in questo caso speciale, potremmo anche semplicemente eliminare l’intera riga dall’editor. Se una riga (che rappresenta un commit) non è più presente quando si salva e si chiude la finestra, Git eliminerà il commit corrispondente.

Comunque tu scelga di farlo, dopo aver salvato e chiuso la finestra dell’editor, il commit sarà eliminato dalla storia del tuo repository!

Combinare Più Commit in Uno

Un altro caso d’uso per il rebase interattivo si verifica quando si desidera combinare più commit separati in uno solo. Prima di addentrarci in come funziona, dedicheremo alcuni momenti a parlare di quando o perché questo potrebbe avere valore.

In generale, rendere i commit “più grandi” (combinando più in uno) non è una buona strategia nella maggior parte dei casi. La regola pratica è mantenere i commit il più piccoli possibile, perché “piccoli” significa “più facili da leggere e capire”. Tuttavia, ci sono situazioni in cui questo può avere senso. Ecco due esempi:

  • Immagina di aver notato un problema in un commit più vecchio. Potresti procedere e produrre un nuovo commit che risolve il problema. In una situazione del genere, essere in grado di combinare questi commit in uno solo ha molto senso: il commit più recente, dopotutto, era solo un “cerotto” per risolvere un problema che non avrebbe dovuto esistere in primo luogo. Combinando questi commit, sembra che il problema non sia mai esistito!
  • Un altro esempio è quando ti accorgi di aver reso le cose un po’ troppo granulari. Fare commit piccoli è tutto buono, ma sporcare la tua cronologia dei commit con molti piccoli inutilmente significherebbe eccedere nel bersaglio.

Il ragionamento è lo stesso in entrambi gli esempi: combinando due (o più) commit che originariamente avrebbero dovuto essere uno solo, si produce una cronologia dei commit più pulita e leggibile!

Analizziamo insieme un esempio pratico e prendiamo la situazione raffigurata di seguito come punto di partenza.

Diciamo che, semanticamente, avrebbe più senso che questi due commit fossero un unico commit. Utilizzando lo strumento squash di rebase interattivo, possiamo effettivamente combinarli:

$ git rebase -i HEAD~3

Da ora, sei già abituato a cosa succede dopo: si apre una finestra di editor con un elenco di commit.

I already mentioned that we’re going to use the squash action keyword in this case. There’s an important thing to know about how squash works: the line you mark up with the keyword will be combined with the line directly above! This explains why I marked line 2 with the squash keyword in our example.

Dopo aver salvato e chiuso questa finestra, ne verrà aperta una nuova. Questo perché, combinando più commit, stiamo naturalmente creando un nuovo commit. E anche questo ha bisogno di un messaggio di commit, come qualsiasi altro commit!

Ciò che vedi nella schermata sopra è ciò che Git ci ha preparato: ha combinato i messaggi di commit delle rispettive commit originali insieme a qualche commento. Sei libero di eliminare i vecchi messaggi e iniziare da capo – oppure mantenerli e aggiungere ulteriori informazioni.

Dopo aver salvato e chiuso questa finestra di editor, possiamo dire orgogliosamente: ciò che era due commit separati ora è un unico commit!

Sfruttare il Potere del Rebase Interattivo

I hope you agree that Git’s interactive rebase tools can be very valuable! As developers, it’s important for us to strive for a clean and clear commit history. It’s a crucial ingredient in keeping a codebase healthy and easy to understand (both for your teammates, and yourself, after some time has passed).

Se vuoi saperne di più, ti consiglio vivamente il “Kit di Pronto Soccorso per Git”. È una raccolta (gratuita) di brevi video che ti mostrano come ripulire e annullare errori in Git.

Buon divertimento!

Domande Frequenti (FAQs) sul Rebase Interattivo di Git

Qual è la differenza tra Git Rebase e Git Merge?

Git Rebase e Git Merge sono due modi diversi per integrare modifiche da un ramo in un altro. Git Merge è un modo semplice per combinare il codice di due rami diversi. Crea un nuovo commit nella storia, preservando l’ordine cronologico dei commit. D’altra parte, Git Rebase è un modo per spostare o combinare una sequenza di commit in un nuovo commit base. È come dire “Voglio basare le mie modifiche su ciò che tutti gli altri hanno fatto”. In altre parole, ti permette di posizionare le modifiche dal ramo attuale in cima a un altro ramo.

Come posso annullare un Git Rebase?

Se vuoi annullare un Git Rebase, puoi usare il comando git reflog per trovare il commit a cui vuoi tornare, e poi usare il comando git reset --hard HEAD@{numero}. Il comando git reflog mostra un elenco di ogni modifica apportata alla HEAD, e il comando git reset ti permette di impostare la HEAD corrente nello stato specificato.

Qual è lo scopo di Git Interactive Rebase?

Git Interactive Rebase ti consente di alterare i commit in molti modi, come modificare, eliminare e unire. Non solo puoi cambiare il messaggio di commit, ma puoi anche cambiare il codice effettivo se hai fatto un errore. È uno strumento potente che ti dà il completo controllo sulla storia dei commit del tuo progetto.

Come posso unire i commit usando Git Interactive Rebase?

Lo squash è l’atto di combinare diversi commit in uno solo. In Git, puoi squashare i commit utilizzando il comando git rebase -i seguito dall’hash del commit che desideri squashare. Nel text editor che si apre, puoi contrassegnare i commit che vuoi squashare sostituendo pick con squash o s accanto a ciascun commit.

Quali sono i rischi dell’uso di Git Interactive Rebase?

Sebbene Git Interactive Rebase sia uno strumento potente, può essere pericoloso se non utilizzato correttamente. Riscrive la storia dei commit, il che può essere problematico se stai lavorando su una branch pubblica su cui stanno lavorando anche altri. Si consiglia di usarlo su branch locali che non sono stati ancora spinti.

Come posso risolvere i conflitti durante un Git Rebase?

Durante un rebase, possono verificarsi conflitti. Git si fermerà e ti consentirà di risolvere tali conflitti prima di continuare. Puoi risolvere i conflitti modificando i file per correggere le modifiche in conflitto e quindi aggiungere i file risolti con git add. Dopo aver risolto tutti i conflitti, puoi continuare il rebase con git rebase --continue.

Posso usare Git Interactive Rebase per dividere un commit?

Sì, puoi usare Git Interactive Rebase per dividere un commit in più piccoli. Questo può essere utile se hai apportato diverse modifiche in un singolo commit ma in seguito hai deciso che avrebbero dovuto essere commit separati.

Come posso modificare un messaggio di commit utilizzando Git Interactive Rebase?

Puoi modificare un messaggio di commit durante un rebase interattivo. Nell’elenco dei commit, sostituisci pick con reword o r accanto al commit che desideri modificare. Quando continui, Git aprirà un editor di testo per ogni commit contrassegnato con reword, permettendoti di modificare il messaggio del commit.

Qual è la differenza tra Git Rebase e Git Pull?

Git Pull è un comando che recupera le modifiche da un repository remoto e le unisce alla tua branch corrente. D’altra parte, Git Rebase è un comando che sposta o combina una sequenza di commit in un nuovo commit di base. Sebbene entrambi i comandi siano utilizzati per integrare le modifiche, lo fanno in modi diversi.

Posso usare Git Interactive Rebase per cambiare l’ordine dei commit?

Sì, puoi cambiare l’ordine dei commit utilizzando Git Interactive Rebase. Nell’elenco dei commit, puoi semplicemente cambiare l’ordine delle righe per modificare l’ordine dei commit. Ciò può essere utile se vuoi rendere la tua storia di commit più logica o chiara.

Source:
https://www.sitepoint.com/git-interactive-rebase-guide/