Una guida per annullare gli errori con Git (Parte 2)

Pubblicato: 2022-03-10
Breve riassunto ↬ Errori. Questi cattivi crudeli non si fermano nemmeno al bellissimo mondo dello sviluppo del software. Ma anche se non possiamo evitare di commettere errori, possiamo imparare a annullarli! Questo articolo mostrerà gli strumenti giusti per il tuo lavoro quotidiano con Git. Potresti voler controllare anche il primo articolo della serie.

In questa seconda parte della nostra serie su "Undoing Mistakes with Git", guarderemo di nuovo coraggiosamente il pericolo negli occhi: ho preparato quattro nuovi scenari apocalittici, inclusi, ovviamente, alcuni modi intelligenti per salvarci il collo! Ma prima di immergerci: dai un'occhiata ai precedenti articoli su Git per ulteriori metodi di autosoccorso che ti aiutano a annullare i tuoi errori con Git!

Andiamo!

Recupero di un ramo cancellato utilizzando il Reflog

Ti è mai capitato di cancellare un ramo e, poco dopo, ti sei reso conto che non avresti dovuto? Nell'improbabile eventualità che tu non conosca questa sensazione, posso dirti che non è una bella sensazione. Un misto di tristezza e rabbia si insinua su di te, mentre pensi a tutto il duro lavoro che è stato dedicato ai commit di quel ramo, a tutto il prezioso codice che ora hai perso.

Fortunatamente, c'è un modo per riportare indietro quel ramo dalla morte, con l'aiuto di uno strumento Git chiamato "Reflog". Abbiamo usato questo strumento nella prima parte della nostra serie, ma ecco un piccolo aggiornamento: Reflog è come un diario in cui Git annota ogni movimento del puntatore HEAD nel tuo repository locale. In altre parole meno nerd: ogni volta che esegui il checkout, il commit, l'unione, il rebase, il cherry-pick e così via, viene creata una voce di diario. Questo rende il Reflog una rete di sicurezza perfetta quando le cose vanno male!

Diamo un'occhiata a un esempio concreto:

 $ git branch * feature/login master

Possiamo vedere che al momento abbiamo verificato la nostra feature/login al ramo. Diciamo che questo è il ramo che cancelleremo (inavvertitamente). Prima di poterlo fare, tuttavia, dobbiamo passare a un ramo diverso perché non possiamo eliminare il nostro ramo HEAD corrente!

 $ git checkout master $ git branch -d feature/login

Il nostro prezioso ramo di funzionalità ora è andato - e ti darò un minuto per (a) capire la gravità del nostro errore e (b) per piangere un po'. Dopo che avrai asciugato le lacrime, dobbiamo trovare un modo per riportare indietro questo ramo! Apriamo il Reflog (semplicemente digitando git reflog ) e vediamo cosa ha in serbo per noi:

Git's Reflog registra tutte le azioni principali nel nostro repository locale
Git's Reflog protocolla tutte le azioni principali nel nostro repository locale. (Grande anteprima)

Ecco alcuni commenti per aiutarti a dare un senso all'output:

  • Prima di tutto, devi sapere che il Reflog ordina le sue voci in ordine cronologico: le voci più recenti sono in cima alla lista.
  • L'elemento più in alto (e quindi il più recente) è il comando git checkout che abbiamo eseguito prima di eliminare il ramo. È registrato qui nel Reflog perché è uno di questi "movimenti del puntatore HEAD" che il Reflog registra così diligentemente.
  • Per annullare il nostro grave errore, possiamo semplicemente tornare allo stato precedente , che è anche registrato in modo pulito e chiaro nel Reflog!

Quindi proviamo questo, creando un nuovo ramo (con il nome del nostro ramo "perso") che inizia con questo hash SHA-1 dello stato "prima":

 $ git branch feature/login 776f8ca

E voilà! Sarai felice di vedere che ora abbiamo ripristinato il nostro ramo apparentemente perduto!

Se stai usando una GUI desktop Git come "Tower", puoi prendere una bella scorciatoia: premi semplicemente CMD + Z sulla tastiera per annullare l'ultimo comando, anche se hai appena eliminato violentemente un ramo!

Una GUI desktop come Tower può semplificare il processo di annullamento degli errori.
Altro dopo il salto! Continua a leggere sotto ↓

Spostamento di un commit in un ramo diverso

In molti team c'è un accordo per non impegnarsi su rami di lunga durata come main o develop : rami come questi dovrebbero ricevere nuovi commit solo attraverso integrazioni (ad esempio unioni o rebase). Eppure, certo, gli errori sono inevitabili: a volte dimentichiamo e ci impegniamo comunque su questi rami! Quindi, come possiamo ripulire il pasticcio che abbiamo creato?

