Git Tag: The Complete Guide for 2026
Branches move. Tags should not. That one sentence explains why tags are the backbone of reliable releases in Git. A branch like main points to the latest commit today and a different commit tomorrow. A tag such as v2.4.0 points to one exact commit forever, giving your team and your CI/CD pipeline a stable reference for build artifacts, deployments, and rollbacks.
This guide covers Git tags end to end: lightweight vs annotated tags, how to create and publish release tags safely, semantic versioning patterns, signed tags for trusted releases, and practical workflows for fixing mistakes without breaking your team's history.
Table of Contents
- What a Git Tag Is and Why It Matters
- Lightweight vs Annotated Tags
- How to Create Tags
- How to List and Inspect Tags
- How to Push and Fetch Tags
- Working from a Tag Without Breaking History
- Deleting and Moving Tags Safely
- SemVer Release Workflow with Tags
- Signed Tags and Release Trust
- Troubleshooting Tag Problems
- Frequently Asked Questions
1. What a Git Tag Is and Why It Matters
A Git tag is a permanent label for one commit. Unlike branches, tags are intended to stay fixed. The most common use is versioning releases: v1.0.0, v1.0.1, v2.0.0.
Why teams rely on tags:
- Reproducible builds: build systems can fetch the exact release commit every time.
- Clear deployment inputs: "deploy
v2.3.1" is unambiguous. - Fast rollback: switching from
v2.4.0back tov2.3.3is straightforward. - Traceable release notes: each version maps to one point in history.
# Typical release tag names
v1.0.0
v1.0.1
v1.1.0
v2.0.0
2. Lightweight vs Annotated Tags
Git supports two tag types. Use annotated tags for almost every shared release workflow.
| Tag Type | What It Stores | Best Use |
|---|---|---|
| Lightweight | Only a name pointing to a commit | Temporary local markers |
| Annotated | Tagger, date, message, optional signature | Public releases and automation triggers |
# Lightweight tag
git tag v1.4.0
# Annotated tag (recommended for releases)
git tag -a v1.4.0 -m "Release v1.4.0"
If your deployment pipeline triggers on tags, use annotated tags so you always have release metadata and audit context.
3. How to Create Tags
Create a tag on the current commit
# Annotated release tag on current HEAD
git tag -a v2.1.0 -m "Release v2.1.0"
# Lightweight marker on current HEAD
git tag ready-for-qa
Create a tag on an older commit
# First, inspect history
git log --oneline --decorate -n 20
# Tag an explicit commit hash
git tag -a v2.0.3 9f6b3ac -m "Release v2.0.3 hotfix"
Tag from a clean release checklist
# 1) Verify working tree
git status
# 2) Sync with remote
git fetch origin
git rebase origin/main
# 3) Run tests
npm test
# 4) Create release tag
git tag -a v2.2.0 -m "Release v2.2.0"
# 5) Push branch + tag
git push origin main
git push origin v2.2.0
4. How to List and Inspect Tags
# List all tags
git tag
# Filter tags by pattern
git tag -l "v2.*"
# Sort tags by semantic-ish version names
git tag -l --sort=-version:refname
# Show details for one annotated tag
git show v2.1.0
For release tooling, sorted tag output is useful for identifying the latest version candidate:
# Print the newest version-like tag
LATEST_TAG=$(git tag -l "v*" --sort=-version:refname | head -n 1)
echo "$LATEST_TAG"
5. How to Push and Fetch Tags
Tags are not always pushed automatically with branch pushes. Treat tag publishing as an explicit step.
# Push one tag
git push origin v2.1.0
# Push all local tags not yet on remote
git push --tags
# Fetch remote tags
git fetch --tags
Prefer pushing one release tag at a time in production workflows. It avoids accidentally publishing private or draft tags from local experiments.
6. Working from a Tag Without Breaking History
Checking out a tag puts you in detached HEAD. That is safe for inspection, builds, or hotfix analysis, but you should create a branch before committing new work.
# Inspect exactly what shipped in v2.0.0
git switch --detach v2.0.0
# If you need code changes, branch immediately
git switch -c hotfix/v2.0.1-fix-timeout
Common release patch pattern:
# Start from shipped release tag
git switch -c hotfix/v2.0.1 v2.0.0
# Apply fix and commit
git commit -am "Fix timeout bug in payment webhook"
# Tag new patch release
git tag -a v2.0.1 -m "Release v2.0.1"
git push origin hotfix/v2.0.1
git push origin v2.0.1
7. Deleting and Moving Tags Safely
Sometimes a tag points to the wrong commit or was named incorrectly. Handle corrections carefully, especially after publication.
Delete a tag
# Delete local tag
git tag -d v2.1.0
# Delete remote tag
git push origin --delete v2.1.0
# equivalent: git push origin :refs/tags/v2.1.0
Move a tag to another commit
# Force move local tag
git tag -fa v2.1.0 -m "Retag v2.1.0" <new-commit>
# Force update remote tag (high risk for shared consumers)
git push origin -f v2.1.0
Recommendation: avoid moving published release tags. Create a new version tag instead (for example, v2.1.1) and document the correction in release notes.
8. SemVer Release Workflow with Tags
Most engineering teams combine Git tags with semantic versioning:
- MAJOR (
v3.0.0): breaking API changes - MINOR (
v3.2.0): backward-compatible features - PATCH (
v3.2.4): backward-compatible bug fixes
# Example release cadence
v3.1.0 # feature release
v3.1.1 # bugfix
v3.1.2 # bugfix
v3.2.0 # new features
v4.0.0 # breaking changes
A practical release flow:
- Merge approved changes into
main. - Run full test suite and smoke tests.
- Create annotated tag with release message.
- Push the tag and trigger CI/CD deployment.
- Generate changelog diff from previous tag to new tag.
# Changelog diff between releases
git log --oneline v3.1.2..v3.2.0
# Files changed between release tags
git diff --name-status v3.1.2..v3.2.0
9. Signed Tags and Release Trust
Unsigned tags prove nothing about who created them. Signed tags provide integrity and authorship checks, which is important for compliance-heavy environments and open-source releases.
# Create a signed annotated tag (GPG)
git tag -s v3.2.0 -m "Release v3.2.0"
# Verify signature
git tag -v v3.2.0
If your team already uses SSH signing for commits, align tag-signing policy with the same identity model so release automation can validate signatures consistently.
10. Troubleshooting Tag Problems
"Tag already exists"
# Check where it points
git show v2.0.0
# If truly incorrect, delete + recreate intentionally
git tag -d v2.0.0
git tag -a v2.0.0 <correct-commit> -m "Release v2.0.0"
"Remote rejected" when pushing a tag
The remote may already have that tag name. Inspect it first before forcing updates:
git ls-remote --tags origin | rg v2.0.0
Detached HEAD confusion
# You made commits while detached and want to keep them
git branch rescue/detached-work
# or
git switch -c rescue/detached-work
CI did not trigger on tag push
Check pipeline filters. Many CI systems require explicit tag patterns such as v* or refs/tags/*.
11. Frequently Asked Questions
What is the difference between lightweight and annotated Git tags?
A lightweight tag is only a name pointing at a commit. An annotated tag includes metadata such as creator, timestamp, and message, and can be signed. Use annotated tags for releases.
How do I push all tags to remote?
Run git push --tags. For production release flow, prefer git push origin <tag-name> to publish one validated version at a time.
How do I delete a tag locally and remotely?
Delete local tag with git tag -d <tag-name>, then remove remote tag with git push origin --delete <tag-name>.
Can I move a Git tag after it is created?
Yes, but do not move tags that are already published unless your team has an explicit policy and coordination window. Prefer creating a new patch version tag.
What does detached HEAD mean when checking out a tag?
HEAD points to a commit directly, not a branch. If you plan to commit changes, create a branch first with git switch -c <branch-name>.
Final Checklist Before You Publish a Release Tag
- Working tree clean (
git status) - Branch up to date with remote
- Tests passed for release commit
- Annotated tag created with clear release message
- Tag pushed explicitly to remote
- Release notes generated from previous tag diff
When your team treats tags as immutable release contracts, rollbacks become safer, production debugging gets faster, and deployment automation becomes predictable.