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.
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.
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.
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.