Editing Avanzato della Cronologia Git: Modifica dei Commit e Rebase Interattivo

Usa git commit --amend e il rebase interattivo per pulire la cronologia locale senza interrompere i rami condivisi.

Editing Avanzato della Cronologia Git: Modifica dei Commit e Rebase Interattivo

L'editing avanzato della cronologia Git ti aiuta a pulire i commit prima che diventino parte della cronologia condivisa. Quando capisci come modificare i commit e usare il rebase interattivo, puoi correggere piccoli errori, combinare commit rumorosi e presentare una storia più chiara per la revisione del codice.

La regola chiave è semplice: modificare la cronologia locale è normale, ma riscrivere la cronologia condivisa richiede attenzione. I comandi sono potenti perché cambiano gli ID dei commit, non solo i messaggi.

Cosa Cambia Effettivamente l'Editing della Cronologia Git

Ogni commit Git ha un ID basato sul suo contenuto, metadati, commit genitore, autore, data e messaggio. Se modifichi un commit o lo riscrivi durante un rebase, Git crea un nuovo commit con un nuovo ID.

Questo va bene quando il commit esiste solo sulla tua macchina. È rischioso quando altre persone hanno già scaricato il vecchio commit. I loro rami potrebbero ancora puntare alla vecchia cronologia, mentre il tuo punta a quella riscritta.

Usa l'editing della cronologia per:

  • Correggere un errore di battitura nell'ultimo messaggio di commit.
  • Aggiungere un file dimenticato al tuo ultimo commit locale.
  • Comprimere diversi commit di lavoro in corso prima di aprire una pull request.
  • Riordinare i commit locali in modo che le modifiche correlate siano più facili da revisionare.
  • Dividere un grande commit locale in commit logici più piccoli.

Evita l'editing della cronologia su:

  • Rami principali.
  • Rami di rilascio.
  • Rami di funzionalità condivisi usati da più persone.
  • Qualsiasi ramo con tag di deployment o commit sensibili per audit.

Prima di iniziare, controlla su quale ramo ti trovi e cosa è già stato inviato:

git status
git branch --show-current
git log --oneline --decorate -5

Se non sei sicuro che la riscrittura sia sicura, crea un ramo di backup:

git branch backup-before-rebase

Questo ramo ti fornisce un punto di recupero noto se il rebase va storto.

Modificare l'Ultimo Commit

git commit --amend sostituisce il commit più recente con uno nuovo. È il modo più veloce per correggere l'ultimo commit prima che qualcun altro dipenda da esso.

Per modificare solo il messaggio del commit:

git commit --amend

Git apre il tuo editor con il messaggio corrente. Salva il messaggio corretto e Git crea un commit sostitutivo.

Per aggiungere un file dimenticato all'ultimo commit:

git add path/to/file
git commit --amend --no-edit

Il flag --no-edit mantiene il messaggio esistente. Questo è utile quando il messaggio del commit è già corretto e hai solo dimenticato di mettere in stage una modifica.

Ecco uno scenario comune. Fai un commit di un aggiornamento del Dockerfile, poi noti di aver dimenticato la modifica correlata a .dockerignore:

git add Dockerfile
git commit -m "Migliora la cache di build Docker"
git add .dockerignore
git commit --amend --no-edit

Ora il ramo ha un commit pulito invece di un secondo commit che dice "file dimenticato." Questo rende la revisione più facile.

Se il commit originale era già stato inviato, il ramo remoto ha ancora il vecchio ID del commit. Inviare il commit modificato richiede un aggiornamento forzato:

git push --force-with-lease

Preferisci --force-with-lease a --force. Rifiuta di sovrascrivere il ramo remoto se qualcun altro ha inviato nuovo lavoro dopo il tuo ultimo fetch.

Pulire Più Commit con il Rebase Interattivo

Il rebase interattivo ti permette di modificare più commit contemporaneamente. Scegli un intervallo, poi Git apre una lista di cose da fare dove puoi selezionare, riscrivere, comprimere, correggere, riordinare o fermarti sui commit.

Per modificare gli ultimi cinque commit:

git rebase -i HEAD~5

Vedrai una lista come questa:

pick a1b2c3d Aggiungi script di deployment
pick b2c3d4e Correggi errore di battitura
pick c3d4e5f Aggiungi health check
pick d4e5f6a Aggiorna documentazione
pick e5f6a7b Regola timeout

Cambia il comando all'inizio di ogni riga per controllare cosa succede. Le scelte comuni sono:

  • pick: mantieni il commit così com'è.
  • reword: mantieni le modifiche ma modifica il messaggio.
  • squash: combina questo commit nel precedente e modifica il messaggio combinato.
  • fixup: combina questo commit nel precedente e scarta il messaggio di questo commit.
  • edit: fermati a questo commit così puoi cambiarne il contenuto.
  • drop: rimuovi il commit.

Ad esempio, se "Correggi errore di battitura" appartiene a "Aggiungi script di deployment," cambia la seconda riga:

pick a1b2c3d Aggiungi script di deployment
fixup b2c3d4e Correggi errore di battitura
pick c3d4e5f Aggiungi health check
pick d4e5f6a Aggiorna documentazione
pick e5f6a7b Regola timeout

Salva e chiudi l'editor. Git riproduce i commit e combina la correzione dell'errore di battitura nel commit precedente.

Il rebase interattivo è utile anche per migliorare i messaggi dei commit prima di una pull request. Se tre commit dicono tutti "aggiorna," usa reword e trasformali in messaggi che spiegano il cambiamento effettivo.

Se appare un conflitto, risolvilo come un normale conflitto di merge:

git status
git add file-risolto
git rebase --continue

Se decidi che il rebase non vale la pena:

git rebase --abort

Questo riporta il tuo ramo allo stato prima dell'inizio del rebase.

Dividere un Commit Durante il Rebase

A volte un commit contiene due modifiche non correlate. Ad esempio, potresti avere un commit che aggiorna un manifest Kubernetes e corregge anche una sezione del README. Queste modifiche dovrebbero probabilmente essere separate.

Avvia un rebase interattivo:

git rebase -i HEAD~3

Cambia pick in edit per il commit che vuoi dividere. Quando Git si ferma a quel commit, resettalo mantenendo le modifiche nel tuo albero di lavoro:

git reset HEAD^

Ora metti in stage e fai il commit del primo pezzo logico:

git add k8s/deployment.yaml
git commit -m "Aggiorna health check del deployment"

Poi metti in stage e fai il commit del secondo pezzo:

git add README.md
git commit -m "Documenta il comportamento dell'health check"

Continua il rebase:

git rebase --continue

Questo trasforma un commit ampio in due commit mirati. I revisori possono capire ogni modifica senza separare mentalmente il lavoro non correlato.

Quando Chiedere Aiuto Prima di Riscrivere

Chiedi aiuto prima di riscrivere qualsiasi ramo che altre persone usano. Un team lead, un ingegnere dei rilasci o un manutentore del repository può dirti se il ramo è sicuro da riscrivere e come il team gestisce i force push.

Chiedi aiuto immediatamente se un rebase influisce su commit già distribuiti, taggati o referenziati da report di incidenti. In questi casi, preservare la cronologia è spesso più importante che renderla ordinata.

Per i rami di funzionalità di routine, l'editing della cronologia è un normale passo di pulizia. Usa git commit --amend per l'ultimo commit, il rebase interattivo per una piccola serie locale e --force-with-lease quando devi aggiornare un ramo remoto di tua proprietà.