概述:在使用git的過程中,我們常常會對其中的HEAD感到疑惑:HEAD是什麼意思?表示目前分支嗎?什麼是處于遊離态的commit點?等等,這些都和一個叫做detached head的狀态有關,我們來看看它的真面目。
通常情況下,HEAD指向一個分支;同時,每一個分支對應一個特定的commit(确切的說,一個分支上可以有多個commit,但是隻有一個頂層commit,而且commit之間是簡單的線性關系)。我們來看下面這個包含三個commit的例子,其中目前在master分支上。
HEAD (refers to branch 'master')
|
v
a---b---c branch 'master' (refers to commit 'c')
^
|
tag 'v2.0' (refers to commit 'b')
在這樣的狀況下,如果進行一次送出,目前分支将指向新的送出點。具體來說,git commit建立了一個新的commit id,它的父節點是的commit的id是C。這個時候,HEAD仍然指向master分支,而且指向commit id是d的送出點。
$ edit; git add; git commit
HEAD (refers to branch 'master')
|
v
a---b---c---d branch 'master' (refers to commit 'd')
^
|
tag 'v2.0' (refers to commit 'b')
有時,如果能夠檢出到一個不在分支頂端的commit點是很有用的(通常情況下,我們直接運作指令git checkout mater,這樣checkout到master的最新commit上);同樣,如果能夠建立一個不屬于任何分支的送出點也是一件很有用的事情。運作接下來的兩條指令,看看會發生什麼。
$ git checkout v2.0 # or
$ git checkout master^^
HEAD (refers to commit 'b')
|
v
a---b---c---d branch 'master' (refers to commit 'd')
^
|
tag 'v2.0' (refers to commit 'b')
注意,現在head已經指向commit b,這就是所謂的dedatched head狀态。從這裡我們也可以看出,head是目前index的狀态,而不是目前分支(的最近commit節點)。這僅僅意味着head指向某個特定的commit點,而不是指向每一個特定的分支(的頂端節點)。如果我們此時送出一個commit,看看将要發生什麼:
$ edit; git add; git commit
HEAD (refers to commit 'e')
|
v
e
/
a---b---c---d branch 'master' (refers to commit 'd')
^
|
tag 'v2.0' (refers to commit 'b')
注意,此時産生了一個新的送出點,但是它隻能被head索引到,不屬于任何一個分支。當然,我們還可以給在這個“無名分支”的基礎上繼續送出。
$ edit; git add; git commit
HEAD (refers to commit 'f')
|
v
e---f
/
a---b---c---d branch 'master' (refers to commit 'd')
^
|
tag 'v2.0' (refers to commit 'b')
實際上,我們可以進行任何git的正常操作。但是,讓我們開看看如果我們運作git checkout master将會發生什麼:
$ git checkout master
HEAD (refers to branch 'master')
e---f |
/ v
a---b---c---d branch 'master' (refers to commit 'd')
^
|
tag 'v2.0' (refers to commit 'b')
此時,我們一定要注意,e f已經處于無法被索引到的狀态。最終e和f将被git的預設回收機制所回收,除非我們在它們被回收之前建立一個指向他們的索引。如果我們沒有從commit f離開的話,可以用接下來的指令建立一個指向f的索引。
$ git checkout -b foo (1)
$ git branch foo (2)
$ git tag foo (3)
1.建立來一個foo分支,指向f,接着更新head指向分支foo,此時,我們不再處在detached head的狀态
2.同樣建立了一個foo分支,但是head仍然指向master分支,仍然處在detached head的狀态。
3.建立了一個新标簽foo,仍處于detached的狀态。
如果我們從f處離開,我們必須首先恢複他的主體名稱,接着我們才可以建立指向它的索引。例如,為了看看最近的兩個由head指向的commit點,我們可以使用如下的指令:
$ git reflog -2 HEAD # or
$ git log -g -2 HEAD
參考文獻:man git-checkout