Come (e perché!) Mantenere pulita la cronologia dei commit Git

I commit sono una delle parti chiave di un repository Git, e ancora di più, il messaggio di commit è un registro di vita per il repository. Man mano che il progetto / repository si evolve nel tempo (nuove funzionalità vengono aggiunte, bug risolti, architettura rifattorizzata), i messaggi di commit sono il luogo in cui è possibile vedere cosa è stato modificato e come. Quindi è importante che questi messaggi riflettano la modifica sottostante in modo breve e preciso.

Perché una cronologia di commit Git significativa è importante

Cosa fa Git commit? Messaggi di Git commit sono le impronte digitali che lasci sul codice che tocchi. Qualsiasi codice che effettui oggi, tra un anno in cui guardi lo stesso cambiamento; saresti grato per un messaggio di commit chiaro e significativo che hai scritto, e lo sarà anche semplifica la vita dei tuoi colleghi sviluppatori. Quando i commit sono isolati in base al contesto, un bug introdotto da un certo commit diventa più veloce da trovare e più facile è annullare il commit che ha causato il bug in primo luogo.

Mentre lavoriamo a un progetto di grandi dimensioni, spesso ci occupiamo di molte parti in movimento che vengono aggiornate, aggiunte o rimosse. Garantire che i messaggi di commit vengano mantenuti in questi casi potrebbe essere complicato, soprattutto quando lo sviluppo si estende su più giorni, settimane, o anche mesi, quindi per semplificare lo sforzo di mantenere conciso Per eseguire il commit della cronologia, questo articolo utilizzerà alcune delle situazioni comuni che uno sviluppatore potrebbe dover affrontare mentre lavora su un repository Git.

  • Situazione 1: devo modificare il commit più recente
  • Situazione 2: devo modificare un commit specifico
  • Situazione 3: devo aggiungere, rimuovere o combinare i commit
  • Situazione 4: la cronologia dei miei commit non funziona senso, ho bisogno di un nuovo inizio!

Ma prima di immergerci, vediamo rapidamente come appare un tipico flusso di lavoro di sviluppo in una nostra ipotetica applicazione Ruby.

Nota: questo articolo presume che tu sia a conoscenza delle basi di Git, di come funzionano i rami, come aggiungere modifiche non salvate di un ramo allo stage e come eseguire il commit delle modifiche. Se non sei sicuro di questi flussi, la nostra documentazione è un ottimo punto di partenza.

Un giorno nella vita

Qui stiamo lavorando a un piccolo progetto Ruby on Rails in cui è necessario aggiungere una visualizzazione di navigazione sulla home page e ciò comporta laggiornamento e laggiunta di diversi file. Di seguito è riportata unanalisi dettagliata dellintero flusso:

  • Inizi a lavorare su una funzione aggiornando un file ; let “s call it application_controller.rb
  • Questa funzione richiede di aggiornare anche una vista: index.html.haml
  • Hai aggiunto un parziale che viene utilizzato nella pagina dellindice: _navigation.html.haml
  • Anche gli stili della pagina devono essere aggiornati per riflettere il parziale che abbiamo aggiunto: styles.css.scss
  • La funzionalità è ora pronta con le modifiche desiderate, è ora di aggiornare anche i test; i file da aggiornare sono i seguenti:
    • application_controller_spec.rb
    • navigation_spec.rb
  • I test vengono aggiornati e passano come previsto, ora è il momento di eseguire il commit delle modifiche!

Poiché tutti i file appartengono a diversi territori dellarchitettura, ci impegniamo le modifiche isolate luna dallaltra per garantire che ogni commit rappresenti un determinato contesto e venga eseguito in un certo ordine. Di solito preferisco il backend – > ordine del frontend in cui la maggior parte delle modifiche incentrate sul backend viene salvata per prima, seguito dal livello intermedio e poi dalle modifiche incentrate sul frontend nellelenco Git.

