È uscito il Corso Java Completo
Torna al blog

Git reset vs revert: come annullare senza fare danni

Reset e revert a confronto: cosa fanno davvero, le tre modalità di reset, quando usare quale e come recuperare quando hai già combinato un guaio.

Edoardo Midali

Edoardo Midali

Developer · Content Creator

6 min di lettura

"Devo annullare l'ultimo commit" è una delle situazioni in cui si cercano comandi su internet e si incollano senza capirli — con il rischio concreto di peggiorare le cose. Git offre due strade che sembrano equivalenti e non lo sono affatto: una riscrive la storia, l'altra ci aggiunge sopra. In questo articolo trovi quando usare quale, e come recuperare se hai già sbagliato.

La differenza in una riga

git revert crea un nuovo commit che annulla gli effetti di uno precedente. git reset sposta indietro il puntatore del ramo, facendo sparire i commit dalla storia.

Visivamente:

Prima:        A---B---C---D

revert D:     A---B---C---D---D'    (D' annulla D)
reset a C:    A---B---C            (D non è più raggiungibile)

Revert aggiunge, reset toglie. Da qui discende tutto il resto, inclusa la regola su quale usare.

La regola che decide

Se il commit è già stato condiviso con altri, usa revert. Se è ancora solo tuo, puoi usare reset.

Il motivo è concreto: il reset fa sparire dei commit dalla tua storia. Se un collega li ha già scaricati, la sua copia e la tua raccontano fatti diversi — e per riallinearsi dovresti forzare l'invio, sovrascrivendo il suo lavoro.

Revert invece è sempre sicuro, perché non tocca nulla di esistente: aggiunge un commit che dice "questo è annullato". Chi ha già scaricato la storia riceve semplicemente un commit in più.

È lo stesso principio che rende pericoloso il rebase su rami condivisi, di cui parlo in merge vs rebase.

Le tre modalità di reset

Qui sta la parte che confonde, e sono solo tre.

Il reset agisce su tre cose: il puntatore del ramo, l'area di stage e i file su disco. Le tre modalità si distinguono per quante di queste tocca.

--soft — sposta solo il puntatore

git reset --soft HEAD~1

Il commit sparisce dalla storia, ma le modifiche restano in stage, pronte per essere ricommittate.

Quando serve: hai fatto un commit e ti accorgi che volevi includere un altro file, o dividerlo in due. Annulli il commit, sistemi, ricommitti.

--mixed — anche l'area di stage (predefinito)

git reset HEAD~1

Il commit sparisce e le modifiche tornano nella cartella di lavoro, non più in stage. I file sono ancora modificati, ma devi rifare git add.

Quando serve: vuoi rivedere cosa mettere nel commit prima di rifarlo.

--hard — anche i file su disco

git reset --hard HEAD~1

Il commit sparisce e le modifiche vengono cancellate dai file. Tutto torna com'era.

È l'unico comando davvero pericoloso dei tre, ed è quello che viene incollato più spesso senza capirlo.

ModalitàPuntatoreStageFile su disco
--softintattointatti
--mixedintatti
--hardcancellati

Regola pratica: se non sei sicuro, usa --soft. Non perdi niente e puoi sempre procedere da lì.

Come si usa revert

git revert abc123          # annulla quel commit
git revert HEAD            # annulla l'ultimo
git revert abc123 --no-edit  # senza aprire l'editor del messaggio

Git crea un commit che applica le modifiche inverse. Il commit originale resta nella storia, e si vede sia cosa era stato fatto sia che è stato annullato.

Su un commit di unione serve indicare quale ramo considerare quello "principale", perché altrimenti Git non sa quale lato annullare — il concetto di unione è in merge vs rebase:

git revert -m 1 abc123

Un revert può generare conflitti, se nel frattempo quelle righe sono state toccate ancora. Si risolvono normalmente.

E si può annullare un revert: è a sua volta un commit come gli altri.

Il caso pratico più comune

"Ho fatto un commit con dentro una chiave API."

Vale la pena affrontarlo perché è frequente e viene gestito male.

Se non l'hai ancora inviato: git reset --soft HEAD~1, togli il file, ricommitta.

Se l'hai già inviato, la situazione è diversa da come sembra: rimuovere il segreto con un commit successivo non lo cancella dalla storia. Resta lì, leggibile da chiunque abbia accesso al repository — e su un repository pubblico va considerato già compromesso.

La sola azione che conta davvero è revocare quella chiave e generarne una nuova. La pulizia della storia (con strumenti dedicati che la riscrivono) è secondaria, e su un repository condiviso richiede il coordinamento di tutti.

La prevenzione, ovviamente, vale più della cura: come impostare le esclusioni fin dall'inizio è in file .gitignore: cosa escludere.

Se hai già combinato un guaio

Il comando che salva è git reflog.

Registra ogni spostamento fatto nel repository locale: cambi di ramo, commit, reset, unioni. Anche i commit "spariti" con un reset restano lì per settimane.

git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: la mia funzionalità
git reset --hard e4f5g6h

Prima di dare qualcosa per perso, guarda sempre il reflog. Recupera la stragrande maggioranza dei disastri.

L'unica cosa che non recupera sono le modifiche mai committate, cancellate da un --hard: non essendo mai entrate nella storia, non c'è nulla da ripescare. È il motivo per cui quella modalità va usata sapendo cosa si fa.

Gli altri modi di annullare

Per completezza, perché spesso servono questi invece di reset o revert:

git restore file.js              # butta le modifiche a un file
git restore --staged file.js     # toglie dallo stage, tiene le modifiche
git commit --amend               # corregge l'ultimo commit

git commit --amend è utilissimo per correggere un messaggio sbagliato o aggiungere un file dimenticato — ma riscrive l'ultimo commit, quindi vale la stessa regola: solo se non l'hai ancora condiviso.

In sintesi

Revert aggiunge un commit che annulla, reset fa sparire i commit. È la differenza che decide tutto.

La regola: revert se il commit è già condiviso, reset se è ancora solo tuo. Revert è sempre sicuro; reset su roba condivisa crea problemi a tutto il team.

Le tre modalità di reset si distinguono per quanto cancellano: --soft tiene tutto in stage (la scelta prudente), --mixed riporta i file nella cartella di lavoro, --hard cancella anche le modifiche — ed è l'unico davvero distruttivo.

E la cosa da ricordare per quando qualcosa va storto: git reflog recupera quasi tutto. L'unica eccezione sono le modifiche mai committate.

Se i comandi di base non ti sono ancora familiari, il quadro è in comandi Git essenziali.