Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

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.

Levels: Intermediate ~30 min read

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.

bash
# Tag the current commit
git tag release-1.0

# Show the tag reference explicitly
git rev-parse refs/tags/release-1.0

Quick 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.

bash
git tag v1.0-temp

# The tag resolves directly to the commit
git rev-parse v1.0-temp

Quick 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.

bash
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.

bash
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.

bash
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^{}
# commit

Quick 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.

bash
# 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" HEAD

Quick 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.
Was this page helpful?

Mark this learning resource complete to track your learning progress.