(注意:其中一些是通用的。)
这里的额外怪异可能与每个工作树都有自己的私有HEAD
文件这一事实有关。不同的操作可能会HEAD
通过 case-folding 找到不同的文件:添加的工作树有一个文件,主工作树有一个文件。如果操作A选择匹配,而操作B选择,您会看到这种行为。使用全大写应该让 Git 做正确的事。.git/worktrees/worktree/HEAD
.git/HEAD
.git/HEAD
head
.git/worktrees/worktree/HEAD
HEAD
(特别是,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 上,因为现在有两种解决方法:作为分支或标记,以及作为. 最好不要这样做。head
head
.git/HEAD