544

I have a bunch of unannotated tags in the repository and I want to work out which commit they point to. Is there a command that that will just list the tags and their commit SHAs? Checking out the tag and looking at the HEAD seems a bit too laborious to me.

Update

I realized after I went through the responses that what I actually wanted was to simply look at the history leading up to the tag, for which git log <tagname> is sufficient.

The answer that is marked as answer is useful for getting a list of tags and their commits, which is what I asked. With a bit of shell hackery I'm sure it's possible to transform those into SHA+Commit message.

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128
  • 4
    I want to point that `git show-ref` shows sha of the tag, not sha of the repo revision. $ git show-ref test 08b9c774ab20e5bdb638339cf4ea2c124b0dae54 refs/tags/test $ git checkout test HEAD is now at c7f8831... $ git checkout 08b9c77 HEAD is now at c7f8831... – Konstantin Pelepelin Jan 14 '14 at 12:17
  • 1
    if your tags are annotated then you need `--dereference` – Trevor Boyd Smith Nov 20 '18 at 14:06

22 Answers22

495

One way to do this would be with git rev-list. The following will output the commit to which a tag points:

$ git rev-list -n 1 $TAG

NOTE This works for both Annotated and Unannotated tags

You could add it as an alias in ~/.gitconfig if you use it a lot:

[alias]
  tagcommit = rev-list -n 1

And then call it with:

$ git tagcommit $TAG

Possible pitfall: if you have a local checkout or a branch of the same tag name, this solution might get you "warning: refname 'myTag' is ambiguous". In that case, try increasing specificity, e.g.:

$ git rev-list -n 1 tags/$TAG
samthebest
  • 30,803
  • 25
  • 102
  • 142
mipadi
  • 398,885
  • 90
  • 523
  • 479
  • I've actually found that on windows (in bash shell and normal cmd line client) I don't need to do `| head -n 1` as rev-list just returns the SHA. – Igor Zevaka Dec 07 '09 at 22:28
  • 36
    Why not use `git rev-parse `? Or `git rev-list -1 `? – Jakub Narębski Dec 07 '09 at 23:47
  • 76
    @ Jakub: `git rev-parse $TAG` returns the SHA1 of the tag object, not the commit to which it points. `git rev-list -1` works, though. – mipadi Dec 08 '09 at 00:24
  • 14
    @mipadi: For **un-annotated** tags it soedn't matter; for annotated tags you can use `git rev-parse $TAG^{commit}` or `git rev-parse $TAG^{}` to dereference annotated/signed tag – Jakub Narębski Dec 08 '09 at 11:49
  • @AndySmith: It prints the commit hash on one line. – mipadi Apr 16 '13 at 17:42
  • That alias didn't work in Windows, so I made one that does: https://gist.github.com/jonathanconway/5667042. – Jonathan May 29 '13 at 01:16
  • 5
    You can use: `git rev-list $TAG --max-count=1` – b73 Dec 29 '14 at 22:26
  • @Jakub: What is the difference of the two (rev-parse $TAG, and rev-list -1 $TAG)? Can you give an example? In my experiment, they returns the same sha1 code. What differs a tag object from the commit pointed to by the tag? – Robin Hsu Nov 23 '16 at 03:51
  • 4
    @RobinHsu: if you have ***annotated*** tags, that is created with `git tag -a` or `git tag -s`, then `git rev-parse ` would give you SHA-1 of a *tag object* itself, while `git rev-list -1 ` would give SHA-1 of *commit* (revision) it points to, same as `git rev-parse ^{commit}`. HTH. – Jakub Narębski Nov 23 '16 at 20:42
  • If you have a local checkout of the tag, `git rev-list -n 1 x` might get you "**warning: refname 'x' is ambiguous.**". To avoid that, you can increase specificity like so: `git rev-list -n 1 tags/x` – Domi Oct 18 '20 at 08:51
  • If tag does not exist the command shows error `fatal: ambiguous argument 'mytag': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git [...] -- [...]'`. – vitalets Aug 29 '21 at 11:10
282

WARNING This only works for Unannotated tags Therefore it is safer to use the accepted answer which works in the general case https://stackoverflow.com/a/1862542/1586965

git show-ref --tags

For example, git show-ref --abbrev=7 --tags will show you something like the following:

