Salta al contenuto principale

Annullare Modifiche in Git: reset, revert, restore e Quando Usarli

·5 minuti
Indice dei contenuti
Git ha quattro verbi principali per annullare le cose: restore, reset, revert e reflog. Scegliere quello sbagliato riscrive la storia che altri hanno già scaricato, oppure butta via lavoro che volevi conservare. Ecco il modello mentale per scegliere correttamente.

La domanda “come faccio a disfare questo?” ricorre continuamente, e la risposta dipende da una variabile critica: qualcun altro ha già scaricato il commit che vuoi annullare? Se sì, riscrivere la storia causa problemi ai tuoi colleghi. Se no, hai più opzioni. La mappa qui sotto ti porterà al comando giusto rapidamente, ma capire perché ogni comando funziona nel modo in cui funziona è ciò che fa la differenza in un incidente alle 2 di notte.

git restore: Scartare Modifiche nel Working Tree
#

git restore è il sostituto moderno del vecchio pattern git checkout -- file. Scarta le modifiche nel working tree o nell’area di staging senza toccare i commit.

# Scarta le modifiche non staged in un file (solo working tree)
git restore path/to/file.go

# Rimuovi un file dallo staging (spostalo dall'area di staging al working tree)
git restore --staged path/to/file.go

# Rimuovi dallo staging E scarta le modifiche nel working tree
git restore --staged --worktree path/to/file.go
Avviso

git restore sul working tree è distruttivo e irreversibile. Non esiste un reflog per le modifiche non staged. Usalo solo quando sei sicuro di non aver bisogno di quelle modifiche.

git reset: Spostare HEAD
#

git reset sposta il puntatore del branch (HEAD) a un commit diverso. Cosa succede alle modifiche dei commit “saltati” dipende dal flag.

FlagHEAD si spostaArea di stagingWorking tree
--softInvariata (modifiche staged)Invariato
--mixed (default)Svuotata (modifiche non staged)Invariato
--hardSvuotataSvuotato (modifiche perse)
# Annulla l'ultimo commit, mantieni le modifiche staged
git reset --soft HEAD~1

# Annulla l'ultimo commit, mantieni le modifiche nel working tree (non staged)
git reset --mixed HEAD~1

# Annulla l'ultimo commit, scarta tutte le modifiche
git reset --hard HEAD~1

HEAD~1 significa “un commit prima di HEAD”. Puoi usare anche un SHA specifico: git reset --soft abc1234.

Importante

Non usare mai git reset su commit che sono già stati pushati su un branch condiviso. Riscrive la storia. Se un collega ha già scaricato quei commit, il suo repo divergerà dal tuo e il merge risultante sarà confuso e problematico. Usa invece git revert (vedi sotto).

git revert: Creare un Commit di Annullamento
#

git revert non sposta HEAD all’indietro. Crea invece un nuovo commit le cui modifiche sono l’inverso del commit specificato. Tutta la storia viene preservata.

# Crea un commit di revert per il commit più recente
git revert HEAD

# Revert di un commit specifico tramite SHA
git revert abc1234

# Revert senza fare il commit immediatamente (fai prima lo stage delle modifiche, poi committa manualmente)
git revert --no-commit abc1234

Questo è l’approccio corretto per annullare modifiche su main, release o qualsiasi altro branch che altri ingegneri hanno già scaricato. La storia mostra esattamente cosa è successo: il commit originale seguito dal commit di revert.

Suggerimento

Quando si fa il revert di un merge commit, è necessario specificare a quale parent tornare con il flag -m: git revert -m 1 <sha-del-merge-commit>. Il parent 1 è il branch in cui si è fatto il merge; il parent 2 è il branch mergiato.

Diagramma Decisionale
#

flowchart TD
    A[Devo annullare qualcosa] --> B{È già stato pushato\nsu un branch condiviso?}
    B -->|Sì| C[git revert\nCrea un nuovo commit di annullamento\nLa storia viene preservata]
    B -->|No| D{Dove si trovano\nle modifiche?}
    D -->|Working tree non staged| E[git restore file\nScarta le modifiche al file]
    D -->|Staged ma non committato| F[git restore --staged file\nRimuovi dallo staging]
    D -->|Committato localmente| G{Cosa voglio fare\ncon le modifiche?}
    G -->|Tenerle staged| H[git reset --soft HEAD~1]
    G -->|Tenerle non staged| I[git reset --mixed HEAD~1]
    G -->|Scartarle del tutto| J[git reset --hard HEAD~1]

git reflog: La Rete di Sicurezza
#

Il reflog è un log locale di tutti i posti dove HEAD ha puntato negli ultimi 30 giorni. Anche se esegui git reset --hard e “perdi” commit, sono ancora nell’object store e raggiungibili tramite il reflog.

# Mostra il reflog
git reflog

# L'output appare così:
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: add login feature
# ...

# Recupera il commit "perso"
git checkout def5678

# Oppure esegui un reset a quel punto
git reset --hard def5678

Il reflog è puramente locale. Non viene pushato al remote. Se cloni un repo da zero e perdi commit con --hard, sono andati. Ma nel normale workflow quotidiano sulla tua macchina, il reflog è una rete di sicurezza quasi affidabile.

Nota

Le voci del reflog scadono dopo 90 giorni per default (30 giorni per gli oggetti non raggiungibili). Puoi regolare questo con gc.reflogExpire e gc.reflogExpireUnreachable nella configurazione git, ma i default sono generosi abbastanza per la maggior parte degli scenari di recupero.

**Usare `git reset --hard` su un branch condiviso.** Questo riscrive la storia e causerà conflitti di merge o richieste di force push per chiunque abbia già scaricato. Usa sempre `git revert` su branch che altri stanno tracciando. **Non conoscere il `git reflog` dopo un reset `--hard`.** Molti developer credono che il lavoro sia perso per sempre. Esegui `git reflog`, trova il SHA del commit su cui eri prima del reset e recuperalo con `git reset --hard `. Hai 30 giorni. **Confondere `git restore` con `git reset`.** `git restore` tocca solo il working tree e l'area di staging, non sposta mai HEAD né cambia la storia dei commit. `git reset` sposta sempre HEAD. Sono strumenti complementari, non intercambiabili. **Fare il revert di un merge commit senza il flag `-m`.** Git non sa a quale lato del merge tornare e restituisce un errore. Specifica sempre `-m 1` per tornare al parent principale.

Se vuoi approfondire uno qualsiasi di questi argomenti, offro sessioni di coaching 1:1 per ingegneri che lavorano su integrazione AI, architettura cloud e platform engineering. Prenota una sessione (50 EUR / 60 min) o scrivimi a manuel.fedele+website@gmail.com.

Articoli correlati