Che cos'è HEAD in Git?


Risposte:


775

Puoi pensare a HEAD come al "ramo attuale". Quando si cambia ramo con git checkout, la revisione HEAD cambia per puntare alla punta del nuovo ramo.

Puoi vedere a cosa punta HEAD facendo:

cat .git/HEAD

Nel mio caso, l'output è:

$ cat .git/HEAD
ref: refs/heads/master

È possibile che HEAD faccia riferimento a una revisione specifica che non è associata al nome di un ramo. Questa situazione si chiama HEAD distaccato .


53
Quindi git HEAD dipende dal contesto in cui ti trovi, giusto? Ancora di più, tu come sviluppatore? Immagino di chiedere: Git HEAD sarà una cosa globale a livello di repository o un individuo per ogni sviluppatore?
bobobobo,

91
@bobobobo: Esatto, HEAD è come un puntatore che punta al ramo corrente. Quando effettui il checkout di un altro ramo, HEAD cambia in modo da puntare a quello nuovo. L'attuale HEAD è locale per ciascun repository ed è quindi individuale per ogni sviluppatore.
Greg Hewgill,

16
@Meng Questo mi ha aiutato, spero che aiuti: marklodato.github.com/visual-git-guide/index-en.html
raphael

54
@ 動靜 能量: HEAD può puntare a qualsiasi commit, non è necessario che sia l'ultimo commit in nessun ramo. (Quando HEAD punta a un commit che non è l'ultimo commit in un ramo, si tratta di un "HEAD distaccato").
Greg Hewgill,

127
HEAD non è "il ramo corrente". È il nome assegnato al commit da cui è stato inizializzato lo stato corrente dell'albero di lavoro. In termini più pratici, può essere considerato come un riferimento simbolico al commit verificato.
Ben Collins,

184

Per citare altre persone :

Una testa è semplicemente un riferimento a un oggetto commit. Ogni testa ha un nome (nome del ramo o nome del tag, ecc.). Per impostazione predefinita, in ogni repository è presente un head chiamato master. Un repository può contenere qualsiasi numero di teste. In qualsiasi momento, una testa viene selezionata come "testa corrente". Questa testa è alata con HEAD, sempre in maiuscolo ".

Nota questa differenza: una "testa" (minuscola) si riferisce a una delle teste nominate nel repository; "HEAD" (maiuscolo) si riferisce esclusivamente alla testa attualmente attiva. Questa distinzione viene usata frequentemente nella documentazione di Git.

Un'altra buona fonte che copre rapidamente il funzionamento interno di git (e quindi una migliore comprensione delle teste / HEAD) può essere trovata qui . I riferimenti (ref :) o head o branch possono essere considerati come post-it bloccati su commit nella cronologia dei commit. Di solito indicano la punta di una serie di commit, ma possono essere spostati con git checkouto git resetecc.


Da questo: "Ogni testa ha un nome". E "una testa è selezionata come" testa corrente ". Questa testa è aliasata per HEAD ". Concludo quindi che "HEAD" non si riferisce alla situazione di stato "HEAD distaccato".
gxyd,

1
@gxyd se HEAD non indica una 'testa', è una testa staccata. Indica l'id di commit del commit specificato (utilizzando, ad esempio, git checkout HEAD~2), che non è l'id di commit di un capo noto. Vedi l'articolo su eagain.net/articles/git-for-computer-scientists per una spiegazione più approfondita.
Silfheed,

