为什么工作树中的HEAD指向master中的最高提交?

时间:2019-05-01 15:23:37

标签: git git-worktree

我使用git worktree add创建了一个工作树,并且工作了几天。今天,我想在以前的版本中检出一些代码,所以我暂时分离了HEAD

git checkout head^

找到所需的内容后,我尝试回到工作树分支的顶端:

git checkout <branchname>

但是现在,HEAD指向我的本地master分支中的最高提交。例如:

git show head

显示master中的最新提交。

有什么想法为什么会发生或如何解决?


编辑

我也看到一些奇怪的,不一致的行为。例如,这:

> git reset --hard
HEAD is now at 4f1666467017
> git rev-parse head
e4fab17872cce2f6f37f5b596c7ed2739b135f3f

1 个答案:

答案 0 :(得分:0)

(注意:其中一些是通用的。)

这里额外的怪异可能与每个工作树都有自己的专用HEAD文件这一事实有关。不同的操作可能会通过大小写折叠找到不同的HEAD文件:添加的工作树有一个.git/worktrees/worktree/HEAD文件,而主工作树有一个.git/HEAD文件。如果操作 A 选择.git/HEAD来匹配head,而操作 B 选择.git/worktrees/worktree/HEAD,则您会看到这种情况。使用全键盘HEAD 应该使Git做正确的事。

(特别是git reset --hard在所有大写内部使用HEAD,这是指每个工作树HEAD,而git rev-parse head使用小写的{{1 }},它将引用head文件。)


您可以通过其原始哈希ID来查看任何历史提交:

.git/HEAD

结果就是Git所说的分离头。通常,特殊名称git checkout a123456 (用大写字母表示)是附加,并附加到分支名称:

HEAD

(此处的大写字母代表实际的提交哈希ID)。通过像这样附加,...--A--B--C--D <-- master (HEAD) \ E--F--G <-- branch 意味着HEAD,这意味着提交master。因此,您当前的提交现在就是任何提交D的真实哈希ID。如果您运行:

D

您得到:

git checkout branch

,这意味着您当前的分支...--A--B--C--D <-- master \ E--F--G <-- branch (HEAD) ,而您当前的 commit 现在为branch

但是,当您通过哈希ID选择提交时(例如,提交G,则使E指向该提交:

HEAD

这就是Git所说的“分离头”;您当前的提交是提交...--A--B--C--D <-- master \ E <-- HEAD \ F--G <-- branch

现在,您没有使用原始哈希ID。相反,您键入了E。但是有很多命名提交的方法。原始哈希ID是最低级别的方法:哈希ID始终有效,并且始终表示一个特定的提交,但是您也可以让Git查找某个提交的 parent 。这就是head^的含义:选择当前提交的父级。假设当前提交为HEAD^,因为您在G上;然后branch个名称提交HEAD^,之后:

F

您将拥有:

git checkout HEAD^

小写版本...--A--B--C--D <-- master \ E--F <-- HEAD \ G <-- branch 在Windows和MacOS上有效,但在Linux上无效。这是以下事实的副作用:Git有时会将这些内容存储在文件中(例如head.git/HEAD)。使用.git/refs/heads/master而非head,Git可能会尝试打开不存在的HEAD,但是当Git尝试打开.git/refs/heads/head时,它会得到.git/head确实存在。因此,在这些计算机上的 中,.git/HEADgit checkout head^的含义相同:找到当前的提交,退回到其第一个父提交,并检查那个提交。

要将git checkout HEAD^重新附加到某个分支,请使用HEAD

如果您不在Windows或MacOS上(即使您不在),请注意,您也可以 创建一个名为git checkout branch-name分支或标签 。如果这样做,事情会变得有些混乱,尤其是在Windows和MacOS上,因为现在有两种 解析方式head:分支或标记,以及head 。最好不要这样做。