commit1-----tagA,tagB
git checkout tagA
Question: How to get the tag name of current checkout? I have try git describe
, but it's always return name "tagB", expect return "tagA".
Seems git describe
only be able to return the most recent tag name, see from git manual
The command finds the most recent tag that is reachable from a commit. If the tag points to the commit, then only the tag is shown. Otherwise, it suffixes the tag name with the number of additional commits on top of the tagged object and the abbreviated object name of the most recent commit.
Is there any other method?
Purpose related this question:
I want to make file auto build the version number from the tag name, git describe
work well when 1 commit with 1 tag, but it's not useful in above case.
Both tagA
and tagB
point to that one specific commit, so either name is equally good (or equally bad) as far as git is concerned, if you want to check out or look at that particular commit.
The documentation's phrasing "most recent tag" is perhaps misleading here (although it's likely why you get tagB
as output).
If you want to know what tag-name you gave to git checkout
, you can either save that yourself, or consult the reflog for HEAD
:
8004647 HEAD@{0}: checkout: moving from master to v2.3.1
The reflog method has the advantage that it's already implemented; but reflogs are only retained for a while (configurable, default 90 days for reachable references) before being expired away to keep reflogs from growing forever.
"Most recent" means that if tags have associated date-and-time stamps—annotated tags do, lightweight tags don't—then those with a later time are considered "better", as described below.
Note that at any time, any git command can easily look up all external references and translate them to SHA-1s. To see how this works, simply run git for-each-ref
(you may want to pipe this to a pager like less
). The output looks something like this:
c2e8e4b9da4d007b15faa2e3d407b2fd279f0572 commit refs/heads/maint
9ab698f4000a736864c41f57fbae1e021ac27799 commit refs/heads/master
[snip]
74d2a8cf12bf102a8cedaf66736503bb3fe88dfb tag refs/tags/v2.2.0
[more snippage]
These are branches and tags—in this git repository (for git itself) all the tags are annotated—and their corresponding SHA-1s. If there were an active stash it would show up as well (under refs/stash
).
In any case, suppose that git describe
has, at this point, one of these commit IDs (an SHA-1), and describe
has also found two or more names that resolve to that ID. These may just be annotated tag names, which is what you get without options, or they might be another name (like a branch name) allowed by --all
, for instance; but the important thing is to suppose that there are two or more names, all all pointing to the same commit.
The describe
command could try remembering all of these names, but it doesn't. Instead, it runs the names through a sort of two-at-a-time tournament to see which one "wins a contest":
git describe
should use.Once all the names for this commit have been contested against each other to choose a "winning name", the "winning name" is saved along with the commit SHA-1.
Now, how do we get that commit ID in the first place? The answer is that git describe
starts with your argument(s):
$ git describe # no args, means ...
$ git describe HEAD # use HEAD to get the SHA-1
Your arguments (or HEAD
) are turned into the appropriate raw SHA-1 using git rev-parse
(well, its C code equivalent):
$ git rev-parse HEAD
9ab698f4000a736864c41f57fbae1e021ac27799
Then, git describe
invokes git for-each-ref
(or its C code equivalent) to turn all the names you allow it to use—by default, all annotated tags—into SHA-1 IDs. If any of them match this SHA-1, they're saved. If there are multiple matches, they're run through the contest to pick a single winner.
For your particular case, this part succeeds: both tagA
and tagB
are exact matches, so the whole thing stops after picking a winning tag between these two. In your case that was the tag you didn't want.
In general, though, git describe
often has to keep going. Consider, for instance, the following commits from the git
project itself:
088c9a8 strbuf.h: format asciidoc code blocks as 4-space indent
aa07cac strbuf.h: drop asciidoc list formatting from API docs
6afbbdd strbuf.h: unify documentation comments beginnings
bdfdaa4 strbuf.h: integrate api-strbuf.txt documentation
eae6953 tests: correct misuses of POSIXPERM
1767c51 t/lib-httpd: switch SANITY check for NOT_ROOT
b4a56a3 "log --pretty" documentation: do not forget "tformat:"
Now suppose we make one tag X
pointing to commit b4a56a3
, one tag Y
pointing to commit eae6953
, and one tag Z
pointing to commit aa07cac
. If we then ask git to "describe" commit 088c9a8
, it could be described as any of the following:
X
, orY
, orZ
The output of git describe
will use tag Z
, because it requires fewer steps to go from "tag Z" (commit aa07cac
) to the commit in question (088c9a8
). How this actually happens is remarkably (perhaps unnecessarily, although that's a value judgement :-) ) complicated.
What git describe
does here is to walk through (part of) the commit graph (applying --first-parent
if specified) to find a "nearby" commit that does have a name. The search order is somewhat difficult to describe: it's partly date-based (a la git log
's date-sorted commit listings), but it stops early if it encounters an annotated tag. Otherwise it accumulates a list of "candidate names" (using the contest method described above), stopping when it has accumulated enough (default 10) candidate names, then sorts the list. The sort is based on "graph distance", so assuming X
, Y
, and Z
are all lightweight tags—if any were an annotated tag it would have been picked by now and the search stopped—Z
wins here.
Last, having found a name that points to a suitable commit that is not actually the given-as-argument commit, git describe
prints the name, the number of steps distant ("depth"), and the g
and part of the actual SHA-1:
v2.3.3-220-g9ab698f
(though the depth and g
can be suppressed, and the whole thing can fail if no names at all can be found or if you've asked for exact matches only, and so on).