|$ curl https://forge-ai.dev/api/markdown?path=docs/git/tags
$cat docs/git-—-tags-&-releases.md
updated Recently·10 min read·published

Git — Tags & Releases

GitBeginner
Introduction

Tags in Git are static references to a specific commit, typically used to mark release points (v1.0, v2.3.1, etc.). Unlike branches, tags do not move when new commits are made — they are permanent markers in your project's history.

This guide covers lightweight and annotated tags, signing tags with GPG, semantic versioning conventions, and release tagging workflows.

Lightweight vs Annotated Tags

Git supports two types of tags: lightweight and annotated. The difference is that annotated tags store metadata (tagger name, email, date, message) and can be cryptographically signed.

FeatureLightweightAnnotated
StorageJust a name pointing to a commitFull Git object with metadata
Tagger infoNo tagger informationStores name, email, date
MessageNo messageHas a tag message (like a commit)
SigningCannot be signedCan be GPG or SSH signed
Use casePersonal bookmarks, temporary markersReleases, public tags
terminal
Bash
1# Create a lightweight tag (just a pointer)
2git tag v1.0.0
3
4# Create an annotated tag (recommended for releases)
5git tag -a v1.0.0 -m "Release v1.0.0 — stable API"
6
7# Create an annotated tag with a longer message
8git tag -a v1.0.0 -m "Release v1.0.0
9
10This release introduces the new payment API
11and deprecates the legacy checkout system."

best practice

Always use annotated tags (git tag -a) for public releases. They provide provenance — anyone inspecting the tag can see who created it, when, and why. Use lightweight tags only for local, temporary markers.
Creating Tags

Tags can target the current commit, a specific commit hash, or even a previous tag. You can also tag after the fact — perfect for marking a commit you forgot to tag at release time.

terminal
Bash
1# Tag the current commit
2git tag -a v2.0.0 -m "Release v2.0.0"
3
4# Tag a specific commit by hash
5git tag -a v1.9.0 abc123def -m "Hotfix v1.9.0"
6
7# Tag a commit relative to HEAD
8git tag -a v1.8.0 HEAD~3 -m "Release v1.8.0"
9
10# Tag the commit that created a specific branch
11git tag -a v1.7.0 origin/main -m "Release v1.7.0"
12
13# Create a tag with a message from a file
14git tag -a v2.1.0 -F release-notes.txt
15
16# Re-tag (move a tag to a different commit)
17git tag -a -f v2.0.0 new-commit-hash -m "Moved tag"

warning

Moving a tag with -f is dangerous if the tag has already been pushed and others may have fetched it. Git tags are meant to be immutable. Only force-replace tags on unreleased commits or after coordinating with your team.
Viewing & Listing Tags

Git provides several ways to list, search, and inspect tags. Tags are sorted alphabetically by default, which aligns well with semantic versioning when using leading zeros.

terminal
Bash
1# List all tags
2git tag
3# v1.0.0
4# v1.1.0
5# v2.0.0
6
7# List tags matching a pattern
8git tag -l "v2.*"
9# v2.0.0
10# v2.0.1
11
12# Show tag details (annotated tag)
13git show v1.0.0
14# tag v1.0.0
15# Tagger: Alice <alice@example.com>
16# Date: Mon Mar 4 10:00:00 2024 +0000
17# Release v1.0.0
18# commit abc123def456...
19
20# List tags with commit information
21git tag -n
22# v1.0.0 Release v1.0.0
23# v1.1.0 Release v1.1.0 — minor features
24
25# Sort tags by version (git 2.0+)
26git tag --sort=-version:refname
Pushing Tags to Remote

Unlike branches, tags are not pushed automatically when you run git push. You must explicitly push tags to the remote repository.

terminal
Bash
1# Push a specific tag
2git push origin v1.0.0
3
4# Push all tags that don't exist on remote
5git push origin --tags
6
7# Push tags matching a pattern
8git push origin --follow-tags
9# Only pushes annotated tags that are reachable from pushed commits
10
11# Delete a tag on the remote
12git push origin --delete v1.0.0
13
14# Or use the refspec syntax
15git push origin :refs/tags/v1.0.0
16
17# Fetch tags from remote
18git fetch --tags
19
20# Fetch tags and prune deleted ones
21git fetch --tags --prune

info

Configure git config --global push.followTags true to automatically push annotated tags when you push commits they point to. This ensures you never forget to push a release tag after pushing release commits.
Deleting Tags

Deleting tags locally and on remote follows similar syntax. You should delete locally first, then push the deletion to the remote.

