为什么`master`和`heads/master`之间有区别? [英] Why is there a difference between `master` and `heads/master`?
问题描述
我正在编写一个shell脚本,该脚本将切换到指定的提交,在/tmp
中创建索引的副本,将HEAD
重置为原始位置,然后在临时目录中运行命令:
I'm writing a shell script which switches to a specified commit, makes a copy of the index in /tmp
, resets HEAD
to original position, then runs a command in the temporary directory:
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
时相同的分离头状态"消息:
However, this script gives me the same "'detached HEAD' state" message as when I run 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
的位置?
How can I store and restore the position of HEAD
properly?
我宁愿避免使用reset HEAD@{1}
,因为这看起来很混乱.
I would prefer to avoid using reset HEAD@{1}
, as that seems messy.
推荐答案
大多数git命令实际上并不关心名称是否为分支名称.明显的例外(可能更多,这些不在我的脑海中)是git branch
,当然还有git checkout
.
Most git commands don't really care whether a name is a branch name. The obvious exceptions (there may be more, these are off the top of my head) are git branch
and, of course, git checkout
.
For the non-exceptions, the rules for resolving branch names to SHA-1s are listed in gitrevisions
. For git branch
it's easier: some arguments are obviously branch-names, e.g., in git branch new/branch/name
, new/branch/name
is a branch name, even though it presumably doesn't exist yet.
checkout
命令无法执行此操作:给定git checkout xyz
,xyz
可能是分支名称或标记名称,或
The checkout
command can't do that: given git checkout xyz
, xyz
might be a branch name, or a tag name, or any of the other forms in gitrevisions
. Of course, to be one of the funny syntax forms like HEAD~5
it has to have the special ~
character in it, but even an unadorned name might be a branch name, or might not. (If it follows -b
, as in git checkout -b new/branch
then is is definitely a branch-name, but that's not the case here.)
无论如何,简短的答案是git checkout
有其自己的特殊规则,与
Anyway, the short answer is that git checkout
has its own special rules, different from those listed in gitrevisions
: a name is a branch name if adding refs/heads/
in front works to turn it into an existing branch name.
由于refs/heads/refs/heads/master
不是现有的分支名称,因此此操作失败,并显示refs/heads/master
. 1 因此,您需要自己剥离refs/heads/
部分.
This fails with refs/heads/master
since refs/heads/refs/heads/master
is not an existing branch name.1 Hence you need to strip off the refs/heads/
part yourself.
您可以事后进行此操作,但是有一个更简单的版本:git symbolic-ref
具有--short
可以保留refs/heads/
部分.由于HEAD
应该仅是对分支的符号引用(例如,永远都不是对标记的符号引用),并且您知道自己正在查询HEAD
,因此只需执行以下操作:
You could do this after-the-fact, but there's an easier version: git symbolic-ref
has --short
to leave the refs/heads/
part off. Since HEAD
should only be a symbolic reference to a branch (never a symbolic ref to a tag for instance), and you know you're inquiring about HEAD
, just do:
orig_head=$(git symbolic-ref -q --short HEAD)
您还需要一点一点,那就是要记住系统是否以分离的HEAD状态开始,如果是,还附带什么SHA-1.所以:
You do need one more bit, which is to remember whether the system was in detached HEAD state to start with, and if so, what SHA-1 that goes with. So:
sha1=$(git rev-parse HEAD) || exit 1 # should never fail
orig_head=$(git symbolic-ref -q --short HEAD) && symbolic=true || symbolic=false
或类似的内容.
1 您可以创建这样的分支.别. :-)
1You can create such a branch. Don't. :-)
这篇关于为什么`master`和`heads/master`之间有区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!