如果我仅使用分支名称签出分支,HEAD
将更新为指向该分支。
$git checkout branch
Switched to branch 'branch'
如果我使用refs/heads/branch
或heads/branch
签出分支,则HEAD
会分离。
$git checkout refs/heads/branch
Note: checking out 'refs/heads/branch'.
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 performing another checkout.
$git checkout "refs/heads/branch"
Same result
$git checkout heads/branch
Same result
为什么呢?如果它的版本依赖,我在Ubuntu 12.04.3上有git 1.7.9.5。
答案 0 :(得分:16)
checkout
命令区分两种情况(好吧,实际上是“很多”,但让我们从两种情况开始:-)):
git checkout branch
。git checkout 6240c5c
。(就个人而言,我认为这些应该使用不同的命令名称,但这只是我。另一方面,它可以消除下面描述的所有奇怪。)
现在,让我们说你想要前者。只需写出分支名称,而不是refs/heads/
部分,这是最容易编写的。
如果你想要后者,你可以通过gitrevisions,中除之外的任何方法为任何导致“进入分支”的方法指定修订。
无论出于何种原因,这里选择的算法 - <branch>
下refs/heads/
下记录的算法 - 是这样的:如果你写了一个名字,那么在添加{{1对它来说,命名一个分支,git checkout
会把你“放在那个分支上”。如果您指定@{-N}
或-
,它将在HEAD
reflog中查找 N - 更早的分支(-
含义{{ 1}})。否则它会选择第二种方法,给你“分离的HEAD”。即使名称是gitrevisions中建议的用于避免歧义的名称,也是如此,即@{-1}
当另一个heads/xyz
时}。 (但是:你可以添加xyz
来避免“上一个分支”的情况,即使它会进入分支机构。)
这也与gitrevisions文档中列出的解析规则相矛盾。为了证明这一点(虽然很难看到),我创建了一个同名的标记和分支,--detach
:
derp2
这使我进入分支,而不是分离并转到标记的修订版。
$ git checkout derp2
warning: refname 'derp2' is ambiguous.
Previous HEAD position was ...
Switched to branch 'derp2'
这向我展示了标记版本,gitrevisions表示应该这样做。
一方面注意:“进入分支”实际上意味着“将分支名称的符号引用放入git目录中名为$ git show derp2
warning: refname 'derp2' is ambiguous.
...
的文件”。符号引用是文字文本HEAD
(带尾随空格),后跟完整的分支名称,例如ref:
。 refs/heads/derp2
要求没有git checkout
部分的名称以添加refs/heads/
部分似乎有点不一致,但这对你来说是git。 :-)可能有一些历史原因:最初,作为一个符号引用,ref: refs/heads/
文件实际上是分支文件的符号链接,它始终是一个文件。这些天,部分是因为Windows,部分是因为代码演变,它有文字HEAD
字符串,引用可能会“打包”,因此无论如何都不能作为单独的文件提供。
相反,“分离的HEAD”实际上意味着“将原始SHA-1放入ref:
文件”。除了在此文件中具有数值之外,git的行为与“在分支上”时的行为方式相同:添加新提交仍然有效,新提交的父级是当前提交。合并仍然可以完成,合并提交的父项是当前和将要合并的提交。 HEAD
文件在发生时随每个新提交一起更新。 1 在任何时候你都可以创建一个指向当前提交的新分支或标签标签,以引起新的提交链即使你关掉了“独立的HEAD”,也可以防止未来的垃圾收集;或者你可以简单地切换掉,让新的提交,如果有的话,用通常的垃圾收集取出。 (请注意,HEAD
reflog会在一段时间内阻止这种情况,我认为默认为30天。)
[ 1 如果您“在某个分支上”,则会发生相同的自动更新,它只会发生到HEAD
引用的分支 。也就是说,如果您在分支 HEAD
上并添加新提交,B
仍然会显示HEAD
,但现在您获得的提交ID使用ref: refs/heads/B
是您刚刚添加的新提交。这就是分支“增长”的方式:在“分支”上添加新提交会导致分支引用自动向前移动。同样,当处于此“分离的HEAD”状态时,添加的新提交会导致git rev-parse B
自动向前移动。]
为了完整起见,这里列出了HEAD
可以做的其他事情,如果我有这样的权力,我可能会把它放在各种单独的命令中:
git checkout
git checkout revspec -- path ...
(加上git checkout -b newbranch
的选项)git branch
(这会使你“在一个尚未存在的分支上”,即写入{{ 1}}进入git checkout --orphan
但不创建分支 ref: refs/heads/branch-name
;这也是HEAD
在新存储库中未出生的分支的方式)branch-name
master
,git checkout -m ...
git checkout --ours
:git checkout --theirs
答案 1 :(得分:2)
你没有检查出一个分支;你只是检查一个恰好是分支机构负责人的提交。分支是单向指针:给定一个分支,您可以确定该分支的头部的确切提交,但是您不能进行任意提交并确定它是哪个分支的头部。因此,如果您要进行新的提交,Git将不知道要更新的分支(如果有)。