f727215 refs/tags/v2.16.0
56072ac refs/tags/v2.17.0
b670805 refs/tags/v2.17.1
250ed01 refs/tags/v2.17.2
samthebest
  • 30,803
  • 25
  • 102
  • 142
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Thanks for that, this actually hides the semantics of looking at either `.git/packed-refs` or `.git/refs/tags/*` – Igor Zevaka Dec 07 '09 at 22:32
  • 3
    hmmm. it has strange behavior in my repository: git tag -a v0.1.1-alpha a9dcc1f24cacde535523bddc22f4c69467428550; git show-ref --tags ->b784145a9a71478337f5ceae30aaac4e1b955ee5 refs/tags/v0.1.1-alpha ; see Jakub Narebski 's answer – NickSoft Apr 03 '11 at 09:47
  • @CharlesB: The question asked for a command that listed multiple tags. Also, there is no point to using an explicit ref with `--tags`, an explicit ref will work even if the ref is a lightweight tag. – CB Bailey May 15 '12 at 21:59
  • 6
    this works, although I wonder wouldn't it make sense to have `git tag --verbose` show them too? – nonopolarity Aug 31 '12 at 04:23
  • 53
    This will show the ref of the tag itself, not the commit the tag points to. You need to add the `-d` flag to get the referenced commit (on a second line). – Old Pro Sep 13 '13 at 04:59
  • @OldPro: from the question: "I have a bunch of unannotated tags", so these are lightweight tags. `git show-ref --tags` is simplest and sufficient in this case. – CB Bailey Sep 13 '13 at 05:45
  • 5
    @CharlesBailey, fair enough, but the question and answers have morphed to include annotated tags and the fact that `git show-ref` behaves differently on the two different types of tags is not obvious or common knowledge. – Old Pro Sep 15 '13 at 01:19
  • The result is not the referenced commit, @OldPro is right. – yuchen May 24 '17 at 03:25
130

Just use git show <tag>

However, it also dumps commit diffs. To omit those diffs, use git log -1 <tag>. (Thanks to @DolphinDream and @demisx !)

Hlung
  • 13,850
  • 6
  • 71
  • 90
  • 8
    On SO, when a question has many different possible answers, the answers that are posted first get upvoted first - putting them at the top of the list, and thus getting them more upvotes later. This is a biasing feedback loop based on speed of response over quality of response. With sufficient imagination this problem could be fixed. – samthebest Sep 07 '15 at 11:35
  • 7
    "Best solution" for what? If the interest is in finding out the SHA of a commit the tag points to the "git show " is NOT the best solution. This command will show the entire diff the commit introduces. For listing only the SHA of the commit the tag points to the "git rev-list -n 1" is the correct solution. – DolphinDream Oct 14 '15 at 12:58
  • This is not the answer to the OP's question. `git show ` shows the diff, not the commit the tag points to. – demisx Apr 22 '16 at 03:17
  • @demisx What are you talking about?? It definitely shows the commit hash, along with tagger, date, and other information. Try it. – Hlung Apr 23 '16 at 01:14
  • 5
    @Hlung Like @DolphinDream pointed out, `git show` dumps a whole lot more stuff on the screen that doesn't need to be there. It obscures the actual commit hash one is looking for. A better command is `git log -1 [tag-name]` or `git log -1 --pretty=oneline [tag-name]` if you want oneliners. – demisx Apr 23 '16 at 17:56
  • @demisx You are right. I happened to do `git show` only on commit that doesn't show diffs in the command line up until now (e.g. merge commits). That's where I usually put tags on. I agree with `git log -1 [tag-name]` is cleaner. I'll add a note to my answer. Thanks! – Hlung Apr 27 '16 at 04:16
  • git show shows too much information when all you need is the commit SHAs – Erwin Julius Apr 25 '17 at 13:36
  • @DolphinDream Best solution for people who want to do exactly this, but won't ask another question, coz it'd be flagged as duplicate. – Qback Jan 29 '18 at 09:24
  • This solution, with its verbose output, actually helped me to solve my particular problem more than the solution with the concise output, correct though it may be. – Andy Weinstein Oct 18 '22 at 08:26
57

From Igor Zevaka:

Summary

