Skip to content

Modulo 10 — Annullare modifiche & time traveling

git checkout è il coltellino svizzero di Git: crea branch, switcha, ripristina file, annulla la history. È così “sovraccarico” che sono nati git switch e git restore per separarne gli usi.

Terminal window
git checkout <hash> # bastano le prime ~7 cifre, vedi con git log

Appare l’avviso del detached HEAD — non spaventarti, non è un errore.

  • Normalmente: HEAD → branch reference (es. master) → ultimo commit del branch.
  • Quando committi, il branch reference avanza; HEAD non si muove (punta al branch).
  • Quando switchi branch, HEAD passa a puntare al nuovo branch reference.

Quando fai checkout di un commit specifico, HEAD punta direttamente a quel commit, senza passare dal branch: sei “staccato”.

987fac... d8194d6 171615...
▲
HEAD Master ▲ (ora solo commit, non branch)

Hai tre opzioni:

  1. Restare ed esplorare: guardare i file, fare esperimenti.
  2. Tornare dove eri, ri-attaccando HEAD: git switch master
  3. Creare un branch da qui e lavorarci: git switch -c newbranch — HEAD torna a puntare a un branch e puoi fare commit normalmente. È il vero “time travel”: torni a un vecchio commit e fai partire una nuova linea da lì.
Terminal window
git checkout HEAD~1 # il commit prima di HEAD (il genitore)
git checkout HEAD~2 # due commit prima (il nonno)
git checkout HEAD~3 # ...

Se hai modificato un file ma non vuoi tenerlo, riportalo allo stato dell’ultimo commit:

Terminal window
git checkout HEAD <file> # forma completa
git checkout -- <file> # forma abbreviata

⚠️ Le modifiche non committate vanno perse.

Introdotto insieme a git switch per togliere compiti a checkout (che troppi sviluppatori trovavano confuso). Non è ancora citato da tutorial e libri vecchi, ma conviene conoscerlo.

Terminal window
git restore <file> # riporta il file allo stato di HEAD
git restore --source HEAD~1 app.js # allo stato di un commit precedente
# (o di un hash specifico)
git restore --staged app.js # toglie il file dalla staging area
# (hai fatto git add per sbaglio?)

E se ti confondi: git status ti ricorda i comandi da usare.

Terminal window
git reset <hash> # i commit successivi a <hash> spariscono dalla history
git reset --hard HEAD~1 # idem, e cancella ANCHE le modifiche nei file
  • git reset <hash>: sposta indietro il puntatore del branch; le modifiche restano nei file (potrai committarle di nuovo altrove, es. sul branch giusto).
  • git reset --hard <commit>: cancella commit e modifiche ai file.

git revert — annullare con un nuovo commit

Section titled “git revert — annullare con un nuovo commit”
Terminal window
git revert <hash>

A differenza di reset, revert non riscrive la history: crea un nuovo commit che inverte le modifiche del commit indicato (ti verrà chiesto un messaggio). La vecchia storia resta intatta, con in più il commit “annulla”.

Reset o revert? La regola della collaborazione

Section titled “Reset o revert? La regola della collaborazione”
  • Commits mai condivisi (solo sul tuo machine): usa reset — nessuno se ne accorgerà mai.
  • Commits già condivisi (es. pushati su GitHub, che altri hanno in locale): usa revert.

Se fai reset su commit che il team ha già: hai alterato una history che gli altri possiedono — per loro è un incubo riconciliare le due versioni divergenti. Con revert, invece, i colleghi mergiano il nuovo commit “annulla” senza problemi: la history non è stata toccata.