【问题标题】:Why is there a difference between `master` and `heads/master`?为什么`master`和`heads/master`之间有区别?
【发布时间】:2015-05-02 19:54:32
【问题描述】:

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

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

但是,这个脚本给了我与运行git checkout refs/heads/master 时相同的“'分离 HEAD'状态”消息:

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},因为这看起来很乱。

【问题讨论】:

  • 如果省略“--symbolic”会发生什么?使用“--symbolic”,它似乎返回了无意义的标签“HEAD”,这在您结帐“$1”后没有任何意义。我无法重现 $(git rev-parse --symbolic -q HEAD) 返回“refs/heads/master”的行为,但是...
  • @AndreyTyukin:谢谢,你是对的。使用--symbolic 它根本不起作用,但没有--symbolic 我会收到上面显示的消息。
  • 有趣,我读了它(没有想太多),好像它在上面使用git symbolic-ref,实际上应该使用它(见下面我的答案)。
  • 是的,很奇怪。看来我的潜意识是在正确的轨道上!

标签: git git-checkout


【解决方案1】:

大多数 git 命令并不真正关心名称是否是分支名称。 git branch 当然还有git checkout 是明显的例外(可能还有更多,这些都在我的脑海中)。

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

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

无论如何,简短的回答是git checkout 有自己的特殊规则,与gitrevisions 中列出的规则不同:如果在前面添加refs/heads/ 可以将其变为现有的分支名称,则名称就是分支名称.

refs/heads/master 失败,因为 refs/heads/refs/heads/master 不是现有的分支名称。1 因此,您需要自己剥离 refs/heads/ 部分。

您可以在事后执行此操作,但有一个更简单的版本:git symbolic-ref 具有 --short 以保留 refs/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可以创建这样一个分支。不。 :-)

【讨论】:

  • 有什么理由不这样做:orig_head=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD) || exit 1?
  • 这取决于你想变得多么花哨。例如,rebase 脚本会分别记住您的原始状态和分支名称,以便它可以说出您的位置。如果您只需要回到它,似乎应该可以解决问题。
【解决方案2】:

ma​​ster是一种指向master分支最新提交的指针。

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

【讨论】:

  • 您是在回答问题的标题,而不是回答问题本身...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-03
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 1970-01-01
  • 2016-04-08
相关资源
最近更新 更多