Git squash e la contrazione di più commit

Oggi mi sono accorto che il lastBuildDate del mio feed RSS non veniva aggiornato ogni volta che ce n’era bisogno. Ho sistemato la cosa e, già che c’ero, ho messo mano ad alcune piccole migliorie sparse nel codice del file rss.xml. Siccome il sito è sotto controllo Git e avevo fatto diversi commit su più o meno lo stesso argomento, volevo semplicemente riunirli in modo da avere una storia più pulita. In questi casi, Git offre la possibilità di fare lo squash dei commit, cioè comprimerli in uno solo, così da mantenere appunto una cronologia più ordinata e leggibile. Questa pratica è particolarmente utile quando si lavora in gruppo o semplicemente perché si vogliono evitare più commit tutti incentrati su un unico aspetto. Contrariamente a quanto ci si potrebbe aspettare, però, non esiste un comando diretto git squash, ma l’operazione si esegue attraverso il comando interattivo git rebase -i. Non è complicato, ma è abbastanza tecnico da meritare qualche appunto pratico, che annoto qui sia per me sia per chi volesse provarci.


Nel mio repository avevo questi commit e volevo unificare gli ultimi 5, qui evidenziati in rosso in figura 1:

git-squash-1

Figura 1. I commit da contrarre.

Da terminale ho eseguito:

$ git rebase -i HEAD~5

Git mi ha mostrato l’editor di testo con gli ultimi 5 commit, uno per riga, e all’inizio di ogni riga la parola pick, come si vede in figura 2:

git-squash-2

Figura 2. L’editor con i commit da modificare. L’ordine è inverso rispetto al log tradizionale di Git o a come mostrato in figura 1.

A questo punto bisogna dire a Git quali commit comprimere. Basta lasciare pick sul primo commit in cima (il più vecchio tra i 5) e sostituire pick con squash o s sugli altri, come in figura 3:

git-squash-3

Figura 3. I commit da comprimere, con s al posto di pick.

Salviamo e chiudiamo. Si aprirà una nuova schermata dell’editor con tutti i messaggi dei commit coinvolti, così da poterli mantenere, modificare o cancellare:

git-squash-4

Figura 4. I messaggi originali dei commit.

Nel mio caso, ho scritto un messaggio breve riassuntivo come oggetto del commit e, sotto, un elenco dettagliato delle modifiche, come mostrato in figura 5:

git-squash-5

Figura 5. Il messaggio finale del commit unificato. Una riga vuota separa l’oggetto del commit dal resto del messaggio.

Dopo aver salvato, Git ha eseguito il rebase. Se ora controlliamo la cronologia dei commit, vedremo che i 5 sono stati unificati:

git-squash-6

Figura 6. I 5 commit ora risultano fusi in uno solo.

La stessa situazione da terminale:

$ git log
commit 175a196eb64d0af98957dc813b5072169c177e4f (HEAD -> master)
Author: Aldo Latino <email@tld.com>
Date:   Sun May 11 06:59:49 2025 +0200

    Corretta data lastBuildDate in feed RSS, migliorie varie

    - Fix lastBuildDate in feed RSS
    - Changed Date to PublishDate in RSS pubDate
    - Changed RSS content escaping, removed attribution
    - Removed trailing dashes in RSS source
    - Added leading dashes

commit 1f45056753e6bf8bb9f65b3bfbc96e9f17a75ef9
Author: Aldo Latino <email@tld.com>
Date:   Sun May 11 06:08:51 2025 +0200

    Aggiornato un link

commit 9a32ad1c8cc08dc1103410cc686b397de4416157 (origin/master, origin/HEAD)
Author: Aldo Latino <email@tld.com>
Date:   Sat May 10 18:12:34 2025 +0200

    Abilitato feed RSS solo in home
[...]

Lo squash dei commit è un ottimo modo per tenere ordinata la cronologia di un progetto. Dopo questa operazione, il repository risulta più leggibile e ordinato, specialmente quando si lavora in gruppo o si prepara una pull request. Un comando di Git che può tornare senza dubbio utile, anche se si lavora a un progetto del tutto personale.