Skip to content

Git Tags — Versioning and Releases

DodaTech 3 min read

In this tutorial, you'll learn about Git Tags. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

What You'll Learn

Use Git tags to mark specific points in history — create lightweight and annotated tags, push them to remotes, and use them for versioned releases.

Why It Matters

Tags are how you mark releases, versions, and milestones. They let you quickly go back to any release without remembering commit hashes.

Real-World Use

Tagging a release as v1.2.3 so production always deploys from that tag, or marking v2.0.0-rc1 for a release candidate.

Lightweight vs Annotated Tags

Aspect Lightweight Annotated
Storage Just a pointer Full object in Git database
Metadata None Tagger name, email, date, message
Signing No Can be GPG-signed
Use case Private, temporary markers Public releases
Creation git tag v1.0 git tag -a v1.0 -m "v1.0 release"

Creating Tags

# Lightweight tag (just a name for a commit)
git tag v1.0.0

# Annotated tag (recommended for releases)
git tag -a v1.0.0 -m "Version 1.0.0 — Initial stable release"

# Tag a specific commit (instead of HEAD)
git tag -a v1.0.0 a1b2c3 -m "Version 1.0.0"

# Tag with GPG signature
git tag -s v1.0.0 -m "Signed release v1.0.0"

# Tag for a release candidate
git tag -a v2.0.0-rc1 -m "Release candidate 1 for v2.0.0"

Listing Tags

# List all tags
git tag

# Search for tags matching a pattern
git tag -l "v1.*"

# List tags with messages
git tag -n

# Show tag details
git show v1.0.0

Pushing Tags

# Push a specific tag
git push origin v1.0.0

# Push all tags
git push --tags

# Delete a remote tag
git push --delete origin v1.0.0

# Delete a local tag
git tag -d v1.0.0

Semantic Versioning with Tags

Use SemVer for tag names:

vMAJOR.MINOR.PATCH

v1.0.0      # Initial release
v1.1.0      # Backward-compatible feature add
v1.1.1      # Bug fix
v2.0.0      # Breaking change

# With pre-release labels:
v2.0.0-alpha.1
v2.0.0-beta.1
v2.0.0-rc.1

Creating a Release Workflow

# 1. Prepare the release
git checkout main
git pull
# Run tests, update version numbers, etc.

# 2. Create the tag
git tag -a v1.2.0 -m "Release v1.2.0 — New payment feature"

# 3. Push the tag
git push origin v1.2.0

# 4. Create a release on GitHub
gh release create v1.2.0 \
  --title "v1.2.0 — New Payment Feature" \
  --notes "Added Stripe integration, fixed CSV export bug" \
  --target main

Checking Out a Tag

# View the code at a tag
git checkout v1.0.0

# ⚠️ This puts you in "detached HEAD" state
# You can view/test but shouldn't make changes here

# If you need to work from a tag, create a branch:
git checkout -b release/v1.0.x v1.0.0

Using Tags for Deployment

# In CI/CD (GitHub Actions example)
name: Deploy from Tag
on:
  push:
tags:
      - 'v*'

jobs:
  deploy:
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.ref }}  # Checkout the tag
      - run: ./deploy.sh

Migrating Tags

# Move a tag to the current commit
git tag -f v1.0.0 HEAD

# Rename a tag (create new, delete old)
git tag v1.0.1 v1.0.0
git tag -d v1.0.0
git push origin v1.0.1
git push --delete origin v1.0.0

Best Practices

Practice Why
Always use annotated tags for releases Metadata and signing
Follow SemVer Clear version meaning
Tag after merge to main Stable commit
Push tags separately from branches Cleaner history
Never change a published tag Others may depend on it
Document what each tag means Team alignment

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro