Why should I care about lightweight vs. annotated tags?
回答1
The big plus of an annotated tag is that you know who created it. Just like with commits, sometimes it's nice to know who did it. If you're a developer and you see that v1.7.4 has been tagged (declared ready) and you're not so sure, who do you talk to? The person whose name is in the annotated tag! (If you live in a distrustful不信任的 world, this also keeps people from getting away with tagging things they shouldn't.) If you're a consumer, that name is a stamp of authority: that's Junio Hamano saying this version of git is hereby released.
The other metadata can be helpful too - sometimes it's nice to know when that version was released, not just when the final commit was made. And sometimes the message can even be useful. Maybe it helps explain the purpose of that particular tag. Maybe the tag for a release candidate contains a bit of a status/to-do list.
Signing tags is pretty much like signing anything else - it provides one more level of security for the paranoid. Most of us aren't ever going to use it, but if you really want to verify everything before you put that software on your computer, you might want it.
Edit:
As for what to write in a tag annotation, you're right - there's not always much useful to say. For a version number tag, it's implicitly understood that it marks that version, and if you're happy with your changelogs elsewhere, there's no need to put one there. In this case, it's really the tagger and date that are the most important. The only other thing I can think of is some sort of stamp of approval from a test suite. Have a look at git.git's tags: they all just say something like "Git 1.7.3 rc1"; all we really care about is Junio Hamano's name on them.
However, for less obviously named tags, the message could become much more important. I could envision tagging a specific special-purpose version for a single user/client, some important non-version milestone, or (as mentioned above) a release candidate with extra information. The message is then much more useful.
回答2
My personal, slightly different view on that topic:
- Annotated tags are those tags meant to be published for other developers, most probably new versions (which should also be signed). Not only to see who tagged and when it was tagged, but also why (usually a changelog).
- Lightweight are more appropriate for private use, that means tagging special commits to be able to find them again. May it be to review them, check them out to test something or whatever.
https://git-scm.com/book/en/v2/Git-Basics-Tagging
Creating Tags
Git supports two types of tags: lightweight and annotated.
A lightweight tag is very much like a branch that doesn’t change — it’s just a pointer to a specific commit.
Annotated tags, however, are stored as full objects in the Git database. They’re checksummed; contain the tagger name, email, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG).
It’s generally recommended that you create annotated tags so you can have all this information; but if you want a temporary tag or for some reason don’t want to keep the other information, lightweight tags are available too.
Annotated Tags
Creating an annotated tag in Git is simple. The easiest way is to specify -a
when you run the tag
command:
$ git tag -a v1.4 -m "my version 1.4"
$ git tag
v0.1
v1.3
v1.4
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.
You can see the tag data along with the commit that was tagged by using the git show
command:
$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date: Sat May 3 20:19:12 2014 -0700
my version 1.4
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Change version number
That shows the tagger information, the date the commit was tagged, and the annotation message before showing the commit information.
What is the difference between an annotated and unannotated tag?
回答1
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.
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.
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.
回答2
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 <your@mail.com> 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:
- the object it points to
- the type of object it points to. Yes, tag objects can point to any other type of object like blobs, not just commits.
- the name of the tag
- tagger identity and timestamp
- message. Note how the PGP signature is just appended to the message
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 committag
for annotated, since there is a tag object in that case
-
List only lightweight tags: How can I list all lightweight tags?