1
@Silfheed: in genere penso che questa risposta sia concettualmente più valida di quella accettata (anche se l'uso di una "testa" minuscola per riferirsi a un ramo confonde molte persone). Tuttavia, git revertnon è un buon esempio di spostamento di un ramo per non essere in punta, perché git revertcrea solo alcuni nuovi commit e lascia comunque il ramo corrente in corrispondenza del (nuovo) suggerimento.
LarsH

1
"che non è l'ID commit di un head noto" - In realtà, un HEAD distaccato può puntare a un ID commit che è anche l'ID commit di un head noto (o più head). Ciò che lo distingue è che HEAD punta direttamente all'ID commit, non a un head. Ciò influenzerà il comportamento dei futuri commits, resets, ecc.
LarsH

1
@LarsH: buon punto su una HEAD staccata che punta a un ID commit anziché a un riferimento. Puoi effettivamente verificarlo guardando .git / HEAD. Se è staccato, conterrà l'hash di un commit, anche se è lo stesso commit di un head noto. Se è attaccato, conterrà il percorso verso la testa (es. 'Ref: refs / heads / bob'). Per quanto riguarda il comando di ripristino, dopo 8 anni non ho mai preso quel refuso. Git reset è ciò che ti consente di regolare una testa particolare per puntare a un particolare commit.
Silfheed

62

Consiglio questa definizione dallo sviluppatore di github Scott Chacon [ riferimento video ]:

Head è il tuo ramo attuale. È un riferimento simbolico. È un riferimento a un ramo. Hai sempre HEAD, ma HEAD indicherà uno di questi altri puntatori, uno dei rami su cui ti trovi. È il genitore del tuo prossimo commit. È quello che dovrebbe essere quello che è stato estratto per ultimo nella directory di lavoro ... Questo è l'ultimo stato noto di quale fosse la directory di lavoro.

L'intero video fornirà una buona introduzione all'intero sistema git, quindi ti consiglio anche di guardarlo tutto se ne hai il tempo.


34
Quindi la vera definizione è "il genitore del tuo prossimo commit"
nicolas

1
e anche "la cosa che punta al prossimo ramo che si sposterà"
nicolas

@nicolas - Non penso sia vero. HEAD può puntare a qualsiasi commit, non deve necessariamente puntare a un ramo - in caso contrario, ci si trova in modalità "staccata HEAD".
scubbo,

23
Il video è fantastico, ma sfortunatamente è una risposta inadatta per Stack Overflow. Che cosa succede se il video verrà rimosso in futuro? Quindi il tuo link non punta a nulla. Una risposta migliore dovrebbe includere una trascrizione di ciò che Scott dice nel video.

2
Scott afferma che HEAD è un puntatore a un ramo. Ma HEAD può indicare anche vecchi impegni. Questo è talmente confuso.
Fixee,

60

HEAD è solo un puntatore speciale che punta al ramo locale in cui ti trovi attualmente.

Dal libro Pro Git , capitolo 3.1 Git Branching - Branches in a Nutshell , nella sezione Creazione di un nuovo ramo :

Cosa succede se si crea una nuova filiale? Bene, così facendo si crea un nuovo puntatore per muoversi. Supponiamo che tu crei un nuovo ramo chiamato testing. Puoi farlo con il comando git branch:

$ git branch testing 

Questo crea un nuovo puntatore allo stesso commit in cui ti trovi attualmente

inserisci qui la descrizione dell'immagine

Come fa Git a sapere su quale ramo sei attualmente? Mantiene un puntatore speciale chiamato HEAD. Nota che questo è molto diverso dal concetto di HEAD in altri VCS a cui potresti essere abituato, come Subversion o CVS. In Git, questo è un puntatore al ramo locale in cui ti trovi attualmente. In questo caso, sei ancora padrone. Il comando git branch ha creato solo un nuovo ramo - non è passato a quel ramo.

inserisci qui la descrizione dell'immagine


4
Bene, potrei usare un'immagine che mostra il caso HEAD distaccato
Don Hatch,

@DonHatch, buona spiegazione di HEAD stackoverflow.com/a/35301963/1074179
Alexandr

3
Bella risposta. Le filiali non sono altro che commit con etichetta, quando si effettuano nuovi commit, questa etichetta viene spostata nel nuovo nuovo commit. Quando esegui il checkout di un commit che non ha un'etichetta, si trova nello stato HEAD distaccato. Ciò significa che HEAD punta a un commit che non ha un'etichetta branch. Se fai il checkout 34ac2nell'esempio sopra, ora HEAD punta a quel commit e si chiama HEAD distaccato. In questo stato, è possibile apportare modifiche, sperimentare e anche eseguire il commit delle modifiche, ma una volta verificato un ramo diverso, si perderanno tutte le modifiche, a meno che ovviamente non si crei un nuovo ramo.
sleepwalkerfx,

1
@sleepwalkerfx ma puoi effettuare il checkout di un commit che ha un'etichetta di ramo e che si trova ancora in uno stato head separato perché HEAD non punta più all'etichetta del ramo ma l'id di commit del ramo
Marc

1
@sleepwalkerfx Penso che stiamo parlando di semantica a questo punto. Hai ragione, un'etichetta di diramazione è un riferimento testuale a un particolare commit. Non è, tuttavia, un impegno. Quindi, se hai fatto un git loge ottenuto qualcosa del genere commit ad0265... HEAD -> foo ...significherebbe che il fooramo è un riferimento a commit id ad0265. Fare un checkout del riferimento testuale foonon è una testa staccata. Fare un checkout dell'ID commit ad0265si tradurrebbe in una testa staccata. Forse mi sto perdendo un po 'di delicatezza di ciò che stai comunicando. Spero che questo muro di testo aiuti a scoprire dove mi sono perso.
Marc

40

Supponendo che non si tratti di un caso speciale chiamato "TESTA staccata", quindi, come indicato nel libro di O'Reilly Git, 2a edizione, p.69, HEADsignifica:

HEADfa sempre riferimento al commit più recente sul ramo corrente. Quando si modificano i rami, HEADviene aggiornato per fare riferimento all'ultimo commit del nuovo ramo.

così

HEADè la "punta" del ramo corrente .

Si noti che possiamo utilizzare HEADper fare riferimento al commit più recente e utilizzare HEAD~come commit prima del suggerimento e HEAD~~o HEAD~2come commit anche prima e così via.


27

C'è un malinteso, forse sottile, ma importante in un numero di queste risposte. Ho pensato di aggiungere la mia risposta per chiarirla.

Che cosa è HEAD?

HEAD sei TU

HEADè un riferimento simbolico che punta a dove ti trovi nella cronologia dei commit. Ti segue ovunque tu vada, qualunque cosa tu faccia, come un'ombra. Se effettui un commit, HEADsi sposterà. Se fai il checkout, HEADsi sposterà. Qualunque cosa tu faccia, se ti sei trasferito in un posto nuovo nella tua cronologia di commit, si HEADè spostato insieme a te. Per affrontare un malinteso comune: non puoi staccartiHEAD . Non è questo lo stato HEAD distaccato. Se mai ti ritrovi a pensare: "oh no, sono nello stato HEAD distaccato! Ho perso la HEAD!" Ricorda, è la tua TESTA. HEAD sei tu. Non ti sei staccato dalla TESTA, tu e la tua TESTA avete staccato da qualcos'altro.

A cosa può attaccare HEAD?

HEADpuò indicare un commit, sì, ma in genere non lo fa. Lasciami dire di nuovo. In genere HEADnon punta a un commit. Punta a un riferimento di ramo. È attaccato a quel ramo e quando fai certe cose (es. commitO reset), il ramo attaccato si sposterà insieme HEAD. Puoi vedere a cosa sta puntando guardando sotto il cofano.

cat .git/HEAD

Normalmente otterrai qualcosa del genere:

ref: refs/heads/master

A volte otterrai qualcosa del genere:

a3c485d9688e3c6bc14b06ca1529f0e78edd3f86

Questo è ciò che accade quando HEADpunta direttamente a un commit. Questo è chiamato HEAD distaccato, perché HEADpunta a qualcosa di diverso da un riferimento di ramo. Se effettui un commit in questo stato, masternon essendoti più associato HEAD, non si muoverà più con te. Non importa dove si trovi quel commit. Potresti essere sullo stesso commit del tuo ramo master, ma se HEADpunta al commit anziché al ramo, viene rimosso e un nuovo commit non verrà associato a un riferimento di ramo.

Puoi osservarlo graficamente se provi il seguente esercizio. Da un repository git, esegui questo. Otterrai qualcosa di leggermente diverso, ma i loro bit chiave saranno lì. Quando è il momento di verificare direttamente il commit, usa qualsiasi hash abbreviato che ottieni dal primo output (eccolo a3c485d).

git checkout master
git log --pretty=format:"%h:  %d" -1
# a3c485d:   (HEAD -> master)

git checkout a3c485d -q # (-q is for dramatic effect)
git log --pretty=format:"%h:  %d" -1   
# a3c485d:   (HEAD, master)

OK, quindi c'è una piccola differenza nell'output qui. Il controllo diretto del commit (invece del ramo) ci dà una virgola anziché una freccia. Cosa ne pensi, siamo in uno stato HEAD distaccato? HEAD fa ancora riferimento a una revisione specifica associata al nome di un ramo. Siamo ancora nel ramo principale, vero?

Ora prova:

git status
# HEAD detached at a3c485d

No. Siamo nello stato "HEAD distaccato".

Puoi vedere la stessa rappresentazione di (HEAD -> branch)vs. (HEAD, branch)con git log -1.

In conclusione

HEADsei tu. Indica qualsiasi cosa tu abbia verificato, ovunque tu sia. In genere questo non è un commit, è un ramo. Se HEAD indica un commit (o tag), anche se è lo stesso commit (o tag) a cui punta anche un ramo, tu (e HEAD) sei stato staccato da quel ramo. Dal momento che non hai un ramo attaccato a te, il ramo non ti seguirà mentre fai nuovi commit. HEAD, tuttavia, lo farà.


1
Mi piace questa risposta, perché mentre la documentazione descrive la verità, il software definisce la verità. .git/HEADè ciò che il software considera HEAD.
Don Branson,

2
Solo per la sua definizione concettuale, questa dovrebbe essere la risposta accettata.
ata

22

HEADsi riferisce al commit corrente a cui punta la tua copia di lavoro, ovvero il commit che hai attualmente estratto. Dalla documentazione ufficiale del kernel Linux su come specificare le revisioni di Git :

HEAD nomina il commit su cui hai basato le modifiche nell'albero di lavoro.

Si noti, tuttavia, che nella prossima versione 1.8.4 di Git, @può anche essere usato come scorciatoia per HEAD, come notato dal collaboratore di Git Junio ​​C Hamano nel suo blog Git Blame :

Invece di digitare "HEAD", puoi invece pronunciare "@", ad esempio "git log @".

L'utente di Stack Overflow VonC ha anche trovato alcune informazioni interessanti sul perché è @stato scelto come scorciatoia nella sua risposta a un'altra domanda .

Inoltre, in alcuni ambienti non è necessario capitalizzare HEAD, in particolare nei sistemi operativi che utilizzano file system senza distinzione tra maiuscole e minuscole, in particolare Windows e OS X.


17

Dai un'occhiata a Creare e giocare con i rami

HEAD è in realtà un file il cui contenuto determina dove si riferisce la variabile HEAD:

$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
35ede5c916f88d8ba5a9dd6afd69fcaf773f70ed

In questo repository, il contenuto del file HEAD si riferisce a un secondo file chiamato refs / heads / master . Il file refs / heads / master contiene l'hash del commit più recente sul ramo master.

Il risultato sono i punti HEAD sul commit della diramazione principale dal file .git / refs / heads / master .

inserisci qui la descrizione dell'immagine


1
Attenzione: il link gitguys.com sembra indicare un dominio parcheggiato.
MKesper,

14

Vorrei solo dettagliare alcune cose nella risposta accettata da Greg Hewgil. Secondo la Guida tascabile Git

Ramo:

il ramo stesso è definito come tutti i punti raggiungibili nel grafico di commit dal commit denominato (il "suggerimento" del ramo).

TESTA: un tipo speciale di rif

Lo speciale riferimento HEAD determina su quale ramo ti trovi ...

refs

Git definisce due tipi di riferimenti, o puntatori denominati, che chiama "refs":

  • Un semplice riferimento, che punta direttamente a un ID oggetto (di solito un commit o tag)
  • Un riferimento simbolico (o symref), che indica un altro riferimento (semplice o simbolico)

Come ha detto Greg, HEAD può essere in uno "stato distaccato". Quindi HEAD può essere sia un semplice ref (per una HEAD distaccata) che un symref.

se HEAD è un riferimento simbolico per un ramo esistente, allora sei su quel ramo. Se, d'altra parte, HEAD è un semplice ref che nomina direttamente un commit dal suo ID SHA-1, allora non sei "su" alcun ramo, ma piuttosto in modalità "staccata HEAD", che si verifica quando dai un'occhiata ad alcuni precedenti impegnarsi a esaminare.


Grazie @mike! Questa è la prima risposta che chiarisce cosa succede quando si verifica un commit precedente. Guardando il libro sul sito web di Git, ho avuto l'impressione che una "TESTA distaccata" fosse uno stato patologico in cui ti sei imbattuto solo se hai fatto qualcosa di strano. Ma verificare un commit precedente non è una cosa strana da fare, e quando lo fai, HEAD non è "la punta del ramo corrente". Quindi questa è la prima volta che mi sembra di capire davvero.
Nat Kuhn,

7

Penso che "HEAD" sia il commit del check out corrente. In altre parole, "HEAD" indica il commit attualmente verificato.

Se hai appena clonato e non verificato, non so a cosa faccia riferimento, probabilmente una posizione non valida.


Sì, il riferimento speciale HEADè qualsiasi commit attualmente sottoposto a check-out. Consultare il manuale per i dettagli (il paragrafo pertinente segue immediatamente la Fig 3.4).
Calrion,

1
Se cloni un repository, git controllerà di default il masterramo - quindi HEAD punterà a master.
sleske,

1
@sleske se cloni un repository senza opzioni speciali git verificherà la testa remota. di solito lo è master, ma non è sempre. Vediremote set-head
De Novo

Il mio commento precedente era corretto, tranne per il riferimento a remote set-head, che influisce solo sul ramo predefinito locale e non modificherà il valore predefinito sul server.
De Novo,

5

Testa punta sulla punta del ramo attualmente estratto.

inserisci qui la descrizione dell'immagine

Nel tuo repository, c'è una cartella .git. Apri il file in questa posizione: .git \ refs \ heads. Il codice (sha-1 hash) in quel file (master nella maggior parte dei casi) sarà il commit più recente, cioè quello visto nell'output del comando git log. Maggiori informazioni sulla cartella .git: http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html


1
È un'idea sbagliata comune che la punta dell'attuale ramo punti al commit più recente. In genere è vero, ma non è raro git reset HEAD^, quindi il commit più recente (il precedente suggerimento) non è più indicato dalla punta del ramo.
LarsH

4

Un ottimo modo per portare a casa il punto fatto nelle risposte corrette è quello di eseguire git reflog HEAD, si ottiene una cronologia di tutti i punti indicati da HEAD.


4

Dopo aver letto tutte le risposte precedenti, volevo ancora più chiarezza. Questo blog sul sito Web ufficiale di git http://git-scm.com/blog mi ha dato quello che stavo cercando:

The HEAD: puntatore all'ultima istantanea del commit, genitore successivo

HEAD in Git è il puntatore al riferimento di ramo corrente, che a sua volta è un puntatore all'ultimo commit che hai fatto o all'ultimo commit che è stato estratto nella tua directory di lavoro. Ciò significa anche che sarà il genitore del prossimo commit che fai. In genere è più semplice pensarci perché HEAD è l'istantanea del tuo ultimo commit.


1
L'HEAD: ultima commit dello snapshot, il prossimo genitore non è preciso. HEADnon è un commit; si punta a uno.
jub0bs,

Non c'è bisogno di sarcasmo; prima della modifica, anche se la citazione era accurata, le grandi lettere in grassetto erano una semplificazione e un po 'fuorvianti. Ora va meglio.
jub0bs,

1
SE leggi la riga successiva: HEAD in Git è il puntatore al riferimento di ramo corrente, che a sua volta è un puntatore all'ultimo commit che hai fatto o all'ultimo commit che è stato estratto nella tua directory di lavoro. - Si prega di notare l'uso della parola "puntatore" lì.
user3751385,

Mentre la descrizione dell '"ultima istantanea del commit" dà un'idea concettuale del modo in cui si suppone che debba essere utilizzato HEAD, in realtà non è preciso. Se eseguo un commit, quindi passaggio a un altro ramo, HEAD non punta più all'ultima istantanea del commit. Punta all'ultima istantanea di commit sul ramo in cui sono appena passato. Se io checkout HEAD^, ora HEAD non punta nemmeno all'ultima istantanea di commit su nessun ramo.
LarsH

"Il genitore del tuo prossimo commit (se dovessi impegnarti in questo momento)" è più preciso, ma ci sono molte altre operazioni in git oltre al commit che sono influenzate da HEAD. In realtà, alla fine, è HEAD HEAD, e la sua natura è definita da come influisce comandi come commit, merge, rebase, log, ecc, ma concettualmente forse "(puntatore) la posizione attuale" è la sintesi buona.
LarsH

3

Sembra che HEADsia solo un tag per l'ultimo commit che hai verificato.

Questa può essere la punta di un ramo specifico (come "master") o un commit intermedio di un ramo ("testa staccata")


1

Oltre a tutte le definizioni, la cosa che mi è rimasta impressa nella mente è stata, quando si effettua un commit, GIT crea un oggetto commit all'interno del repository. Gli oggetti commit devono avere un genitore (o più genitori se si tratta di un commit di unione). Ora, come fa Git a conoscere il genitore dell'attuale commit? Quindi HEAD è un puntatore al (riferimento dell'ultimo) commit che diventerà il genitore del commit corrente.


0

Questi due potrebbero confonderti:

testa

Puntando a riferimenti nominati un ramo ha inviato di recente. A meno che non si utilizzi il riferimento al pacchetto, head viene in genere archiviato in $ GIT_DIR / refs / heads /.

TESTA

Ramo corrente, o il tuo albero di lavoro è generalmente generato dall'albero a cui punta HEAD. HEAD deve puntare a una testa, tranne per il fatto che stai usando una HEAD staccata.


0

Dai un'occhiata a http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is

Figura 3-5 File HEAD che punta al ramo in cui ti trovi.


4
Le risposte ai link sono generalmente disapprovate su StackOverflow, si prega di inserire le informazioni pertinenti nella risposta.
HaskellElephant

2
Questo non è del tutto corretto. Ciò che si HEADriferisce dipende dal fatto che tu stia parlando di un repository bare vs un non-bare. Nel contesto di un repository non nudo, si riferisce effettivamente al commit attualmente estratto, che non richiede che vi sia un ramo ad esso collegato (ovvero quando si trova in HEADstato distaccato ).

0

Un ramo è in realtà un puntatore che contiene un ID commit come 17a5 . HEAD è un puntatore a un ramo su cui l'utente sta attualmente lavorando.

HEAD ha un file di riferimento che assomiglia a questo:

ref:

È possibile controllare questi file accedendo .git/HEAD .git/refsal repository in cui si sta lavorando.


0

Gitsi tratta di impegni.
E Headindica il commit che hai attualmente verificato.

$ git cat-file -t HEAD
commit

Ogni volta che esegui il checkout di un ramo, HEAD punta all'ultimo commit su quel ramo. I contenuti di HEAD possono essere controllati come di seguito (per il ramo master):

$ cat .git/refs/heads/master
  b089141cc8a7d89d606b2f7c15bfdc48640a8e25

-5

Come concetto, la testa è l'ultima revisione in un ramo. Se hai più di una testa per ramo nominato, probabilmente lo hai creato quando esegui commit locali senza unire, creando effettivamente un ramo senza nome.

Per avere un repository "pulito", dovresti avere una testa per ramo nominato e unirti sempre a un ramo nominato dopo aver lavorato localmente.

Questo vale anche per Mercurial .


4
Questo è vero per Mercurial, ma non per Git.
Ripristina Monica - notmaynard,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.