Spostare un commit nel ramo di destinazione corretto
Il nostro commit è arrivato sul ramo sbagliato. Come possiamo spostarlo nel ramo di destinazione corretto? (Grande anteprima)

Fortunatamente, questi tipi di problemi possono essere facilmente corretti. Rimbocchiamoci le maniche e mettiamoci al lavoro.

Il primo passo è passare al ramo di destinazione corretto e quindi spostare il commit utilizzando il comando cherry-pick :

 $ git checkout feature/login $ git cherry-pick 776f8caf

Ora avrai il commit sul ramo desiderato, dove avrebbe dovuto essere in primo luogo. Stupendo!

Ma c'è ancora una cosa da fare: dobbiamo ripulire il ramo dove è caduto accidentalmente all'inizio! Il comando cherry-pick , per così dire, ha creato una copia del commit, ma l'originale è ancora presente sul nostro ramo di lunga data:

Una copia del commit sul ramo corretto, ma l'originale risulta essere ancora sul ramo sbagliato
Abbiamo creato con successo una copia del commit sul ramo corretto, ma l'originale è ancora qui, sul ramo sbagliato. (Grande anteprima)

Ciò significa che dobbiamo tornare al nostro ramo di lunga data e utilizzare git reset per rimuoverlo:

 $ git checkout main $ git reset --hard HEAD~1

Come puoi vedere, stiamo usando il comando git reset qui per cancellare il commit errato. Il parametro HEAD~1 dice a Git di "tornare indietro di 1 revisione dietro HEAD", cancellando efficacemente il commit più alto (e nel nostro caso: indesiderato) dalla cronologia di quel ramo.

E voilà: il commit è ora dove avrebbe dovuto essere in primo luogo e il nostro ramo di lunga data è pulito, come se il nostro errore non fosse mai accaduto!

Modifica del messaggio di un vecchio commit

È fin troppo facile contrabbandare un errore di battitura in un messaggio di commit e scoprirlo solo molto più tardi. In tal caso, la buona vecchia opzione --amend di git commit non può essere utilizzata per risolvere questo problema, perché funziona solo per l'ultimo commit. Per correggere qualsiasi commit più vecchio di quello, dobbiamo ricorrere a uno strumento Git chiamato "Interactive Rebase".

Un messaggio di commit che vale la pena cambiare
Ecco un messaggio di commit che vale la pena cambiare. (Grande anteprima)

Innanzitutto, dobbiamo dire a Interactive Rebase quale parte della cronologia dei commit vogliamo modificare. Questo viene fatto alimentandolo con un hash di commit: il commit genitore di quello che vogliamo manipolare.

 $ git rebase -i 6bcf266b

Si aprirà quindi una finestra dell'editor. Contiene un elenco di tutti i commit dopo quello che abbiamo fornito come base per Interactive Rebase nel comando:

Mostra l'intervallo di commit che abbiamo selezionato per la modifica nella nostra sessione Interactive Rebase
La gamma di commit che abbiamo selezionato per la modifica nella nostra sessione Interactive Rebase. (Grande anteprima)

Qui, è importante che tu non segua il tuo primo impulso: in questo passaggio, non modifichiamo ancora il messaggio di commit. Invece, diciamo a Git solo che tipo di manipolazione vogliamo fare con quale(i) commit. Abbastanza convenientemente, c'è un elenco di parole chiave di azione annotate nei commenti nella parte inferiore di questa finestra. Nel nostro caso, contrassegniamo la riga n. 1 con reword (sostituendo così lo standard pick ).

Tutto ciò che resta da fare in questo passaggio è salvare e chiudere la finestra dell'editor. In cambio, si aprirà una nuova finestra dell'editor che contiene il messaggio corrente del commit che abbiamo contrassegnato. E ora è finalmente il momento di apportare le nostre modifiche!

Ecco l'intero processo a colpo d'occhio per te:

Utilizzo di Interactive Rebase per modificare il messaggio di un vecchio commit, dall'inizio alla fine.

Correzione di un impegno interrotto (in modo molto elegante)