Ora che abbiamo eseguito il commit delle modifiche, creiamo una richiesta di unione con il ramo. Una volta che la richiesta di unione è aperta, in genere viene esaminata dal tuo peer prima che le modifiche vengano unite nel ramo master del repository. Ora impariamo in quali diverse situazioni potremmo trovarci durante la revisione del codice.

Situazione 1: devo modificare il commit più recente

Immagina un caso in cui il revisore ha esaminato styles.css.scss e ha suggerito una modifica. In tal caso, è molto semplice fare la modifica poiché le modifiche al foglio di stile fanno parte dellultimo commit sul tuo ramo. Ecco come possiamo gestirlo;

  • Apporti direttamente le modifiche necessarie a styles.css.scss nel tuo ramo.
  • Una volta hai finito con le modifiche, aggiungi queste modifiche allo stage; eseguire git add styles.css.scss.
  • Una volta che le modifiche sono state organizzate, dobbiamo aggiungerle al nostro ultimo commit; eseguire git commit --amend.
    • Analisi dei comandi: qui, stiamo chiedendo al comando git commit di modificare le modifiche presenti stage al commit più recente.
  • Questo aprirà il tuo ultimo commit nel tuo editor di testo definito da Git che ha il messaggio di commit Aggiungi stili per la navigazione.
  • Dato che abbiamo aggiornato solo la dichiarazione CSS, non abbiamo bisogno di alterare il messaggio di commit.A questo punto, puoi semplicemente salvare e uscire dalleditor di testo che Git ha aperto per te e le tue modifiche si rifletteranno nel commit.

Dato che hai modificato un commit esistente, queste modifiche sono necessarie da forzare al tuo repository remoto utilizzando git push --force-with-lease <remote_name> <branch_name>. Questo comando sovrascriverà il commit Add styles for navigation sul repository remoto con il commit aggiornato che abbiamo appena fatto nel nostro repository locale.

Una cosa da tenere a mente mentre si forza il push dei rami è che se stai lavorando sullo stesso ramo con più persone, il push forzato può causare problemi ad altri utenti quando provano normalmente a inviare le loro modifiche su un ramo remoto che ha nuovi commit forzati. Quindi, usa questa funzione con saggezza. Puoi saperne di più sulle opzioni push di Git force qui.

Situazione 2: ho bisogno di cambiare un commit specifico

Nella situazione precedente, la correzione era piuttosto semplice perché dovevamo modificare solo il nostro ultimo commit Git, ma immagina se il revisore suggerisse di cambiare qualcosa in _navigation.html.haml. In questo caso, è il secondo commit dallinizio, quindi cambiarlo non sarà così diretto come nella prima situazione. Vediamo come possiamo gestirlo:

Ogni volta che viene eseguito un commit realizzato in un ramo, è identificato da una stringa hash SHA1 univoca. Consideralo come un ID univoco che separa un commit da un altro. Puoi visualizzare tutti i commit, insieme ai relativi hash SHA1 in un ramo, eseguendo git log. Con questo, vedresti un output che appare in qualche modo come segue, dove i commit più recenti sono in cima;

È qui che entra in gioco il comando git rebase. Ogni volta che desideriamo modificare un commit specifico con git rebase, dobbiamo prima rebase il nostro ramo spostando indietro HEAD al punto immediatamente prima del commit che desideriamo modificare. Nel nostro caso, dobbiamo modificare il commit che legge Page Navigation View.

Qui, nota lhash del commit che si trova subito prima del commit che vogliamo modificare; copiare lhash ed eseguire i seguenti passaggi:

  • Rebase il ramo da spostare in commit prima del commit di destinazione; eseguire git rebase -i 8d74af102941aa0b51e1a35b8ad731284e4b5a20
    • Analisi dei comandi: qui “stiamo eseguendo il comando rebase di Git con la modalità interattiva con hash SHA1 fornito come commit su cui rebase.
  • Questo eseguirà il comando rebase per Git in modalità interattiva e aprirà il tuo editor di testo mostrando tutti i tuoi commit che sono arrivati dopo il commit a cui hai ribasato . Sarà simile a questo:

