(注意:其中一些是通用的。)
这里的额外怪异可能与每个工作树都有自己的私有HEAD文件这一事实有关。不同的操作可能会HEAD通过 case-folding 找到不同的文件:添加的工作树有一个文件,主工作树有一个文件。如果操作A选择匹配,而操作B选择,您会看到这种行为。使用全大写应该让 Git 做正确的事。.git/worktrees/worktree/HEAD.git/HEAD.git/HEADhead.git/worktrees/worktree/HEADHEAD
(特别是,git reset --hard内部使用HEAD所有大写字母,这将引用 per-work-tree HEAD,而git rev-parse head使用小写字母head,它将引用.git/HEAD文件。)
您可以通过其原始哈希 ID 检查任何历史提交:
git checkout a123456
结果就是 Git 所说的分离的 HEAD。通常,特殊名称HEAD(全部大写)附加到分支名称:
...--A--B--C--D <-- master (HEAD)
\
E--F--G <-- branch
(这里的大写字母代表实际的提交哈希 ID)。通过像这样被附加,HEAD意味着master这意味着 commit D。因此,您当前的提交现在就是 commitD的真实哈希 ID。如果你运行:
git checkout branch
你得到:
...--A--B--C--D <-- master
\
E--F--G <-- branch (HEAD)
这意味着您当前的分支是branch并且您当前的提交是 now G。
但是,当您通过哈希 ID 选择提交时——比如说提交E——你HEAD直接指向那个提交:
...--A--B--C--D <-- master
\
E <-- HEAD
\
F--G <-- branch
这就是 Git 所说的“分离的 HEAD”;您当前的提交是 commit E。
现在,您没有使用原始哈希 ID。相反,您输入了head^. 但是有很多方法可以命名提交。原始哈希 ID 是最低级别的方式:哈希 ID 始终有效并且始终意味着一个特定的提交,但您也可以让 Git 找到某个提交的父级。这就是HEAD^意思:选择当前提交的父级。假设当前提交是G因为你在branch;然后HEAD^命名 commit F,然后:
git checkout HEAD^
你将会有:
...--A--B--C--D <-- master
\
E--F <-- HEAD
\
G <-- branch
小写版本head适用于 Windows 和 MacOS,但不适用于 Linux。这是 Git 有时将这些东西存储在文件中的副作用(例如.git/HEAD,和.git/refs/heads/master)。使用head而不是HEAD,Git 可能会尝试打开.git/refs/heads/head不存在的,但是当 Git 尝试打开时.git/head,它会得到.git/HEAD,它确实存在。所以在这些机器上,git checkout head^意思是一样的git checkout HEAD^:找到当前的提交,回到它的第一个父节点,然后检查那个提交。
要将您重新附加HEAD到某个分支,请使用.git checkout branch-name
如果您不在 Windows 或MacOS上(或者即使您在),请注意您也可以创建一个名为. 如果你这样做了,事情会变得有点奇怪,尤其是在 Windows 和 MacOS 上,因为现在有两种解决方法:作为分支或标记,以及作为. 最好不要这样做。headhead.git/HEAD