118

I type git tag and it lists my current tags:

1.2.3
1.2.4

How can I determine which of these is annotated, and which is lightweight?

Diogo Cardoso
  • 21,637
  • 26
  • 100
  • 138
G. Sylvie Davies
  • 5,049
  • 3
  • 21
  • 30

5 Answers5

107

git for-each-ref tells you what each ref is to by default, its id and its type. To restrict it to just tags, do git for-each-ref refs/tags.

[T]he output has three fields: The hash of an object, the type of the object, and the name in refs/tags that refers to the object. A so-called "lightweight" tag is a name in refs/tags that refers to a commit¹ object. An "annotated" tag is a name in refs/tags that refers to a tag object.

- Solomon Slow (in the comments)

Here is an example:

$ git for-each-ref refs/tags                                           
902fa933e4a9d018574cbb7b5783a130338b47b8 commit refs/tags/v1.0-light
1f486472ccac3250c19235d843d196a3a7fbd78b tag    refs/tags/v1.1-annot
fd3cf147ac6b0bb9da13ae2fb2b73122b919a036 commit refs/tags/v1.2-light

with some format:

$ git for-each-ref \
  --format="%(if:equals=tag)%(objecttype)%(then)a %(else)%(if:equals=blob)%(objecttype)%(then)b %(else)  %(end)%(end)%(align:20,right)%(refname:short)%09%(objectname:short)%(end)%09%(if:equals=tag)%(objecttype)%(then)@%(object) %(contents:subject)%(else)%(end)" \
  --sort=taggerdate \
  refs/tags

    v1.2-light  fd3cf14 
b       forsam  633de05 
a   v1.1-annot  1f48647 @1e25186bcf26d260754b6ebf6b236e92eeadc69b annotation comment
    v1.0-light  902fa93

To do this for just one ref, you can use git cat-file -t on the local ref, to continue the example:

$ git cat-file -t v1.0-light
commit
$ git cat-file -t v1.1-annot
tag

¹ tags can refer to any Git object, if you want a buddy to fetch just one file and your repo's got a git server, you can git tag forsam :that.file and Sam can fetch it and show it. Most of the convenience commands don't know what to do with tagged blobs or trees, but the core commands like update-index and such do

childno͡.de
  • 4,679
  • 4
  • 31
  • 57
jthill
  • 55,082
  • 5
  • 77
  • 137
  • 10
    When I tried this, [the output](http://imgur.com/b00mvjr) listed each tag as either a `commit` or a `tag`. I presume those indicate lightweight and annotated tags respectively? – Stevoisiak Apr 17 '17 at 18:49
  • 4
    @StevenVascellaro That's correct, a lightweight tag is just the local ref starting "refs/tags", it can be to anything. A tag in the object db has more than just a name and can get shipped around like any other object. Git makes local refs for every tag in the object db so the distinction is somewhat blurred, generally nobody has to care much once the workflow's set up for their project. – jthill Apr 17 '17 at 19:19
  • 4
    So `commit` is lightweight and `tag` is annotated? – Pontiacks May 30 '18 at 09:59
  • 9
    @Pontiacks, the output has three fields: The hash of an object, the type of the object, and the name in refs/tags that refers to the object. A so-called "lightweight" tag is a name in refs/tags that refers to a `commit` object. An "annotated" tag is a name in refs/tags that refers to a `tag` object. – Solomon Slow May 30 '18 at 17:26
54

The git show-ref -d --tags command sort of does it, since lightweight tags occur once in the output, and annotated tags occur twice. Also, only annotated tags include the "^{}" dereference operator in the output.

588e9261795ec6dda4bd0a881cf1a86848e3d975 refs/tags/1.2.3
7fe2caaed1b02bb6dae0305c5c0f2592e7080a7a refs/tags/1.2.4
588e9261795ec6dda4bd0a881cf1a86848e3d975 refs/tags/1.2.4^{}

And that output can than be massaged with the unix sort, sed, cut, and uniq commands to make the output more readable:

git show-ref -d --tags       | 
cut -b 42-                   | # to remove the commit-id
sort                         |
sed 's/\^{}//'               | # remove ^{} markings
uniq -c                      | # count identical lines
sed 's/2\ refs\/tags\// a /' | # 2 identicals = annotated
sed 's/1\ refs\/tags\//lw /'   

For my original repo (from my question) it outputs this:

  lw 1.2.3
   a 1.2.4

(e.g., 1.2.3 was "lightweight" and "1.2.4" was annotated).

G. Sylvie Davies
  • 5,049
  • 3
  • 21
  • 30
39

Get the tag name (say foo) and then do a git cat-file -t foo. If it's an an annotated tag, cat-file will tell you that it's a "tag". If it's a simple tag, cat-file will tell you that it's a "commit".

Update: As oxymoron said in his comment, git show works too but it gives you more information than just what kind of tag it is.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
  • 7
    For "a given tag" (as stated in the question), this seems *by far* the best answer. – phils Aug 21 '19 at 06:26
  • 3
    Excellent answer - key to how this works is the "-t" option on "git cat-file." As the man page explains: "-t Instead of the content, show the object type identified by ." – G. Sylvie Davies Aug 21 '19 at 23:28
  • Or use `git cat-file -p foo` to see the difference and the message + meta – kxr Feb 17 '21 at 19:58
15

Please try using git describe

https://git-scm.com/docs/git-describe

By default (without --all or --tags) git describe only shows annotated tags.

Oxymoron
  • 1,380
  • 2
  • 19
  • 47
  • 2
    This does not show all annotated tags. It does show only those, who are on the same branch. If you are following a trunk based development and branch from trunk in code freeze and tag the branch when it is going to be released, the tag does not sit on the same branch as trunk and git describe will not show it. – codingdave Jul 09 '21 at 12:31
  • @codingdave that's not that true but only when you provide `--first-parent` but anyway: this was not the question to get the latest tag but the question was if a specific one is annotated or not so @Oxymoron your answer doesn't match either, because it only can show you the latest annotated in best case but not lists you which of all tags is annotated or not – childno͡.de May 12 '23 at 10:20
  • @childno.de Haha, good evening! Let's resurrect this 7 year old answer. First a personal update, I'm a father now, married, own a home. I'm a much different person than the one who wrote this answer. But Perhaps my assumption was that the person asking the question would quickly discover this and be able to compare `git describe` against the output of `git tag` to get the information they were looking for. I can't say for certain but I appreciate you pointing this out. I admit I could have done a better job at that. My answer was posted 9 minutes after the question, so I was prob competing – Oxymoron May 14 '23 at 03:13
1

In case someone is interested in checking a single tag, you can just do git show <tag-name> and if the tag is lightweight, the output will look exactly like for a regular commit:

commit <hash> (<tags>, <branches>)
Author: John Doe <john@doe.com>
Date:   Wed Apr 12 22:29:20 2023 +0200

The message of the actual commit...

But if it is annotated, the output will start like below, followed by the commit info.

tag <tag-name>
Tagger: John Doe <john@doe.com>
Date:   Wed Apr 12 22:29:20 2023 +0200

The message of the annotated tag...
Isti115
  • 2,418
  • 3
  • 29
  • 35