Nota come ogni commit ha una parola pick davanti e nei contenuti sottostanti, ci sono tutte le possibili parole chiave che possiamo usare. Dato che vogliamo modificare un commit, dobbiamo cambiare pick 4155df1cdc7 Page Navigation View in edit 4155df1cdc7 Page Navigation View. Salva le modifiche ed esci dalleditor.

Ora il tuo ramo è ribasato al punto giusto prima del commit che hai fatto che includeva _navigation.html.haml. Apri il file ed esegui le modifiche desiderate secondo il feedback della recensione. Una volta che hai finito con le modifiche, posizionale eseguendo git add _navigation.html.haml.

Dato che abbiamo messo in scena le modifiche, è tempo di spostare il ramo HEAD di nuovo nella commit che avevamo originariamente (includendo anche le nuove modifiche che abbiamo aggiunto), esegui git rebase --continue, questo aprirà il tuo editor predefinito nel terminale e ti mostrerà il messaggio di commit che abbiamo modificato durante il rebase; Page Navigation View. Puoi modificare questo messaggio se lo desideri, ma per ora lo lasceremo così comè, quindi salva ed esci dalleditor. A questo punto, Git riprodurrà tutti i commit quello seguito dopo il commit che hai appena modificato e ora il branch HEAD è tornato al commit iniziale che avevamo originariamente e include anche le nuove modifiche apportate a uno dei commit.

Dato che abbiamo modificato di nuovo un commit che è già presente nel repository remoto, dobbiamo forzare il push di nuovo di questo ramo usando git push --force-with-lease <remote_name> <branch_name>.

Situazione 3 : Devo aggiungere, rimuovere o combinare i commit

Una situazione comune è quando hai fatto diversi commit solo per aggiustare qualcosa precedentemente commesso. Ora riduciamoli il più possibile, combinandoli con i commit originali.

Tutto quello che devi fare è avviare il rebase interattivo come faresti negli altri scenari.

Ora immagina di voler combinare tutte queste correzioni in c22a3fa0c5c Render navigation partial. Devi solo:

  1. Sposta le correzioni verso lalto in modo che siano proprio sotto il commit che desideri mantenere alla fine.
  2. Cambia pick in squash o fixup per ciascuna delle correzioni.

Nota: squash mantiene i messaggi di commit nella descrizione. fixup dimenticherà i messaggi di commit delle correzioni e manterrà loriginale.

Ti ritroverai con qualcosa del genere:

Salva le modifiche, esci dalleditor , e hai finito! Questa è la cronologia risultante:

Come prima, tutto ciò che devi fare ora è git push --force-with-lease <remote_name> <branch_name> e le modifiche sono attive.

Se desideri rimuovere del tutto il commit dal ramo, invece di squash o fixup, scrivi semplicemente drop o elimina semplicemente quella riga.

Evita conflitti

Per evitare conflitti, assicurati che il commit “Stai spostando la sequenza temporale verso lalto non toccando gli stessi file toccati dai commit lasciati dopo di loro.

Pro-tip : Correzioni rapide

Se sai esattamente quale commit vuoi correggere, quando effettui il commit non devi sprecare cicli cerebrali pensando a buoni nomi temporanei per “Fix 1”, “Fix 2”, …, “Fix 42”.

Passaggio 1: incontra --fixup

Dopo che hai messo in scena le modifiche risolvendo qualunque cosa sia da correggere, solo Git esegue tutte le modifiche in questo modo:

(Nota che questo è lhash per il commit c22a3fa0c5c Render navigation partial)

Questo genererà questo messaggio di commit: fixup! Render navigation partial.

Passaggio 2: e il sidekick --autosquash

