Git Tags: Lightweight and Annotated Tags
Learn the structural difference between lightweight and annotated tags, create each form deliberately, understand what a tag reference points at, and choose the form that matches the intended lifecycle.
Intermediate
Learner goal
By the end of this lesson, you should be able to create both lightweight and annotated tags, explain what each tag reference points at, recognize that an annotation creates a separate tag object, and choose a tag form based on whether you need a simple temporary label or a release-oriented tag with tag metadata.
A tag is a reference, not another history
Git defines a tag as a reference under refs/tags/. A tag marks a particular object, usually a commit, without creating a second copy of that commit history. The tag name is the human-facing label; the target object remains the Git object that was already stored.
# Tag the current commit
git tag release-1.0
# Show the tag reference explicitly
git rev-parse refs/tags/release-1.0Quick check
Where does Git store the reference namespace for ordinary tags?
tag name: v1.0ref: refs/tags/v1.0
Lightweight tags: a direct label
When you create a tag without -a, -s, -u, -m, or -F, Git creates a lightweight tag. The reference points directly at the supplied object, usually a commit. There is no separate tag object carrying annotation metadata.
git tag v1.0-temp
# The tag resolves directly to the commit
git rev-parse v1.0-tempQuick check
What is structurally special about a lightweight tag?
git tag v1-light HEADrefs/tags/v1-light → target object
Annotated tags: a tag object with metadata
An annotated tag is created with -a, or by using an option such as -m or -F that implies -a when signing options are absent. Git creates a separate tag object. That tag object records the object being tagged, its object type, the tag name, the tagger and tag date, and the tag message; it can also carry a cryptographic signature, which is covered by the later tag-verification lesson.
git tag -a v1.0.0 -m "Release 1.0.0" HEAD
# -m supplies the annotation message and implies -a here
git tag -m "Release 1.0.0" v1.0.0-message
# An annotated tag resolves to a tag object; the object can then point to the commit
git rev-parse v1.0.0
git rev-parse v1.0.0^{}Quick check
Why does an annotated tag have an extra object compared with a lightweight tag?
git tag -a v1 -m "Release 1" HEADrefs/tags/v1 → tag object → target object
The subtle -m rule
One easy-to-miss rule matters when reading scripts: if -m or -F is supplied and -a, -s, and -u are absent, Git implicitly enables -a. Therefore these two commands both create annotated tags: the first says so explicitly; the second relies on the documented implication.
git tag -a release-1.1 -m "Release 1.1"
git tag release-1.1-message -m "Release 1.1"Quick check
What does `git tag v1.1 -m "Release 1.1"` create when no -a, -s, or -u option is present?
git tag v1.1 -m "Release 1.1"-m implies -a here → annotated tag
See the structural difference
You can verify the distinction in an isolated repository without inspecting Git's internal files. `git cat-file -t` reports the type of the object named by the revision: a lightweight tag resolves to a commit, while an annotated tag name resolves to a tag object. This is a verification technique for this lesson; the later object-model series explains Git object types in depth.
git tag temp-label HEAD
git tag -a release-2.0 -m "Release 2.0" HEAD
git cat-file -t temp-label
# commit
git cat-file -t release-2.0
# tag
git cat-file -t release-2.0^{}
# commitQuick check
In the example above, what object type does `git cat-file -t release-2.0` report?
git cat-file -t release-2.0tag
Choose the form by lifecycle
Git's own documentation describes annotated tags as the form intended for releases and lightweight tags as labels for private or temporary use. That is a documented distinction of intended lifecycle, not a rule that every tag in every repository must follow. When a release needs a tag message and tagger/date metadata, create an annotated tag explicitly with -a and -m.
# Temporary/private label
git tag review-build HEAD
# Release-oriented tag with annotation metadata
git tag -a v2.0.0 -m "Release 2.0.0" HEADQuick check
Which description matches Git's documented intended lifecycle for the two tag forms?
annotated vs lightweightrelease-oriented vs private/temporary labels
Stay inside this lesson's boundary
This lesson establishes the two creation forms and their structure. Tag listing/inspection details and deletion belong to the next lesson; cryptographic signature creation and verification belong to the following tag-verification lesson. The later object-model series will examine tag objects and references in greater depth. Do not use this lesson as a substitute for those focused topics.
Key takeaways
- A tag is a ref under refs/tags/ that marks an existing object.
- A lightweight tag points directly at its target object.
- An annotated tag points to a separate tag object carrying tag metadata and a message.
- Using -m or -F without -a, -s, or -u implies annotated-tag creation.
- Git documents annotated tags as release-oriented and lightweight tags as private or temporary labels.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.