Torna al blog

Git: annullare l'ultimo commit e tenere le modifiche

3 settembre 2026

TL;DR: per annullare l’ultimo commit tenendo le modifiche, lancia git reset --soft HEAD~1 (le modifiche restano in staging) oppure git reset HEAD~1 (le modifiche restano nella working tree). Se il commit è già stato pushato, lancia invece git revert HEAD — crea un nuovo commit che lo annulla senza riscrivere la storia. Quei tre comandi coprono quasi ogni momento «ho committato troppo presto». Il resto della guida passa in rassegna ogni caso con comandi da copiare e incollare, spiega la differenza tra --soft, --mixed e --hard e mostra come recuperare la situazione se qualcosa va storto. Ogni comando funziona su qualunque installazione recente di Git, su Linux, macOS o Windows.

Come annullo l’ultimo commit ma tengo le modifiche?

La situazione più comune: hai fatto il commit, poi hai visto un refuso, un file mancante, o ti sei accorto che la modifica sta in un altro commit. Non hai ancora pushato nulla. Annulla il commit e rimetti tutto a posto:

# Il commit sparisce dalla storia — le modifiche tornano nell'area di staging
git reset --soft HEAD~1

# Le modifiche tornano invece nella working tree (fuori dallo staging)
git reset HEAD~1

HEAD~1 significa «un commit prima di dove punta HEAD adesso». Dopo uno dei due comandi i tuoi file restano intatti su disco — si è spostato solo il puntatore del branch. Verifica con git status: con --soft le modifiche sono in staging, pronte per il re-commit con le correzioni incluse; senza flag sono fuori staging, così puoi modificare liberamente prima.

Un’abitudine più sicura quando vuoi solo aggiungere file all’ultimo commit è non annullarlo affatto:

git add forgotten-file.txt
git commit --amend --no-edit

--amend sostituisce l’ultimo commit sul posto (qui senza cambiare il messaggio). Nota che fare amend di un commit già pushato riscrive la storia — ne parliamo qui sotto.

Qual è la differenza tra —soft, —mixed e —hard?

Questa è la parte da imparare a memoria, perché la flag decide dove finiscono le tue modifiche — e se possono perdersi:

FlagCommit annullato?Modifiche su discoIn staging?Uso tipico
--softMantenuteRicommit con piccole correzioni
--mixed (default)MantenuteNoRiorganizzare le modifiche, stage selettivo
--hardEliminateGettare via tutto il lavoro
git revertNo (nuovo commit)MantenuteAnnullare un commit già pushato

--hard è l’unica pericolosa: scarta il commit e le modifiche. Prima di qualunque reset --hard, metti in stash o su un branch quello che hai:

git branch backup-before-reset   # assicurazione a costo zero
git reset --hard HEAD~1          # commit + modifiche cancellati

Se hai già lanciato la versione pericolosa, non è tutto perduto — git reflog ricorda dove è passato HEAD:

git reflog                       # trovi l'hash del commit perduto
git reset --hard HEAD@{1}        # oppure: git reset --hard <hash>

Il reflog conserva i commit orfani per circa 90 giorni di default, quindi «ho fatto un hard-reset per sbaglio» è quasi sempre recuperabile se intervieni prima del garbage collection.

E se il commit l’ho già pushato?

Se il commit sta su un branch condiviso (qualunque cosa tranne il tuo feature branch personale), non riscrivere la storia. Usa git revert, che calcola la modifica opposta e la committa:

git revert HEAD
git push

Chiunque faccia pull riceve semplicemente un nuovo commit che rimuove le modifiche del vecchio. Niente force-push, niente colleghi con il repository rotto. Se devi annullare una serie di commit, fai il revert di un intervallo: git revert --no-commit HEAD~3..HEAD && git commit.

L’alternativa — git reset --hard HEAD~1 && git push --force-with-lease — è accettabile solo su un branch su cui non costruisce nessun altro, e --force-with-lease (mai il --force semplice) è l’unica forma sicura perché rifiuta se qualcuno ha pushato nel frattempo. Forzare il push sui branch condivisi è il modo in cui i team perdono commit e i log della CI smettono misteriosamente di combaciare con il checkout di chiunque.

Come annullo l’ultimo commit tenendolo da parte per dopo?

A volte il commit è buon lavoro all’indirizzo sbagliato — sul branch sbagliato, o arrivato troppo presto. Invece di annullarlo, spostalo:

git branch stash-commit          # parcheggia il commit su un nuovo branch
git reset --hard HEAD~1          # poi ripulisci il branch corrente

Oppure porta solo quel commit su un altro branch senza toccare quello corrente:

git cherry-pick <hash>           # da eseguire sul branch di destinazione

Tra reset --soft, cherry-pick e revert, non esiste commit che non puoi spostare o neutralizzare — l’arte sta nel scegliere tra «spostare» e «annullare» prima di tirare giù una flag.

Quale undo usare? La decisione in cinque righe

  1. Non pushato, vuoi correggere e ricommitaregit reset --soft HEAD~1
  2. Non pushato, vuoi rimettere in staging con criteriogit reset HEAD~1 (mixed)
  3. Vuoi le modifiche eliminate del tuttogit reset --hard HEAD~1 (il reflog ricorda, se ti penti)
  4. Già pushato su un branch condivisogit revert HEAD
  5. Il commit appartiene a un altro branchcherry-pick, non annullare

Un ultimo consiglio operativo: se un commit marcio è davvero arrivato su un server — un hook di deploy rovinato, un runner CI che impazzisce dopo un force-push — il posto successivo dove guardare sono i log della macchina, non Git. Su qualunque box systemd, journalctl -u <service> -n 100 ti mostra esattamente cosa è stato eseguito e quando; il nostro journalctl cheat sheet ha i pattern pronti da incollare. E se nel tuo flusso di lavoro ci sono LLM locali per rivedere i diff, abbiamo confrontato le due opzioni principali in Ollama vs LM Studio.

— 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?

journalctl cheat sheet: seguire e filtrare i log Linux

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