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.
The Git HEAD is a Git reference object that represents the current branch. Checking out a branch will change the HEAD to point to the checked out branch. The HEAD will point to the tip of a branch by default, but can be set to point to any commit. When pointed at a specific commit the HEAD is considered to be in a ‘detached’ state.
Figure 150. Git directory objects with branch head references included When you run commands like git branch <branch>, Git basically runs that update-ref command to add the SHA-1 of the last commit of the branch you’re on into whatever new reference you want to create.
When working with Git, only one branch can be checked out at a time - and this is what's called the "HEAD" branch. Often, this is also referred to as the "active" or "current" branch. Git makes note of this current branch in a file located inside the Git repository, in.git/HEAD.
That’s basically what a branch in Git is: a simple pointer or reference to the head of a line of work. To create a branch back at the second commit, you can do this: Your branch will contain only work from that commit down: Now, your Git database conceptually looks something like this: Figure 150.
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 rejectrefs/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 thecheck_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 astrbuf
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 thestrbuf
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 thestrbuf
even when it returns an error.
That way, when "-dash
" is given as name, "refs/heads/-dash
" is placed in thestrbuf
when returning an error tocopy_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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With