Difficulty: Beginner
What are Git tags? Explain the difference between lightweight and annotated tags, and how they relate to release management.
Git tags are references that point to specific commits, typically used to mark release points (v1.0.0, v2.1.3, etc.). Unlike branches, tags do not move when new commits are made. They are permanent bookmarks in your history.
There are two types: 1. Lightweight tags: Simply a pointer to a commit. No metadata, no message. Like a branch that never moves. 2. Annotated tags: Full Git objects with tagger name, email, date, and a message. Can be GPG-signed. These are recommended for releases because they carry context about who tagged it and why.
Tags work hand-in-hand with Semantic Versioning (SemVer): MAJOR.MINOR.PATCH. MAJOR for breaking changes, MINOR for new features (backward-compatible), PATCH for bug fixes. Tags are also the basis for GitHub/GitLab Releases, which attach binaries and changelogs to a tagged commit.
# Lightweight tag (just a pointer)
git tag v1.0.0
# Annotated tag (recommended for releases)
git tag -a v1.0.0 -m "Release 1.0.0: initial stable release"
# Tag a specific past commit
git tag -a v0.9.0 -m "Beta release" a1b2c3d
# List all tags
git tag
# v0.9.0
# v1.0.0
# List tags matching a pattern
git tag -l "v1.*"
# Show tag details
git show v1.0.0
# tag v1.0.0
# Tagger: John <john@example.com>
# Date: Mon Jan 15 10:00:00 2024
# Release 1.0.0: initial stable release
# commit a1b2c3d ...
# Delete a local tag
git tag -d v1.0.0
# Delete a remote tag
git push origin --delete v1.0.0
Always use annotated tags (-a) for releases. Lightweight tags are fine for temporary local markers. Use git show to inspect tag details.
# Push a specific tag to remote
git push origin v1.0.0
# Push all tags at once
git push --tags
# Push only annotated tags (skip lightweight)
git push --follow-tags
# Create a GitHub release with gh CLI
gh release create v1.0.0 \
--title "Release 1.0.0" \
--notes "## What's New
- User authentication
- Job posting CRUD
- ATS scoring engine" \
./dist/app.zip
# List releases
gh release list
# Download a release asset
gh release download v1.0.0
# Checkout a specific tag
git checkout v1.0.0
# Warning: detached HEAD state
# Create a branch if you need to make changes:
git checkout -b hotfix/v1.0.1 v1.0.0
Tags must be explicitly pushed to remote. Use --follow-tags to only push annotated tags. GitHub Releases are built on top of Git tags.
# Semantic Versioning: MAJOR.MINOR.PATCH
# 1.0.0 → 1.0.1 (patch: bug fix)
# 1.0.0 → 1.1.0 (minor: new feature, backward compatible)
# 1.0.0 → 2.0.0 (major: breaking change)
# Typical release workflow:
# 1. Update version in package.json
npm version patch # 1.0.0 → 1.0.1 (auto-creates tag)
npm version minor # 1.0.0 → 1.1.0
npm version major # 1.0.0 → 2.0.0
# npm version automatically:
# - Updates package.json version
# - Creates a git commit
# - Creates a git tag (v1.0.1)
# 2. Push with tags
git push --follow-tags
# Pre-release tags
git tag -a v2.0.0-beta.1 -m "Beta 1 for v2.0.0"
git tag -a v2.0.0-rc.1 -m "Release candidate 1"
# Sort tags by version
git tag --sort=-v:refname
# v2.0.0-rc.1
# v2.0.0-beta.1
# v1.1.0
# v1.0.1
# v1.0.0
npm version automates the tag+commit workflow. SemVer communicates the nature of changes to users. Pre-release tags (beta, rc) signal stability level.
git tag, Lightweight Tags, Annotated Tags, Semantic Versioning, Releases