W3docs

Detached HEAD

Capisci lo stato detached HEAD di Git: cosa significa, quando accade, come salvare il lavoro e come tornare a un branch.

Definizione

Un detached HEAD si verifica quando HEAD punta direttamente a un commit invece che a un branch. Normalmente HEAD fa riferimento al nome di un branch (come main), e quel branch punta all'ultimo commit — quindi quando si fa un commit, il branch avanza con te. In uno stato detached HEAD, questa catena è spezzata: HEAD si trova su un commit specifico senza alcun branch che porti avanti i nuovi commit.

HEAD che punta attraverso un branch rispetto a HEAD che punta direttamente a un commit

Come funziona normalmente HEAD

HEAD è un riferimento che indica a Git "dove ti trovi in questo momento." Nel normale stato "attached", i riferimenti formano una catena: HEAD → branch → commit. HEAD non punta direttamente a un commit — punta al nome di un branch, e quel branch punta all'ultimo commit.

Quando crei un nuovo commit, Git sposta il puntatore del branch al nuovo commit, e poiché HEAD punta al branch, lo segue automaticamente. La cronologia rimane ancorata a un branch con nome.

Puoi vedere questa catena da solo. Il file .git/HEAD contiene un riferimento simbolico:

cat .git/HEAD
# ref: refs/heads/main      <- attached: HEAD points at a branch

Cosa distacca HEAD

HEAD si distacca ogni volta che si fa il checkout di qualcosa che non è un branch — il più delle volte un commit specifico, un tag, o un riferimento di tracciamento remoto:

git checkout a1b2c3d      # a commit hash
git checkout v1.0.0       # a tag
git checkout origin/main  # a remote-tracking ref
git switch --detach main  # explicitly detach at main's tip

Git ti avvisa quando questo accade. Il messaggio ha questo aspetto:

Note: switching to 'a1b2c3d'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

Dopo il distacco, .git/HEAD non punta più a un branch — contiene un hash di commit grezzo:

cat .git/HEAD
# a1b2c3d4e5f6...          <- detached: HEAD points at a commit directly

Il comando git checkout svolge un doppio ruolo (cambiare branch e spostare HEAD). I capitoli più recenti su git switch e git checkout spiegano perché Git ha separato questi compiti.

Quando il detached HEAD è utile

Un detached HEAD non è un errore — è uno strumento normale. Lo usi deliberatamente quando vuoi esaminare o costruire la cronologia senza toccare alcun branch:

  • Esaminare una versione precedente — fai il checkout di un commit o tag per leggere il codice com'era in quel momento.
  • Compilare o testare una vecchia release — fai il checkout di v1.0.0, esegui la build, poi torna al tuo branch.
  • Individuare un bug con bisectgit bisect fa il checkout dei commit in un detached HEAD mentre cerca il commit che ha introdotto un bug.
  • Provare un esperimento usa e getta — fai alcuni commit sperimentali, decidi che erano un vicolo cieco, e vai avanti senza lasciare un branch dietro di te.

Perché è importante

Guardarsi intorno in un detached HEAD è perfettamente sicuro — è proprio questo il suo scopo. Il pericolo appare solo quando si fa un commit lì. Poiché nessun branch tiene traccia del tuo lavoro, quei nuovi commit sono raggiungibili solo attraverso HEAD stesso. Nel momento in cui passi a un altro branch, HEAD si sposta e niente punta più ai commit che hai fatto. Diventano "dangling": ancora nel repository per un po', ma senza alcun riferimento che li mantenga, e alla fine vengono rimossi dalla garbage collection.

La soluzione è semplice — dai un nome a quei commit prima di andartene.

Conservare il lavoro fatto in un detached HEAD

Se hai fatto commit in un detached HEAD e vuoi conservarli, crea un branch prima di spostarti. Questo àncora i commit a un nome:

git switch -c my-rescued-work

I tuoi commit distaccati ora vivono sul nuovo branch, al sicuro e raggiungibili. L'equivalente con il vecchio comando è git checkout -b my-rescued-work.

Una procedura completa

Ecco l'intero ciclo — distacca, fai il commit, poi salva il lavoro:

git checkout a1b2c3d          # detach HEAD onto an old commit
# ... edit files ...
git commit -am "Experiment"   # commit lives only on HEAD now
git switch -c experiment      # name it -> commit is now safe on a branch
git log --oneline experiment  # the new commit is reachable by name

Una volta creato il branch, puoi fare il merge, il rebase, o eliminarlo come qualsiasi altro branch.

Tornare alla normalità

Per uscire da un detached HEAD senza conservare nuovi commit, basta passare a un branch:

git switch main

Se hai fatto commit nello stato distaccato, hai dimenticato di creare un branch, e ti sei già spostato altrove, non farti prendere dal panico — git reflog registra ogni posizione visitata da HEAD, inclusi i commit su cui nessun branch punta. Trova l'hash del commit perso lì e recuperalo su un nuovo branch:

git reflog
# a1b2c3d HEAD@{1}: commit: Experiment   <- your lost commit
# 8120552 HEAD@{2}: checkout: moving from main to 8120552
git switch -c recovered a1b2c3d

Le voci del reflog scadono (90 giorni di default per la cronologia raggiungibile, 30 per quella non raggiungibile), quindi recupera prima piuttosto che dopo.

Argomenti correlati

  • git switch — il modo moderno e più sicuro per spostarsi tra i branch.
  • git checkout — il comando originale che può sia cambiare branch sia distaccare HEAD.
  • git branch — crea il branch che salva il lavoro in detached HEAD.
  • git reflog — recupera i commit dopo aver già lasciato un detached HEAD.
  • git tag — fare il checkout di un tag è un modo comune per trovarsi in un detached HEAD.

Esercitazione

Pratica
Quali affermazioni sul detached HEAD sono corrette?
Quali affermazioni sul detached HEAD sono corrette?
Was this page helpful?