I switched from Subversion to Git as my day-to-day VCS last year and am still trying to grasp the finer points of \"Git-think\".
The one which has been bothering me
For me important difference is lightweight tag doesn't have timestamp. Let's say you added several lightweight tags:
git tag v1
git tag v2
git tag v3
and then, maybe later, you want to get last added lightweight tag. There is no way to do it. Neither "git describe" nor "git tag" will not give you chronologically last lightweight tag. "git tag -l" can return all of them or sort them in lex order, but not by date/time. "git describe --tags" will return "v1" which is definitely not last added tag.
From the other hand, if you add annotated tags:
git tag v1 -m v1
git tag v2 -m v1
git tag v3 -m v1
you always can get timestamp of every tag and "git describe" will sure return "v3" which is really last added tag.
My personal, slightly different view on that topic:
I've found the one good use for lightweight tags - creating a release at GitHub in retrospective.
We did release our software and we had the necessary commits, we just didn't bother to maintain the 'Release' section on the GitHub. And when we gave that a little attention, we've realised that we would want to add some previous releases too, with correct old release dates for them.
If we would just create an annotated tag on an old commit, GitHub would take the date for the release from the tag object. In contrast, when we've created a lightweight tag for this old commit, the release started showing the correct (old) date. Source @ GitHub help, 'About releases'
It seems it's also possible to specify your desired date for an annotated commit, but it doesn't look that simple to me: https://www.kernel.org/pub/software/scm/git/docs/git-tag.html#_on_backdating_tags
Signing a tag is an easy way to assert the authenticity of a release.
This is particularly useful in a DVCS because anyone can clone the repository and modify history (e.g. via git-filter-branch). If a tag is signed, the signature will not survive a git-filter-branch operation, so if you have a policy that every release is tagged and signed by a committer, it's possible to detect a bogus release tag in the repository.
If it weren't for signing, I wouldn't see much point in annotated tags either.
Annotated tags store extra metadata such as author name, release notes, tag-message, and date as full objects in the Git database. All this data is important for a public release of your project.
git tag -a v1.0.0
Lightweight tags are the simplest way to add a tag to your git repository because they store only the hash of the commit they refer to. They can act like "bookmarks" to a commit, as such, they are great for private use.
git tag v1.0.0
You can sort, list, delete, show and edit old tags. All these functions will help you to identify specific release versions of your code. I found this article that could help you to get a better idea what tags can do.
Push annotated tags, keep lightweight local
Certain Git 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 describe
without command line options only sees annotated tagsman git-tag
says:
Annotated tags are meant for release while lightweight tags are meant for private or temporary object labels.
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:
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, tag
for annotated.
List only lightweight tags: How can I list all lightweight tags?