Infine, daremo un'occhiata a fixup , il coltellino svizzero degli strumenti di annullamento. In parole povere, ti consente di correggere un commit interrotto/incompleto/errato dopo il fatto. È davvero uno strumento meraviglioso per due motivi:

  1. Non importa quale sia il problema.
    Potresti aver dimenticato di aggiungere un file, avresti dovuto eliminare qualcosa, apportare una modifica errata o semplicemente un errore di battitura. fixup funziona in tutte queste situazioni!
  2. È estremamente elegante.
    La nostra reazione normale e istintiva a un bug in un commit è produrre un nuovo commit che risolva il problema. Questo modo di lavorare, per quanto intuitivo possa sembrare, rende la cronologia dei commit molto caotica, molto presto. Hai commit "originali" e poi questi piccoli commit "bandaid" che risolvono le cose che sono andate storte nei commit originali. La tua storia è disseminata di piccoli e insignificanti impegni di cerotto che rendono difficile capire cosa è successo nella tua base di codice.
La cronologia dei tuoi commit può essere molto difficile da leggere se correggi costantemente piccoli errori con i cosiddetti commit cerotti
Correggere costantemente piccoli errori con "commissioni di cerotto" rende molto difficile leggere la cronologia dei tuoi commit. (Grande anteprima)

È qui che entra in gioco la fixup . Ti consente ancora di eseguire questo commit di correzione del cerotto. Ma ecco che arriva la magia: quindi lo applica al commit originale, rotto (riparandolo in questo modo) e quindi scarta completamente il brutto commit del cerotto!

Fixup applica le tue correzioni al commit originale e quindi elimina il commit superfluo del cerotto
Fixup applica le tue correzioni al commit originale e quindi elimina il commit superfluo del cerotto. (Grande anteprima)

Possiamo fare insieme un esempio pratico! Diciamo che il commit selezionato qui è rotto.

Correzione del commit errato selezionato in modo elegante
Il commit selezionato non è corretto e lo sistemeremo in modo elegante. (Grande anteprima)

Diciamo anche che ho preparato delle modifiche in un file chiamato error.html che risolverà il problema. Ecco il primo passo che dobbiamo fare:

 $ git add error.html $ git commit --fixup 2b504bee

Stiamo creando un nuovo commit, ma stiamo dicendo a Git che questo è speciale: è una correzione per un vecchio commit con l'hash SHA-1 specificato ( 2b504bee in questo caso).

Il secondo passaggio, ora, è avviare una sessione di Interactive Rebase, perché la fixup appartiene al grande set di strumenti di Interactive Rebase.

 $ git rebase -i --autosquash 0023cddd

Vale la pena spiegare due cose su questo comando. Innanzitutto, perché ho fornito 0023cddd come hash di revisione qui? Perché dobbiamo iniziare la nostra sessione Interactive Rebase al commit genitore del nostro compagno rotto.

Secondo, a cosa serve l'opzione --autosquash ? Ci vuole molto lavoro dalle nostre spalle! Nella finestra dell'editor che ora si apre, tutto è già pronto per noi:

La finestra della sessione Interactive Rebase
La finestra della sessione Interactive Rebase (Anteprima grande)

Grazie all'opzione --autosquash , Git ha già fatto il lavoro pesante per noi:

  1. Ha contrassegnato il nostro piccolo impegno di cerotto con la parola chiave azione di fixup . In questo modo, Git lo combinerà con il commit direttamente sopra e quindi lo scarterà.
  2. Ha anche riordinato le righe di conseguenza, spostando il nostro commit cerotto direttamente sotto il commit che vogliamo correggere (di nuovo: la fixup funziona combinando il commit contrassegnato con quello sopra !).

Insomma: per noi non c'è altro da fare che chiudere la finestra!

Diamo un'ultima occhiata al risultato finale.

  • Il commit precedentemente interrotto è stato corretto: ora contiene le modifiche che abbiamo preparato nel nostro commit band-aid.
  • Il brutto commit stesso è stato scartato: la cronologia dei commit è pulita e facile da leggere, come se non si fosse verificato alcun errore.
Un esempio di come appare una cronologia di commit puliti
Il risultato finale dopo aver utilizzato lo strumento di correzione: una cronologia di commit pulita! (Grande anteprima)

Sapere come annullare gli errori è un superpotere

Congratulazioni! Ora puoi salvarti il ​​collo in molte situazioni difficili! Non possiamo davvero evitare queste situazioni: non importa quanto siamo esperti come sviluppatori, gli errori fanno semplicemente parte del lavoro. Ma ora che sai come affrontarli, puoi affrontarli con una frequenza cardiaca rilassata.

Se vuoi saperne di più sull'annullamento degli errori con Git, posso consigliarti il ​​"Kit di pronto soccorso per Git" gratuito, una serie di brevi video su esattamente questo argomento.

Divertiti a commettere errori e, naturalmente, a annullarli con facilità!