terminal
Bash
1# Delete a local tag
2git tag -d v1.0.0
3
4# Delete a remote tag
5git push origin --delete v1.0.0
6
7# Delete multiple local tags
8git tag -d v1.0.0 v1.1.0 v1.2.0
9
10# Delete all local tags that match a pattern
11git tag -d $(git tag -l "v1.0.*")
12
13# Clean up remote tags that no longer exist locally
14git fetch --tags --prune
Signed Tags (GPG)

Signed tags provide cryptographic verification that a tag was created by a trusted identity. This is important for open-source projects and software distribution, where consumers need to verify release authenticity.

terminal
Bash
1# Create a GPG-signed tag
2git tag -s v1.0.0 -m "Release v1.0.0"
3
4# Create a tag signed with your default GPG key
5# You'll be prompted for your GPG passphrase
6
7# Verify a signed tag
8git tag -v v1.0.0
9# gpg: Signature made Mon Mar 4 10:00:00 2024
10# gpg: using RSA key ABCDEF1234567890
11# gpg: Good signature from "Alice <alice@example.com>"
12
13# Configure Git to always sign tags
14git config --global tag.gpgSign true
15
16# List tags with verification status
17git tag --verify
18
19# If you don't have GPG, you can use SSH signatures:
20git tag -s v1.0.0 -m "Release v1.0.0" # with ssh format
21# Requires: git config gpg.format ssh
🔥

pro tip

Set up your GPG key in GitHub to display verified tags on your repository. Go to GitHub Settings > SSH and GPG keys to add your public key. Then tags you push with git tag -s will show as verified on the releases page.
Tags & Semantic Versioning

Git tags pair naturally with Semantic Versioning (SemVer). The standard convention is to prefix version numbers with v (e.g., v1.2.3), following the MAJOR.MINOR.PATCH format.

terminal
Bash
1# Standard SemVer tag formats
2git tag -a v1.0.0 -m "Initial stable release"
3git tag -a v2.3.1 -m "Bugfix release"
4git tag -a v3.0.0-alpha.1 -m "Alpha preview"
5git tag -a v3.0.0-beta.2 -m "Beta release"
6git tag -a v3.0.0-rc.1 -m "Release candidate"
7
8# Pre-release suffixes sort before the release
9# v3.0.0-alpha < v3.0.0-alpha.1 < v3.0.0-beta < v3.0.0-rc.1 < v3.0.0
10
11# Build metadata (not used in precedence)
12git tag -a v1.0.0+build.20240304 -m "With build metadata"
13
14# Find the latest tag
15git describe --tags --abbrev=0
16
17# Find the latest tag matching a pattern
18git describe --tags --match "v[0-9]*" --abbrev=0

info

Use git describe --tags in your build scripts to embed the current version into your application. It returns the nearest tag with the number of commits since that tag and an abbreviated commit hash (e.g., v1.0.0-5-gabc1234).
Tagging Workflows for Releases

Teams adopt different tagging strategies depending on their release process. Here are common workflows for tagging releases:

terminal
Bash
1# Workflow 1: Tag on main after merge
2# 1. Feature branch merged to main
3# 2. CI passes on main
4# 3. Tag and release
5git checkout main
6git pull
7git tag -a v1.2.0 -m "Release v1.2.0"
8git push origin v1.2.0
9
10# Workflow 2: Tag on release branch (Git Flow)
11git checkout release/1.3
12# ... final testing and fixes ...
13git commit -m "Release 1.3 preparations"
14git tag -a v1.3.0 -m "Release v1.3.0"
15git push origin v1.3.0
16git checkout main
17git merge release/1.3
18
19# Workflow 3: Automated tagging via CI
20# In CI pipeline (GitHub Actions example):
21# - name: Tag release
22# run: |
23# git tag -a v${env.VERSION} -m "Release v${env.VERSION}"
24# git push origin v${env.VERSION}
25#
26# This integrates with semantic-release for full automation
Best Practices

Always Use Annotated Tags for Releases

Public releases should always use annotated tags with a descriptive message. Lightweight tags are fine for personal bookmarks but lack the metadata needed for provenance.

Follow SemVer Conventions

Use the vMAJOR.MINOR.PATCH format for all release tags. This ensures compatibility with tools like npm version, Go modules, and semantic-release.

Automate Tagging in CI/CD

Use tools like semantic-release or CI pipeline scripts to create tags automatically. This reduces human error and ensures every release is properly tagged.

Sign Release Tags

For public packages and open-source projects, sign your release tags with GPG. This allows consumers to verify that the release was created by you and has not been tampered with.

$Blueprint — Engineering Documentation·Section ID: GIT-TAGS·Revision: 1.0