Last updated: 2026-05-17

Tagging

Tags are named pointers to specific commits in your repository's history. While branches move forward automatically with every new commit, tags are permanent markers that stay fixed to the exact commit they point to. They are most commonly used to mark release points — v1.0, v2.0, v2.1.3 — creating a permanent, human-readable reference to the state of a project at a significant moment.


Two Types of Tags

Git supports two kinds of tags with meaningfully different purposes:

TypeWhat It IsWhen to Use It
LightweightA simple pointer to a commit — just a name and a hash, nothing more.Temporary markers, personal bookmarks, or quick references during development.
AnnotatedA full object stored in Git's database. Contains tagger name, email, date, a message, and can be GPG-signed.Release versions and any tag meant to be permanent and shared.

Annotated tags are the recommended default for anything meaningful. They carry context — who tagged it, when, and why — that a lightweight tag cannot.


Creating an Annotated Tag

Use the -a flag with a message:

git tag -a v1.4 -m "Release version 1.4"

To write the message in your editor instead (like a commit message):

git tag -a v1.4

Viewing an annotated tag shows the full tag metadata before the commit it points to:

git show v1.4
tag v1.4
Tagger: Wariz <wariz@example.com>
Date:   Sat May 3 20:19:12 2024 -0700

Release version 1.4

commit ca82a6dff817ec66f44342007202690a93763949
Author: Wariz <wariz@example.com>
Date:   Mon Mar 17 21:52:11 2024 -0700

    Change version number

Creating a Lightweight Tag

Provide only the tag name — no -a, -s, or -m flags:

git tag v1.4-lw

A lightweight tag stores only the commit checksum. Running git show on it skips the tag metadata and goes straight to the commit:

git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Wariz <wariz@example.com>
Date:   Mon Mar 17 21:52:11 2024 -0700

    Change version number

Listing Tags

List all tags in the repository:

git tag
v1.0
v1.2
v1.3
v1.4
v1.4-lw
v1.5

Tags are listed alphabetically. To search for tags matching a pattern, use -l with a wildcard:

git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5.1
v1.8.5.2

The -l flag is optional for a plain listing but required when using wildcard patterns.


Tagging a Past Commit

You can tag any commit in your history after the fact by providing its hash at the end of the command:

# Find the commit you want to tag
git log --oneline

# Tag it
git tag -a v1.2 9fceb02 -m "Version 1.2"

This is useful when you forgot to tag a release at the time and need to add the marker retroactively.


Pushing Tags to a Remote

By default, git push does not transfer tags to remote repositories. Tags must be pushed explicitly.

Push a single tag

git push origin v1.4

Push all tags at once

git push origin --tags

This transfers all local tags not already present on the remote. Note that --tags pushes both lightweight and annotated tags together.

To push only annotated tags (which is often preferable since they carry more information):

git push origin --follow-tags

Deleting Tags

Delete a local tag

git tag -d v1.4-lw

This removes the tag from your local repository only. The remote is unaffected.

Delete a remote tag

# Modern syntax (preferred)
git push origin --delete v1.4-lw

# Older syntax (still works)
git push origin :refs/tags/v1.4-lw

Deleting a remote tag requires two steps — first delete it locally, then push the deletion to the remote.


Checking Out a Tag

You can check out a tag to view the state of the project at that exact point:

git checkout v2.0.0

However, this puts your repository in detached HEAD state — meaning you are no longer on any branch. Any commits you make in this state will not belong to a branch and can be lost once you switch away.

Note: switching to 'v2.0.0'.
You are in 'detached HEAD' state.

If you need to make changes based on a tagged version — for example, applying a hotfix to an older release — create a new branch from the tag first:

git checkout -b hotfix-v2.0 v2.0.0

Now you are on a proper branch pointing to the same commit as the tag, and any new commits will be tracked safely.


Semantic Versioning

Tags are most useful when paired with a consistent naming convention. The widely adopted standard is semantic versioning (SemVer), which uses the format vMAJOR.MINOR.PATCH:

SegmentWhen to increment
MAJORBreaking changes — the API or behaviour changes incompatibly
MINORNew features added in a backwards-compatible way
PATCHBug fixes and small backwards-compatible changes

Examples: v1.0.0, v1.2.0, v1.2.3, v2.0.0

Pre-release suffixes like -rc1 (release candidate) or -beta are also common: v2.0.0-rc1.

Using SemVer consistently makes your tags meaningful to anyone reading the project history — they can immediately understand the significance of a version change from the number alone.


Summary

CommandWhat It Does
git tagLists all tags
git tag -l "pattern*"Lists tags matching a pattern
git tag -a v1.0 -m "msg"Creates an annotated tag
git tag v1.0Creates a lightweight tag
git tag -a v1.0 <hash>Tags a past commit
git show v1.0Shows tag details and the tagged commit
git push origin v1.0Pushes a single tag to remote
git push origin --tagsPushes all tags to remote
git push origin --follow-tagsPushes only annotated tags to remote
git tag -d v1.0Deletes a local tag
git push origin --delete v1.0Deletes a remote tag
git checkout v1.0Checks out a tag (detached HEAD)
git checkout -b <branch> v1.0Creates a branch from a tag