I am looking for a Git command that will print the symbolic name for HEAD
. I
was using this command
$ git name-rev --name-only HEAD
master
$ git checkout HEAD~2
$ git name-rev --name-only HEAD
master~2
However I noticed that it does not work on a new repository
$ git init
$ git name-rev --name-only HEAD
Could not get sha1 for HEAD. Skipping.
I found this workaround
$ git init
$ git symbolic-ref --short HEAD
master
But this does not work on older commits
$ git checkout HEAD~2
$ git symbolic-ref --short HEAD
fatal: ref HEAD is not a symbolic ref
So now I have this, which covers both new repos and older commits
$ git symbolic-ref -q --short HEAD || git name-rev --name-only HEAD
master
I was just wondering, is this the best way to do this? It feels like this should be possible with one command.
A symbolic ref is a regular file that stores a string that begins with ref: refs/ . For example, your . git/HEAD is a regular file whose contents is ref: refs/heads/master .
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 rev-parse is an ancillary plumbing command primarily used for manipulation. One common usage of git rev-parse is to print the SHA1 hashes given a revision specifier. In addition, it has various options to format this output such as --short for printing a shorter unique SHA1.
The git checkout command lets you navigate between the branches created by git branch . Checking out a branch updates the files in the working directory to match the version stored in that branch, and it tells Git to record all new commits on that branch.
You write:
I am looking for a Git command that will print the symbolic name for
HEAD
.
The following may suffice to demonstrate that what you're asking for does not make sense in all situations, simply because HEAD
may not be unambiguously associated with one reference. Read on.
git name-rev
doesIn the git-name-rev
man-page, you find the following description:
Given a commit, find out where it is relative to the local refs. [...]
More specifically, git name-rev
checks whether <commit-ish>
is reachable from any of the local references (by processing them in lexicographical order, e.g. develop
before master
).
Let's examine what
$ git name-rev --name-only <commit-ish>
does in different cases (the --name-only
flag is incidental here, as its effects are purely cosmetic).
HEAD
is not detachedIf HEAD
is not detached, i.o.w. if HEAD
is pointing to a valid ref (let's call it myref
), then there is no ambiguity: running
$ git name-rev --name-only HEAD
simply outputs
myref
because the myref
reference is unambiguously associated with HEAD
. So far, so good.
HEAD
is detachedIn that case, things are not as simple. In fact, there may be one or more references from which <commit-ish>
is reachable, or there may be none at all.
At the first such local reference found, git name-rev
prints a "relative" symbolic reference, i.e. a revision of the form
<ref>~<n>
where <ref>
stands for the local reference in question, and <n>
stands for the generation. For example, if HEAD
points directly to a commit that is a grandparent of master
(master
being the only local reference), then
$ git name-rev HEAD
returns
master~2
Note, however, that in case <commit-ish>
is reachable from multiple references, the one returned by git name-rev
is somewhat arbitrary, as it's only dictated by the lexicographical order (in which the command checks local references).
It's easy to imagine situations in which <commit-ish>
is reachable from none of the local references. Actually, here is one you can reproduce at home (boilerplate stdout is omitted):
# set things up
$ mkdir test
$ cd test
$ git init
# create a commit
$ touch README.md
$ git add README.md
$ git commit -m "add README"
# detach the HEAD (make it point directly to the tip of master, instead of to master itself)
$ git checkout $(git rev-parse master)
# create a second commit (while in detached-HEAD state)
$ printf "foo\n" > README.md
$ git commit -am "write 'foo' in README"
# attempt to find a symbolic name for HEAD
$ git name-rev --name-only HEAD
undefined
Because the commit DAG looks as follows,
A [master]
\
B [HEAD]
commit B
is not reachable from the only reference (master
); therefore, git name-rev
gives up and simply returns undefined
.
Because HEAD
is not guaranteed to be unambiguously associated to one reference, what you're asking for doesn't make sense :p
Just want to add my solution for your case:
git symbolic-ref -q --short HEAD || git describe --all --always HEAD
This covers branches, tags, detached heads (commits) and new repositories. But tags will be returned as tags/0.1.0
for example.
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