Torna al blog

Git revert vs reset: quale salva la tua cronologia?

15 settembre 2026

TL;DR: git revert aggiunge un nuovo commit che annulla uno vecchio — la cronologia resta intatta, sicuro sui branch che altri hanno già scaricato. git reset sposta all’indietro il puntatore del branch — la cronologia viene riscritta, sicuro solo sui commit che non hai ancora fatto in push. Usa revert sui branch condivisi, reset per la pulizia locale. reset --hard cancella anche le modifiche non committate nel working tree; quello è il comando che si mangia lavoro vero.

Qual è la differenza tra git revert e git reset?

Entrambi fanno sembrare che un commit del passato non sia mai esistito. Il disaccordo è sul come:

  • git revert <sha> calcola la patch inversa di un commit e la committa. La tua cronologia cresce di un commit che dice «annulla quello». Il commit cattivo resta nel log, seguito dalla sua cancellazione. Gli SHA di tutto il resto restano intatti.
  • git reset <sha> sposta il puntatore del branch corrente su <sha>. I commit successivi si staccano — restano nell’object database fino alla garbage collection, ma non sono più raggiungibili da nessun branch o git log.

Uno non riscrive nulla, l’altro finge che non sia successo. Questa singola proprietà decide quale dei due serve in ogni situazione:

# Demo: un repo usa-e-getta eseguibile
git init /tmp/revert-vs-reset && cd /tmp/revert-vs-reset
echo one > file.txt && git add . && git commit -m "one"
echo two > file.txt && git add . && git commit -m "two"

# Revert: la cronologia tiene entrambi i commit, più un terzo che annulla "two"
git revert --no-edit HEAD
git log --oneline        # 3 commit: revert, two, one

# Reset: il puntatore del branch torna indietro, "two" sparisce dal log
git reset --hard HEAD~1
git log --oneline        # 1 commit: one

Lancia entrambe le demo e guarda git log — l’asimmetria è tutta la risposta.

Cosa fanno davvero git reset —soft, —mixed e —hard?

Le tre modalità controllano dove sopravvivono le tue modifiche dopo lo spostamento del puntatore:

ModalitàPuntatore di branchArea di stagingWorking treeLe tue modifiche
--softtorna indietroresta in stagingintattoconservate del tutto
--mixed (default)torna indietrofuori stagingintattoconservate, non in staging
--hardtorna indietroazzerataazzeratoeliminate

Letture concrete di quella tabella:

  • git reset --soft HEAD~1 — «ho committato troppo presto». Tutto torna in staging, pronto per il recommit, magari insieme ad altro lavoro.
  • git reset HEAD~1 (mixed) — «ho messo in staging i file sbagliati». Le modifiche sopravvivono nel working tree, nulla resta in staging. Abbinalo a git remove untracked files quando vuoi far sparire anche i file vaganti.
  • git reset --hard HEAD~1 — «questo commit e le mie modifiche non committate sono spazzatura». Git non te lo chiede due volte; per la parte di working tree non esiste undo, a meno che tu non l’abbia prima messa in stash o committata.

revert non ha modalità perché non distrugge mai nulla — si limita ad aggiungere un commit compensativo.

Quando usare git revert invece di git reset?

Una sola domanda: qualcun altro ha già fatto pull di questo commit? Se sì, reset è fuori discussione.

Resettare un branch su cui altri hanno costruito riscrive la cronologia condivisa. Il loro prossimo pull incontra branch divergenti, e la «sistemazione» di solito è un force-push che trasforma il tuo errore nel problema di tutti. Revert aggiunge un commit normale, quindi un semplice git pull mergia pulito per tutti — ecco perché revert è la risposta di default su main e sulle pull request GitHub, dove il bottone “Revert” esiste proprio perché riscrivere la cronologia di una PR mergiata non è un’opzione.

Reset è per la finestra prima della condivisione: il commit fatto trenta secondi fa, lo staging sbagliato, il branch di esperimento locale. Se l’unica copia del lavoro sta sulla tua macchina, sei libero di riarrangiare la cronologia — è proprio questo il senso della finestra pre-push.

C’è un caso intermedio: hai fatto push sul tuo feature branch e nessun altro ci costruisce sopra. Un force-push dopo il reset è socialmente accettabile lì, ma revert costa comunque meno coordinamento. Riserva i force-push ai branch che possiedi da solo.

git revert è più sicuro di git reset sui branch condivisi?

Sì, strutturalmente — non solo per convenzione:

  • Revert produce un commit ordinario: la CI ci gira sopra, il diff è revisionabile, e git log spiega al te-del-futuro perché la modifica è sparita.
  • Reset scarta in silenzio lo stato intermedio. Nessuno che revisiona dopo può vedere cosa è stato annullato e quando, perché il log mostra una linea retta che non l’ha mai contenuto.

Due spigoli da conoscere:

  • Annullare un merge commit richiede git revert -m 1 <sha> (tieni la linea del primo parent). Senza -m, git rifiuta e ti lascia leggere l’errore.
  • Revert non è una macchina del tempo: annulla il diff di un solo commit. Se commit successivi hanno toccato le stesse righe, potresti dover risolvere conflitti — è git che ti dice che l’annullamento è annodato, un’informazione utile, non un malfunzionamento.

Per annullare nello specifico il tuo ultimo commit — tenendo o buttando le sue modifiche — le opzioni sono tutte in git undo last commit: tenere le modifiche.

E git restore, dove sta?

git restore (e git switch, il suo gemello) sono arrivati in git 2.23 per prendere i lavori che reset svolgeva male per sovraccarico di nomi:

CompitoModo vecchioModo chiaro
Scartare le modifiche al working tree di un filegit checkout -- file / git reset --hardgit restore file
Togliere un file dallo staginggit reset HEAD filegit restore --staged file
Spostare il branch su un altro commitgit reset <sha>git reset <sha> (nessun sostituto — questo resta)

Quindi la divisione moderna è: restore sistema i file, reset sposta i branch, revert annulla i commit pubblicati. L’autocomplete mostra che la gente cerca “git revert vs reset vs restore” insieme, e per una buona ragione — sono un unico modello mentale spezzato su tre comandi. Le vecchie forme di git checkout funzionano ancora ovunque; le nuove ti evitano solo di mandare un branch intero nel distruttore quando intendevi togliere un file dallo staging.

Se l’obiettivo è copiare in avanti un commit buono anziché cancellarne uno cattivo, quello è il lavoro di cherry-pick — vedi git cherry-pick: commit multipli, branch e conflitti.

Riepilogo rapido delle decisioni

  1. Commit pubblico (fatto il push, altri hanno fatto pull) → git revert <sha>.
  2. Commit solo locale, vuoi rifarlo → git reset --soft o --mixed e ricommit.
  3. Solo locale, vuoi eliminarlo insieme al disordine non committato → git reset --hard, dopo un’occhiata onesta a cos’altro contiene il working tree.
  4. Un file è stato malmenato → git restore <file> e lascia stare il branch.

L’unica voce davvero pericolosa della lista è --hard — tutto il resto si può riportare indietro con git reflog. Le perdite permanenti in git sono poche e in gran parte richiedono che tu lo scriva esplicitamente; l’abitudine che vale la pena costruire è la mezza pausa prima di --hard, non l’evitare del tutto gli attrezzi affilati di git.

— mrsaynothing

Get the next one by email

One email per post. No spam, no algorithms.

self-hosted · no third parties · one-click unsubscribe

what is this?

Il servizio systemd non parte? Come risolverlo

Ti piacciono gli articoli? È così che costruisco per lavoro. assumimi