548

If I want to tag the current commit. I know both of the following command lines work:

git tag <tagname>

and

git tag -a <tagname> -m '<message>'

What is the difference between these commands?

5
  • 1
    possible duplicate of In what circumstances should I add the -a flag to the git tag command?
    – Thilo
    Commented Jul 16, 2012 at 23:37
  • 2
    @Thilo This is not an exact duplicate. The referenced question is about when to annotate, not about the related flags. Commented Jul 16, 2012 at 23:42
  • 2
    This is very well explained in Git's documentation: git-scm.com/book/en/Git-Basics-Tagging Commented Jul 17, 2012 at 8:25
  • 1
    TLDR unannotated: commit; annotated: commit, author, date, (optional) comment Commented Aug 19, 2019 at 5:10
  • @SamyDindane if Gits docs would be more clear in search results and would show up higher than stack results, and if gits docs were as useful as stack was, then more of us would probably use git docs, but instead i always choose the stack results. Thanks for linking the git docs here or i wouldnt have found it as useful :-). this is the part i needed to know The -m specifies a tagging message, which is stored with the tag. If you don’t specify a message for an annotated tag, Git launches your editor so you can type it in.. So ill use -a without -m here out cause i prefer vim.
    – blamb
    Commented Jan 18 at 17:27

4 Answers 4

430

TL;DR

The difference between the commands is that one provides you with a tag message while the other doesn't. An annotated tag has a message that can be displayed with git-show(1), while a tag without annotations is just a named pointer to a commit.

More About Lightweight Tags

According to the documentation: "To create a lightweight tag, don’t supply any of the -a, -s, or -m options, just provide a tag name". There are also some different options to write a message on annotated tags:

  • When you use git tag <tagname>, Git will create a tag at the current revision but will not prompt you for an annotation. It will be tagged without a message (this is a lightweight tag).
  • When you use git tag -a <tagname>, Git will prompt you for an annotation unless you have also used the -m flag to provide a message.
  • When you use git tag -a -m <msg> <tagname>, Git will tag the commit and annotate it with the provided message.
  • When you use git tag -m <msg> <tagname>, Git will behave as if you passed the -a flag for annotation and use the provided message.

Basically, it just amounts to whether you want the tag to have an annotation and some other information associated with it or not.

9
  • 8
    Is there a difference between a tag "annotation" and a commit message? Commented Jul 16, 2012 at 23:57
  • 4
    @SteveBennett Yes. A tag annotation is not a commit message. You can't see it with git-log(1); you need to use git-show(1). Commented Jul 17, 2012 at 0:03
  • 192
    The difference between "annotated" and "lightweight" tags goes beyond message. You can have annotated tag without a message (git tag -a <tag> -m ''), but an annotated tag always has tagger (author) and date. Commented Oct 24, 2013 at 0:36
  • 76
    Another important thing to note is that when you push your tags to a remote repository using git push --follow-tags, only the annotated tags will be pushed. Commented Dec 11, 2015 at 17:13
  • 11
    Complementing @Xatoo comment, git push origin --tags push both types of tags, annotated and lightweight tags. Commented May 11, 2020 at 5:04
333

Push annotated tags, keep lightweight local

man git-tag says:

Annotated tags are meant for release while lightweight tags are meant for private or temporary object labels.

And certain behaviors do differentiate between them in ways that this recommendation is useful e.g.:

  • annotated tags can contain a message, creator, and date different than the commit they point to. So you could use them to describe a release without making a release commit.

    Lightweight tags don't have that extra information, and don't need it, since you are only going to use it yourself to develop.

  • git push --follow-tags will only push annotated tags
  • git describe without command line options only sees annotated tags

Internals differences

  • both lightweight and annotated tags are a file under .git/refs/tags that contains a SHA-1

  • for lightweight tags, the SHA-1 points directly to a commit:

    git tag light
    cat .git/refs/tags/light
    

    prints the same as the HEAD's SHA-1.

    So no wonder they cannot contain any other metadata.

  • annotated tags point to a tag object in the object database.

    git tag -as -m msg annot
    cat .git/refs/tags/annot
    

    contains the SHA of the annotated tag object:

    c1d7720e99f9dd1d1c8aee625fd6ce09b3a81fef
    

    and then we can get its content with:

    git cat-file -p c1d7720e99f9dd1d1c8aee625fd6ce09b3a81fef
    

    sample output:

    object 4284c41353e51a07e4ed4192ad2e9eaada9c059f
    type commit
    tag annot
    tagger Ciro Santilli <[email protected]> 1411478848 +0200
    
    msg
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.11 (GNU/Linux)
    
    <YOUR PGP SIGNATURE>
    -----END PGP SIGNAT
    

    And this is how it contains extra metadata. As we can see from the output, the metadata fields are:

    A more detailed analysis of the format is present at: What is the format of a git tag object and how to calculate its SHA?

Bonuses

  • Determine if a tag is annotated:

    git cat-file -t tag
    

    Outputs

    • commit for lightweight, since there is no tag object, it points directly to the commit
    • tag for annotated, since there is a tag object in that case
  • List only lightweight tags: How can I list all lightweight tags?

0
67

The big difference is perfectly explained here.

Basically, lightweight tags are just pointers to specific commits. No further information is saved; on the other hand, annotated tags are regular objects, which have an author and a date and can be referred because they have their own SHA key.

If knowing who tagged what and when is relevant for you, then use annotated tags. If you just want to tag a specific point in your development, no matter who and when did that, then lightweight tags are good enough.

Normally you'd go for annotated tags, but it is really up to the Git master of the project.

0

Another difference is when git tag -a foo fails, because there is already a tag foo/bar, as explained here.

With Git 2.42 (Q3 2023), "git tag"(man) learned to leave the "$GIT_DIR/TAG_EDITMSG" file when the command failed, so that the user can salvage what they typed.
That git tag message file would not exist for a lightweight tag.

See commit 08c12ec, commit 669c11d, commit 719515f (16 May 2023) by Kristoffer Haugsbakk (LemmingAvalanche).
(Merged by Junio C Hamano -- gitster -- in commit 6d2a88c, 13 Jun 2023)

tag: keep the message file in case ref transaction fails

Signed-off-by: Kristoffer Haugsbakk

The ref transaction can fail after the user has written their tag message.
In particular, if there exists a tag foo/bar and git tag -a foo(man) is said then the command will only fail once it tries to write refs/tags/foo, which is after the file has been unlinked.

Hold on to the message file for a little longer so that it is not unlinked before the fatal error occurs.

And:

doc: tag: document TAG_EDITMSG

Suggested-by: Junio C Hamano
Signed-off-by: Kristoffer Haugsbakk

Document TAG_EDITMSG which we have told the user about on unsuccessful command invocations since commit 3927bbe ("tag: delete TAG_EDITMSG only on successful tag", 2008-12-06, Git v1.6.1-rc2 -- merge).

Introduce this documentation since we are going to add tests for the lifetime of this file in the case of command failure and success.

Use the documentation for COMMIT_EDITMSG from git-commit.txt as a template since these two files share the same purpose.1

† 1: from commit 3927bbe:

“ This matches the behavior of COMMIT_EDITMSG, which stays around
  in case of error.

git tag now includes in its man page:

FILES

$GIT_DIR/TAG_EDITMSG

This file contains the message of an in-progress annotated tag. If git tag exits due to an error before creating an annotated tag then the tag message that has been provided by the user in an editor session will be available in this file, but may be overwritten by the next invocation of git tag.


And since annotated tags can contain a message, with Git 2.46 (Q3 2024) batch 4, "git tag"(man) learned the --trailer option to futz with the trailers in the same way as git commit(man) does.

That is another feature that a lightweight tag does not have.

See commit 066cef7, commit 4a86187, commit 56740f9 (05 May 2024) by John Passaro (jpassaro).
(Merged by Junio C Hamano -- gitster -- in commit f9d4eaf, 15 May 2024)

builtin/tag: add --trailer option

Helped-by: Patrick Steinhardt
Signed-off-by: John Passaro
Acked-by: Patrick Steinhardt

git-tag(man) supports interpreting trailers from an annotated tag message, using --list --format="%(trailers)".
However, the available methods to add a trailer to a tag message (namely -F or --editor) are not as ergonomic.

In a previous patch, we moved git-commit's implementation of its --trailer option to the trailer.h API.
Let's use that new function to teach git-tag the same --trailer option, emulating as much of git-commit's behavior as much as possible.

git tag now includes in its man page:

--trailer <token>[(=|:)<value>]

Specify a (, ) pair that should be applied as a trailer. (e.g. git tag --trailer "Custom-Key: value" will add a "Custom-Key" trailer to the tag message.) The trailer.* configuration variables (git interpret-trailers) can be used to define if a duplicated trailer is omitted, where in the run of trailers each trailer would appear, and other details. The trailers can be extracted in git tag --list, using --format="%(trailers)" placeholder.

Not the answer you're looking for? Browse other questions tagged or ask your own question.