为什么 `master` 和 `heads/master` 有区别?

Why is there a difference between `master` and `heads/master`?

我正在编写一个 shell 脚本,它切换到指定的提交,复制 /tmp 中的索引,将 HEAD 重置为原始位置,然后 运行s 临时目录中的命令:

orig_head=$(git rev-parse -q HEAD)  # "refs/heads/master"
git checkout ""
# copy index to /tmp/...
git checkout "$orig_head"
# run command in /tmp/...

然而,这个脚本给了我相同的“'detached HEAD' state”消息,就像我 运行 git checkout refs/heads/master:

Note: checking out 'refs/heads/master'.

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.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at c82ad67... Use vector and binary search for dictionary

如何正确存储和恢复 HEAD 的位置?

我宁愿避免使用 reset HEAD@{1},因为那看起来很乱。

大多数 git 命令并不真正关心名称是否为分支名称。明显的例外(可能还有更多,这些超出了我的想象)是 git branch,当然还有 git checkout.

对于非例外情况,gitrevisions 中列出了将分支名称解析为 SHA-1 的规则。对于 git branch 更容易:一些参数显然是分支名称,例如,在 git branch new/branch/name 中,new/branch/name 是一个分支名称,即使它可能还不存在。

checkout 命令无法做到这一点:给定 git checkout xyzxyz 可能是分支名称、标记名称或 [= 中的任何其他形式37=]。当然,要成为像 HEAD~5 这样有趣的语法形式之一,它必须在其中包含特殊的 ~ 字符,但即使是朴素的名称也可能是分支名称,也可能不是。 (如果它跟在 -b 之后,如 git checkout -b new/branch 那么 is 绝对是一个分支名称,但这里不是这种情况。)

无论如何,简短的回答是 git checkout 有自己的特殊规则,与 gitrevisions 中列出的不同:如果名称在前面加上 refs/heads/ 则为分支名称把它变成一个现有的分支名称。

由于 refs/heads/refs/heads/master 不是现有的分支名称,因此 refs/heads/master 失败。1 因此您需要删除 refs/heads/ 部分你自己。

您可以在事后执行此操作,但有一个更简单的版本:git symbolic-ref--shortrefs/heads/ 部分关闭。由于 HEAD 应该 只是对分支的符号引用(例如,绝不是对标记的符号引用),并且您知道您正在查询 HEAD , 只需做:

orig_head=$(git symbolic-ref -q --short HEAD)

你还需要一点,那就是记住系统是否处于分离的 HEAD 状态,如果是,那么它的 SHA-1 是什么。所以:

sha1=$(git rev-parse HEAD) || exit 1 # should never fail
orig_head=$(git symbolic-ref -q --short HEAD) && symbolic=true || symbolic=false

或类似的东西。


1可以创建这样一个分支。不。 :-)

master是一种指针,指向master分支的最新提交。

refs/heads/master 是一种历史跟踪器,它跟踪 master 指针的活动,如提交、切换到其他分支,在 github 等

上推送 master 分支