Hai fatto un commit che vuoi annullare. E adesso?
Succede a tutti. Fai commit troppo presto, includi un file che non avresti dovuto, scrivi il messaggio sbagliato o ti rendi conto che il codice semplicemente non va bene. La buona notizia: Git è progettato per gestire questo. La notizia migliore: nella maggior parte dei casi, puoi annullare un commit senza perdere il tuo lavoro.
L'approccio giusto dipende da una domanda chiave: il commit è stato pushato su un remote, o è ancora locale? I commit locali ti danno più flessibilità. I commit pushati richiedono una strategia più sicura perché altre persone potrebbero aver già pullato le tue modifiche.
Annullare un commit locale con git reset
Se il commit è ancora locale (non pushato), git reset è lo strumento più comune. Sposta il puntatore del branch indietro a un commit precedente, annullando di fatto il commit. Cosa succede alle modifiche dipende dal flag che usi.
git reset --soft: annulla il commit, mantiene tutto in staging
git reset --soft HEAD~1
Questo annulla l'ultimo commit ma mantiene tutte le modifiche in staging (nell'indice). Il tuo directory di lavoro non viene toccato. È come se non avessi mai eseguito git commit -- sei tornato al momento appena prima del commit.
Quando usarlo: Vuoi cambiare il messaggio del commit, aggiungere più file al commit o dividere il commit in altri più piccoli. Il tuo codice è a posto, hai solo fatto commit prematuramente.
git reset --mixed: annulla il commit, rimuovi le modifiche dallo staging
git reset --mixed HEAD~1
Questo è il comportamento predefinito di git reset (puoi omettere il flag --mixed). Annulla il commit e rimuove le modifiche dallo staging, ma i tuoi file rimangono modificati nel directory di lavoro. Nulla va perso.
Quando usarlo: Vuoi ripensare cosa includere nel commit. Forse vuoi mettere in staging solo alcuni file, o vuoi rivedere le modifiche prima di fare un nuovo commit.
git reset --hard: annulla il commit, scarta tutte le modifiche
git reset --hard HEAD~1
Questo annulla il commit e cancella permanentemente tutte le modifiche. Il tuo directory di lavoro viene ripristinato per corrispondere al commit precedente. Non c'è modo di recuperare le modifiche scartate tramite le normali operazioni Git.
Quando usarlo: Sei certo di non volere affatto le modifiche. Forse hai fatto commit di codice sperimentale che non ha funzionato e vuoi ripartire da zero. Usalo con cautela.
Tornare ancora più indietro
HEAD~1 si riferisce a un commit prima dell'HEAD attuale. Puoi andare oltre:
git reset --soft HEAD~3
Questo annulla gli ultimi tre commit, combinando tutte le loro modifiche nell'area di staging. Puoi anche puntare a un commit specifico tramite il suo hash:
git reset --soft a1b2c3d
Correggere l'ultimo commit con git commit --amend
Se hai solo bisogno di modificare l'ultimo commit piuttosto che annullarlo completamente, --amend è l'opzione più veloce:
git commit --amend -m "corrected commit message"
Questo sostituisce il commit precedente con uno nuovo. Puoi anche usarlo per aggiungere file dimenticati:
git add forgotten-file.ts
git commit --amend --no-edit
Il flag --no-edit mantiene il messaggio di commit originale. Il risultato è un singolo commit corretto invece di una sequenza di commit "ops".
Importante: Come reset, anche amend riscrive la storia. Usalo solo su commit che non sono stati pushati. Se fai amend di un commit pushato e poi force-push, chiunque abbia pullato il commit originale avrà problemi.
Annullare un commit pushato con git revert
Una volta che un commit è stato pushato su un remote condiviso, non dovresti riscrivere la storia. Altri sviluppatori potrebbero aver basato il loro lavoro su quel commit. Usa invece git revert:
git revert HEAD
Questo crea un nuovo commit che fa esattamente l'opposto del commit target. Se il commit originale aggiungeva una riga, il commit di revert la rimuove. Se cancellava un file, il commit di revert lo ripristina. Il commit originale rimane nella storia, e il revert viene aggiunto sopra.
Quando usarlo: Ogni volta che devi annullare un commit che è già stato pushato. È sicuro perché aggiunge alla storia invece di riscriverla.
Revertire un commit più vecchio
Puoi revertire qualsiasi commit, non solo il più recente:
git revert a1b2c3d
Git tenterà di creare un commit di revert che annulla solo le modifiche di quel commit specifico. Se quelle modifiche si sovrappongono con lavoro successivo, potresti ottenere un conflitto che necessita di risoluzione manuale.
Revertire più commit
Per revertire un intervallo di commit:
git revert HEAD~3..HEAD
Questo crea commit di revert individuali per ogni commit nell'intervallo. Se preferisci un singolo commit di revert, aggiungi il flag --no-commit e fai il commit manualmente:
git revert --no-commit HEAD~3..HEAD
git commit -m "revert last 3 commits"
Scegliere l'approccio giusto
| Situazione | Metodo | Cosa succede alle tue modifiche |
|---|---|---|
| Commit troppo presto, vuole ri-stagare | git reset --soft HEAD~1 |
Le modifiche rimangono in staging |
| Commit troppo presto, vuole rielaborare | git reset --mixed HEAD~1 |
Le modifiche rimangono nel directory di lavoro |
| Commit di qualcosa da scartare | git reset --hard HEAD~1 |
Le modifiche vengono cancellate |
| Bisogno di correggere il messaggio o aggiungere un file | git commit --amend |
Il commit precedente viene sostituito |
| Bisogno di annullare un commit pushato in sicurezza | git revert HEAD |
Un nuovo commit annulla le modifiche |
Recupero dagli errori
Anche se usi git reset --hard e ti rendi conto che non avresti dovuto, spesso c'è un modo per recuperare. Git mantiene un registro di dove ha puntato HEAD, chiamato reflog:
git reflog
Questo mostra un elenco delle posizioni recenti di HEAD. Puoi trovare il commit che pensavi di aver perso e tornare ad esso:
git reset --hard HEAD@{2}
Il reflog è la tua rete di sicurezza. Le voci vengono mantenute per 90 giorni per impostazione predefinita, quindi hai un'ampia finestra per recuperare dagli errori.
Annullare commit in GitSquid
GitSquid semplifica le operazioni di annullamento più comuni. Puoi premere Cmd+Z (o Ctrl+Z su Windows e Linux) subito dopo aver fatto commit per annullare l'ultimo commit, mantenendo le tue modifiche in staging e pronte per essere rielaborate. Per operazioni più specifiche, facendo clic destro su qualsiasi commit nel grafo puoi accedere alle opzioni di reset e revert tramite un menu contestuale, così puoi mirare esattamente al commit che vuoi annullare senza memorizzare flag.
Annullare un commit Git non deve essere stressante. Comprendi la differenza tra reset, amend e revert, sappi quale si adatta alla tua situazione, e potrai correggere gli errori con sicurezza. La distinzione più importante è semplice: se è locale, usa reset o amend. Se è pushato, usa revert.