Since there are about 4 almost equally acceptable yet different answers I will summarise all the different ways to skin a tag.

  1. git rev-list -1 $TAG (answer). git rev-list outputs the commits that lead up to the $TAG similar to git log but only showing the SHA1 of the commit. The -1 limits the output to the commit it points at.

  2. git show-ref --tags (answer) will show all tags (local and fetched from remote) and their SHA1s.

  3. git show-ref $TAG (answer) will show the tag and its path along with the SHA1.

  4. git rev-parse $TAG (answer) will show the SHA1 of an unannotated tag.

  5. git rev-parse --verify $TAG^{commit} (answer) will show a SHA1 of both annotated and unannotated tags. On Windows use git rev-parse --verify %TAG%^^^^{commit} (four hats).

  6. cat .git/refs/tags/* or cat .git/packed-refs (answer) depending on whether or not the tag is local or fetched from remote.

Community
  • 1
  • 1
47

For annotated tags, git show-ref TAG shows the tag's hash, not the hash of the commit it points to.

git show-ref --dereference TAG shows, additionally, the commit being pointed at with an added ^{}.

CervEd
  • 3,306
  • 28
  • 25
orip
  • 73,323
  • 21
  • 116
  • 148
38

Use

git rev-parse --verify <tag>^{commit}

(which would return SHA-1 of a commit even for annotated tag).


git show-ref <tag> would also work if <tag> is not annotated. And there is always git for-each-ref (see documentation for details).

Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
  • 13
    I prefer `git rev-parse ~0` which also seems to work, and requires no special escaping on Windows (on which four hats (^) are necessary instead of one). The suffix `~` gives the th parent commit, therefore `~0` yields the commit itself. Btw, `^0` is also a valid shorthand for the `^{commit}` revision suffix. – Attila Mar 20 '12 at 16:15
15

How about this:

git log -1 $TAGNAME

OR

git log -1 origin/$TAGNAME
ScottJShea
  • 7,041
  • 11
  • 44
  • 67
Tuong Le
  • 18,533
  • 11
  • 50
  • 44
13

In order to get the sha/hash of the commit that a tag refers to (not the sha of the tag):

git rev-list -1 <tag>

Daniel Little
  • 16,975
  • 12
  • 69
  • 93
10

Short post-Git-2 answer

I know this question has been out here for quite a while. And the answer from CB Bailey is 100% correct: git show-ref --tags --abbrev

I like this one better since it uses git tag:

git tag --list --format '%(refname:short) %(objectname:short)'

Simple. Short.

PS alias it as git taglist with this command:

git config --global alias.taglist "tag --list --format '%(refname:short) %(objectname:short)'"
Jesper Rønn-Jensen
  • 106,591
  • 44
  • 118
  • 155
10

The --format option can be used to show both tag hash and the commit hash, and to distinguish between lightweight and annotated tags.

git tag --format="%(color:bold cyan)== %(refname:short) ==%(if)%(object)%(then)%0aTag Hash: %(objectname)%0aTag Date: %(taggerdate:iso-local)%0a  Commit: %(object) %0a%0a%(contents)%(else)%0a(lightweight tag)%0a  Commit: %(objectname)%(end)%0a"

Gives output similar to:

== b2lightweight ==
(lightweight tag)
  Commit: 0450fae4352dbbbf088419757eda32711316a02e

== c3_annotated ==
Tag Hash: 19961d8678a09a319a9d6c398c79f27cc23d610c
Tag Date: 2021-08-06 15:18:48 -0600
  Commit: 85be6e80c109ce44d78f0ca0da8e1ec53817b24c

This is my tag message.

It has multiple lines.

Another line.

To define as a git alias, you can edit the global git config with git config --global -e and add the following:

[alias]
    tag-verbose = tag --format='%(color:bold cyan)== %(refname:short) ==%(if)%(object)%(then)%0aTag Hash: %(objectname)%0aTag Date: %(taggerdate:iso-local)%0a  Commit: %(object) %0a%0a%(contents)%(else)%0a(lightweight tag)%0a  Commit: %(objectname)%(end)%0a'

The alias still allows filtering, e.g.

C:\playground>git tag-verbose -l *b2*
== b2lightweight ==
(lightweight tag)
  Commit: 0450fae4352dbbbf088419757eda32711316a02e

For additional information on the --format options see the "Field Names" section under git help for-each-ref. (git help tag states "The format is the same as that of git-for-each-ref")

Nathan
  • 10,593
  • 10
  • 63
  • 87
9

I'd also like to know the "right" way, but in the meantime, you can do this:

git show mytag | head -1    
gahooa
  • 131,293
  • 12
  • 98
  • 101
7

Even though this is pretty old, I thought I would point out a cool feature I just found for listing tags with commits:

git log --decorate=full

It will show the branches which end/start at a commit, and the tags for commits.

Terrence Reilly
  • 116
  • 3
  • 4
5

You could as well get more easy-to-interpret picture of where tags point to using

git log --graph |git name-rev --stdin --tags |less

and then scroll to the tag you're looking for via /.

More compact view (--pretty=oneline) plus all heads (-a) could also help:

git log -a --pretty=oneline --graph |git name-rev --stdin --tags |less

Looks a bit terrifying, but could also be aliased in ~/.gitconfig if necessary.

~/.gitconfig

[alias]
ls-tags = !git log -a --pretty=oneline --graph |git name-rev --stdin --tags |less
Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
3

This doesn't show the filenames, but at least you get a feel of the repository.

cat .git/refs/tags/*

Each file in that directory contains a commit SHA pointing to a commit.

Peter Stuifzand
  • 5,084
  • 1
  • 23
  • 28
3

From git mailing list, here is the way to get the list of commit hashes for tags with automatic dereferencing for annotated tags:

git for-each-ref --format='%(if)%(*objectname)%(then)%(*objectname)%(else)%(objectname)%(end) %(refname)' refs/tags
anatoly techtonik
  • 19,847
  • 9
  • 124
  • 140
2

i'd also like to know the right way, but you can always peek either into:

$ cat .git/packed-refs 

or:

$ cat .git/refs/tags/*
miku
  • 181,842
  • 47
  • 306
  • 310
  • Right, so behaviour for packed-refs and refs/tags is somewhat different, packed-refs is a text file containing tags and SHAs, whereas refs/tags/ is a directory with text files named after a tag containing the SHA. I actually think that the *proper* way of doing this is with `git rev-list`. – Igor Zevaka Dec 07 '09 at 22:27
2

This will get you the current SHA1 hash

Abbreviated Commit Hash

git show <tag> --format="%h" --> 42e646e

Commit Hash

git show <tag> --format="%H" --> 42e646ea3483e156c58cf68925545fffaf4fb280
Louis
  • 439
  • 4
  • 4
2

If you would like to see the details of the tag SOMETAG (tagger, date, etc), the hash of the commit it points to and a bit of info about the commit but without the full diff, try

git show --name-status SOMETAG

Example output:

tag SOMETAG
Tagger: ....
Date:   Thu Jan 26 17:40:53 2017 +0100

 .... tag message .......

commit 9f00ce27c924c7e972e96be7392918b826a3fad9
Author: .............
Date:   Thu Jan 26 17:38:35 2017 +0100

 .... commit message .......

..... list of changed files with their change-status (like git log --name-status) .....
1

git rev-list --no-walk [tag_name]

Peter
  • 29
  • 2
  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 30 '22 at 09:41
0

So I have a load of release folders, where those folders may be checked out from one of a few different repos, and may be dev, qa or master branches or may be production releases, checked out from a tag, and the tag may be annotated or not. I have a script that will look at the target folder and get be back an answer in the form -. The problem is different versions of git return different status' for a tag checkout.

So I found git show-ref --tags worked initially, except for the annotated tags. However adding -d added a separate entry to the list of tags, one for the tag, the other for the annotation (the annotation commit was identified as ^{} which I stripped out with sed).

So this is the core of my script, for anyone that wants it:-

REPO=`git --git-dir=${TARGET} remote show origin -n | \
         grep "Fetch URL:" | \
         sed -E "s/^.*\/(.*)$/\1/" | \
         sed "s/.git$//"`

TAG=`git --git-dir=${TARGET} show-ref -d --tags | \
         grep \`git --git-dir=${TARGET} show --quiet --format=format:%H HEAD\` | \
         cut -d\  -f2 | \
         cut -d/ -f3 | \
         sed "s/\^{}$//"`

if [ "${TAG}" == "" ] ; then 
  BRANCH=`git --git-dir=${TARGET} show-ref --heads | \
         grep \`git --git-dir=${TARGET} show --quiet --format=format:%H HEAD\` | \
         cut -d\  -f2 | \
         cut -d/ -f3`
  TAG=${BRANCH}
fi
sibaz
  • 1,242
  • 14
  • 26
0

Can use below, It will give the commit hash
git show -s --format=%H <tag>^{commit}

If abbreviated commit hash required, git show -s --format=%h <tag>^{commit}

0

Hacky solution

Parse the .git/packed-refs and format it as {tag}\t{sha}

sed -n '/ refs\/tags/ { s@\([^ ]*\) refs/tags/\(.*\)@\2\t\1@; p}' .git/packed-refs
CervEd
  • 3,306
  • 28
  • 25