Facile rebase interattivo. Puoi fare git posizionare automaticamente i fixup nel posto giusto.

git rebase -i 4155df1cdc7 --autosquash

La cronologia verrà mostrata in questo modo:

Pronto per te solo rivedi e procedi.

Se ti senti avventuroso puoi fare un rebase non interattivo git rebase --autosquash, ma solo se ti piace vivere in modo pericoloso, come vuoi non abbiamo la possibilità di rivedere le zucche fatte prima che vengano “applicate”.

Situazione 4: la cronologia del mio commit Git non ha senso, ho bisogno di un nuovo inizio!

Se noi “Stiamo lavorando su una funzionalità di grandi dimensioni, è comune avere diverse modifiche alla correzione e al feedback di revisione che vengono impegnate frequentemente. Invece di ribasare costantemente il ramo, possiamo lasciare la pulizia dei commit fino alla fine dello sviluppo.

È qui che la creazione di file di patch è estremamente utile. In effetti, i file di patch erano il modo principale per condividere il codice tramite email durante la collaborazione su grandi progetti open source prima che i servizi basati su Git come GitLab fossero disponibili per gli sviluppatori. Immagina di avere uno di questi branch (ad esempio; add-page-navigation) dove ci sono tonnellate di commit che non comunicano chiaramente i cambiamenti sottostanti. Ecco come puoi creare un file patch per tutti le modifiche apportate in questo ramo:

  • Il primo passaggio per creare il file patch è assicurarsi che il tuo ramo abbia tutte le modifiche presenti da master branch e non ha conflitti con lo stesso.
  • Puoi eseguire git rebase master o git merge master mentre “ricontrolla nel ramo add-page-navigation per ottenere tutte le modifiche da master al ramo.
  • Ora crea il file patch ; esegui git diff master add-page-navigation > ~/add_page_navigation.patch.
    • Analisi dei comandi: qui “stiamo utilizzando la funzione di differenze di Git” e chiediamo una differenza tra master branch e add-page-navigation branch e reindirizzare loutput (tramite il simbolo >) a un file denominato add_page_navigation.patch nel nostro noi er home directory (tipicamente ~/ nei sistemi operativi * nix).
  • Puoi specificare qualsiasi percorso in cui desideri mantenere questo file in e il nome del file e lestensione potrebbero essere qualsiasi cosa tu voglia.
  • Una volta che il comando è stato eseguito e non vedi alcun errore, viene generato il file di patch.
  • Ora fai il checkout master branch; eseguire git checkout master.
  • Elimina il ramo add-page-navigation dal repository locale; esegui git branch -D add-page-navigation. Ricorda, abbiamo già modifiche a questo ramo in un file patch creato.
  • Ora crea un nuovo ramo con lo stesso nome (mentre master è estratto); esegui git checkout -b add-page-navigation.
  • A questo punto, questo è un nuovo ramo e non ha nessuna delle tue modifiche.
  • Infine, applica le modifiche dal file di patch; git apply ~/add_page_navigation.patch.
  • Qui, tutte le modifiche vengono applicate in un ramo e appariranno come non salvate, come se tutte le modifiche dove fatto, ma nessuna delle modifiche è stata effettivamente salvata nel ramo.
  • Ora puoi andare avanti e eseguire il commit di singoli file o file raggruppati per area di impatto nellordine desiderato con messaggi di commit concisi.

Come nelle situazioni precedenti, abbiamo sostanzialmente modificato lintero ramo, quindi è ora di forzare il push!

Conclusione

Anche se abbiamo trattato le situazioni più comuni e di base che si presentano in un flusso di lavoro quotidiano con Git, la riscrittura della cronologia di Git è un argomento vasto e man mano che acquisisci familiarità con suggerimenti sopra, puoi apprendere concetti più avanzati sullargomento nella documentazione ufficiale di Git. Buon git “ing!

Foto di pan xiaozhen su Unsplash

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *