GIT: How to unambiguously reference current HEAD w

2019-01-26 07:18发布

问题:

Even though "HEAD" is definitely a poor choice for the name of a Git branch, it is still a valid branch name. If you happen to have branch named "HEAD", is there a way how to unambiguously refer to the actual HEAD symbolic reference?

The branch can be referenced as refs/heads/HEAD, but what about the HEAD itself?

Using just HEAD results in an refname 'HEAD' is ambiguous error anywhere where a <commit> is passed as an argument.

回答1:

According to gitrevisions, if both HEAD and refs/heads/HEAD exist, the selected revision is HEAD (i.e., not the branch named HEAD).

This is in fact the correct answer for most situations, but git checkout prefers the branch-name to the revision, so git checkout HEAD resolves to the branch, rather than the current commit.

There are other commands that also choose the branch name, e.g., git branch -f HEAD newrev or git branch -D HEAD refers to the branch, but here there's no real room for ambiguity: git branch is obviously going to work on the branch.

Other handlers generally pass a branch name or a revision specifier to git rev-parse or git rev-list, and those behave as documented in gitrevisions.

Note that similar cases can occur with more realistic branch names. Just yesterday I created a branch for dealing with a certain ethernet items, and named the branch e1000 ... which looks like an abbreviated SHA-1. A branch named facade suffers the same fate.



回答2:

The good news is, with Git 2.16 (Q1 2018), that issue won't come up easily anymore, since "git branch" and "git checkout -b" are now forbidden from creating a branch whose name is "HEAD".

See commit 662a4c8 (14 Nov 2017) by Kaartic Sivaraam (sivaraam).
See commit a625b09 (14 Nov 2017), and commit bc1c9c0, commit 8280c4c (13 Oct 2017) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 1616928, 28 Nov 2017)

branch: correctly reject refs/heads/{-dash,HEAD}

strbuf_check_branch_ref() is the central place where many codepaths see if a proposed name is suitable for the name of a branch.
It was designed to allow us to get stricter than the check_refname_format() check used for refnames in general, and we already use it to reject a branch whose name begins with a '-'.
The function gets a strbuf and a string "name", and returns non-zero if the name is not appropriate as the name for a branch.
When the name is good, it places the full refname for the branch with the proposed name in the strbuf before it returns.

However, it turns out that one caller looks at what is in the strbuf even when the function returns an error.
Make the function populate the strbuf even when it returns an error.
That way, when "-dash" is given as name, "refs/heads/-dash" is placed in the strbuf when returning an error to copy_or_rename_branch(), which notices that the user is trying to recover with "git branch -m -- -dash dash" to rename "-dash" to "dash".

While at it, use the same mechanism to also reject "HEAD" as a branch name.



回答3:

You can use use $(git rev-parse --quiet HEAD) whenever you need the commit (or $(git symbolic-ref HEAD) if you want to know where HEAD "points to").

According to git help rev-parse $GIT_DIR/<refname> takes precedence over refs/HEAD, refs/tags/HEAD, refs/heads/HEAD, etc., etc. and --quiet will silence the "refname 'HEAD' is ambiguous" warning.

Everywhere that takes a ref you should be able to use HEAD to refer to the currently checked out "thing" and refs/heads/HEAD to refer to a branch called HEAD. If you find a place in Git which takes a ref (not a branch) and HEAD doesn't work then you should report it as a bug.



标签: git branch