Beginner’s Guide to Interactive Rebasing

Originariamente pubblicato da Stride il 16 gennaio 2018 52,731 letture

All’inizio di quest’anno ho fatto un rebase interattivo per la prima volta e sono rimasto colpito da quello che si può fare con esso. L’ho anche trovato un po’ complesso all’inizio. Speriamo che questa guida aiuti a rimuovere qualche incertezza al riguardo.

Inoltre, poiché è così potente e si può essenzialmente riscrivere la storia, un piccolo avvertimento prima di iniziare: Ci sono molte scuole di pensiero su Git e se il rebasing sia una buona idea o meno. Questo post non si immergerà in queste discussioni ed è puramente inteso a camminare attraverso le basi dell’uso del rebasing interattivo.

TL;DR

  • Il rebasing interattivo può essere usato per cambiare i commit in molti modi come la modifica, la cancellazione e lo squash.
  • Per dire a Git dove iniziare il rebase interattivo, usa lo SHA-1 o l’indice del commit che precede immediatamente il commit che vuoi modificare.
  • Durante un rebase interattivo, quando Git si ferma ad un commit che hai taggato per modificare, il flusso di lavoro non è diverso da un normale processo di commit – metti in scena i file e poi fai il commit. L’unica differenza è che usi il comando git commit --amend piuttosto che git commit.
  • Il rebase interattivo creerà nuovi SHA-1 quindi è meglio usare il rebase interattivo sui commit che non hai spinto su un ramo remoto.

Il problema

In questo esempio, lavoreremo su una situazione in cui abbiamo lavorato in un ramo di funzionalità e abbiamo un paio di commit che vorremmo cambiare o cancellare. Ecco come appare il nostro git log:

Dal git log sopra, ecco i due commit che vogliamo cambiare:
4a4d705 – In questo commit abbiamo accidentalmente commesso un conflitto di fusione
6c01350 – In questo commit abbiamo rimosso il conflitto di fusione

Quello che vorremmo fare è tornare indietro nel tempo a 4a4d705, rimuovere il conflitto di fusione nel commit, poi cancellare 6c01350 poiché il conflitto di fusione è risolto e non abbiamo più bisogno di questo commit. Questo sarà un miglioramento per la nostra storia dei commit per due ragioni:

  1. Non avremo più commit rotti (conflitti di merge)
  2. Avremo solo commit significativi, nessun commit relativo alla sola correzione di un mancato conflitto di merge

La soluzione

Questa situazione è un buon candidato per il rebasing interattivo. Scott Chacon, nel suo libro Pro Git, descrive il rebasing interattivo come segue: “A volte la cosa corretta … non può essere modificata al commit non proprio perfetto che corregge, perché quel commit è sepolto profondamente in una serie di patch. Questo è esattamente ciò a cui serve il rebase interattivo: usalo dopo un sacco di , riorganizzando e modificando i commit, e schiacciando più commit in uno.”

Quali commit vogliamo modificare?

Per iniziare un rebase interattivo, dobbiamo dire a Git quali commit vogliamo modificare. Lo facciamo facendo riferimento al commit immediatamente precedente al primo commit che vogliamo modificare. O, detto semplicemente, facciamo riferimento “all’ultimo commit che vogliamo mantenere così com’è”, secondo Scott Chacon.

Guardiamo il nostro esempio per capire meglio. Ci sono due modi per fare riferimento a questo commit:
By SHA-1 – L’ultimo commit che vogliamo mantenere as-is ha un SHA-1 di 528f82equindi possiamo passarlo nel nostro comando interattivo rebase.
By Index – L’ultimo commit che vogliamo mantenere as-is ha una posizione di indice di 3 (Git usa un’indicizzazione basata su zero) quindi possiamo passare HEAD~3 al nostro comando di rebase interattivo.

Nota – Se hai solo pochi commit su cui fare il rebase interattivo, usare l’indice è probabilmente più facile per la maggior parte delle persone. Tuttavia, se hai molti commit, usare lo SHA-1 è probabilmente più facile in modo da non dover contare fino in fondo al registro git.

Avvia il rebasing interattivo

In base al nostro esempio, eseguiremo o:

$ git rebase -i 528f82e

Oppure

$ git rebase -i HEAD~3

che apre questa finestra in Vim:

Nota che i commit sono nell’ordine opposto di git log. In git log il commit più recente è in cima. In questa vista, il commit più recente è in basso. Notate anche che i commenti sotto danno un utile elenco dei comandi validi che possiamo usare su ogni commit.

Se non conoscete Vim, cliccate semplicemente su ogni parola pick che volete modificare e poi premete il tasto <i> (per la modalità inserimento). Una volta che hai finito di scrivere premi il tasto <esc> per uscire dalla modalità di inserimento.

Nel nostro esempio, abbiamo cambiato il comando in edit per il commit che vogliamo modificare e abbiamo cambiato il comando in drop per il commit che vogliamo cancellare. Poi eseguiamo :wq per salvare ed uscire dalla finestra Vim.

Modifica il commit

Nel terminale vediamo questo messaggio:

Questo ha senso perché siamo fermi a 4a4d705. Questo è il commit più vecchio nella serie di commit che vogliamo modificare. Inizieremo con questo commit e ci faremo strada attraverso ogni commit fino al più recente.

Come promemoria, 4a4d705 era il commit con il conflitto di fusione che abbiamo accidentalmente commesso. Quando apriamo il nostro editor vediamo il conflitto di fusione lì:

Quindi sistemiamo il conflitto di fusione nel file ma cosa facciamo ora? Nel dubbio, git status:

Fico! Questo è effettivamente utile. Vediamo che stiamo attualmente modificando 4a4d705, e vediamo i prossimi due commit su cui agire dopo questo.

Il resto del messaggio ci sta spiegando un flusso di lavoro familiare. Git ci dice che se vogliamo modificare il commit eseguiamo git commit --amend. Questo agirà essenzialmente come il nostro tipico git commit che usiamo in un normale flusso di lavoro. In fondo a questo messaggio vediamo che il nostro file è stato modificato riflettendo le modifiche che abbiamo appena fatto per rimuovere il conflitto di merge. Abbiamo bisogno di mettere in scena il file prima di fare il commit. Questo non è diverso da un normale flusso di lavoro.

Tutto quello che facciamo è git add tempChanger.js per mettere in scena il file modificato e poi git commit --amend per impegnare il file messo in scena! Questo aprirà di nuovo una finestra Vim con il messaggio di commit:

Possiamo modificare il messaggio di commit o lasciarlo così com’è. Scegliamo di mantenere il messaggio di commit lo stesso e digitiamo :wq per salvare e uscire dalla finestra.

Abbiamo modificato il nostro vecchio commit. E adesso? Esegui git status:

Continua il rebase interattivo

Non abbiamo altro da cambiare nel commit quindi continuiamo!

Eseguiamo git rebase --continue e vediamo il seguente messaggio:

Woah, abbiamo finito? Ma che dire degli altri due commit? Bene, il prossimo commit su cui agire era 6c01350. Questo commit è stato segnato per essere cancellato (drop) quando abbiamo iniziato il rebase interattivo. Git lo ha cancellato automaticamente e si è spostato sul commit successivo, 41aa9d2. Questo non è mai stato modificato nel rebase interattivo iniziale. Il suo comando di default era pick che significa che il commit sarà usato. Git ha applicato quel commit e dato che era l’ultimo commit, il rebase interattivo è stato completato.

Nota, se avessimo avuto altri commit da modificare, ci saremmo semplicemente spostati sul commit successivo e avremmo iniziato il processo di modifica proprio come abbiamo fatto sopra. Il ciclo continua fino a quando non ci sono più commit.

Il pulsante di espulsione

E’ da notare che se in qualsiasi punto del nostro rebase interattivo facciamo un casino e non sappiamo come sistemarlo, possiamo sempre interrompere. In qualsiasi momento possiamo eseguire git rebase --abort nel terminale e il rebase interattivo verrà interrotto senza che le modifiche vengano salvate. Avremmo quindi bisogno di ricominciare il rebase interattivo da capo.

Dopo il rebase interattivo

Il nostro log git ora assomiglia a:

Si noterà che alcune cose sono cambiate da prima di iniziare il rebase interattivo:

  • Non abbiamo più il commit 6c01350 con il messaggio commit “Remove merge conflict”. Questo è il commit che abbiamo cancellato nel nostro rebase interattivo.
  • Il nostro commit che abbiamo modificato, 4a4d705, ha un diverso SHA-1, 2b7443d.
  • Il nostro commit più recente dal nostro log git originale, 41aa9d2, ha anche un nuovo SHA-1, 2b95e92. Questo commit non è stato cambiato ma è stato semplicemente applicato al commit precedente 2b7443d.

Effetti collaterali del rebasing interattivo

Per i due commit più recenti nel nostro log git, poiché hanno nuovi SHA-1, Git li vede come commit completamente nuovi. Questo è anche vero per il nostro ultimo commit, 2b95e92, dove né il messaggio di commit né i file sono cambiati affatto. Questo porta ad un punto importante con il rebasing interattivo: Se modificate un commit, quel commit e tutti i successivi avranno nuovi SHA-1.

Questo non influenzerà nulla se i commit che avete modificato non sono stati spinti su un ramo remoto. Tuttavia, se hai effettivamente completato un rebase interattivo sui commit che erano già stati spinti su un ramo remoto e poi hai spinto di nuovo il tuo ramo vedrai:

Tecnicamente, potresti aggirare questo usando git push --force ma questo è molto pericoloso. Se il ramo remoto ha i commit di altre persone ma il tuo ramo locale non ha ancora quei commit, cancellerai effettivamente i loro commit.

Un’altra soluzione è usare git push --force-with-lease che modificherà solo i tuoi commit ma non quelli degli altri, sebbene anche questo possa essere problematico. Per esempio, se un altro sviluppatore ha già quei commit che hanno ricevuto nuovi SHA-1 nel suo ramo locale, quando tira il ramo remoto, avrà conflitti di fusione con ognuno di questi commit.

Quando usare --force-with-lease va oltre lo scopo di questo post sul blog, ma sarebbe meglio consultare altri membri del tuo team prima di farlo. Puoi leggere di più su git push --force-with-lease qui.

Il risultato chiave di questa sezione è che è molto più facile e sicuro usare il rebasing interattivo sui commit che non sono stati ancora inviati ad un ramo remoto.

Scritto da Blake DeBoer. Originariamente pubblicato su Dev.to

Senior, Lead, o Principal developer a NYC? Stride sta assumendo! Vuoi migliorare il tuo team tecnico? Guarda come lo facciamo noi! www.stridenyc.com

Tags

Iscriviti a Hacker Noon

Crea il tuo account gratuito per sbloccare la tua esperienza di lettura personalizzata.

Leave a Reply