Stage 2 · Tools
Branching & Merging
Tagging Releases
Lightweight vs annotated tags, semantic versioning, and release workflows that scale with your team.
What Tags Are
A tag is a permanent reference to a specific commit. Unlike branches, tags never move. When you tag commit v1.0, that tag will always point to that exact commit, no matter how many commits are made after it.
Tags are Git's mechanism for marking release points. They give you a stable name to reference instead of remembering commit hashes. v2.1.0 is much easier to remember than a1b2c3d4e5f6.
A branch pointer advances with each new commit. A tag pointer stays fixed. This makes tags ideal for marking releases, milestones, and points-in-time that should never change.
Lightweight vs Annotated Tags
| Feature | Lightweight Tag | Annotated Tag |
|---|---|---|
| Stores | Commit hash only | Tag object with message, date, author, GPG signature |
| Recommended | For temporary or personal markers | For releases and shared tags |
| Signed | No | Yes (with GPG/SSH signing) |
| Visible in git tag | Yes | Yes |
| Metadata | None | Tagger name, date, annotation message |
| Can be verified | No | Yes — git verifies the tag object |
For releases, always use annotated tags. They store metadata about who created the tag, when, and why. Lightweight tags are useful for personal bookmarks or temporary markers.
Creating Tags
# Create a lightweight tag at the current commit
git tag v1.0.0
# Create at a specific commit
git tag v1.0.0 a1b2c3d
# Lightweight tag — just a pointer, no metadata
cat .git/refs/tags/v1.0.0
# a1b2c3d4e5f6...A lightweight tag is a file containing a commit hash. It has no author, no date, no message. It is simply a named pointer.
# Create an annotated tag with a message
git tag -a v1.0.0 -m "Release version 1.0.0 — initial stable release"
# Create at a specific commit
git tag -a v1.0.0 a1b2c3d -m "Backport critical fix to v1.0.0"
# Tag the current commit with a detailed message
git tag -a v2.0.0 -m "Version 2.0.0
Major changes:
- New authentication system
- API v2 endpoints
- Breaking changes in config format
See CHANGELOG.md for details."Annotated tags create a tag object in Git's object database. The object stores the tagger's name, email, date, and the annotation message. It also points to the commit it tags.
Annotated tags are the standard for release versions. They can be signed with GPG for security, and they store metadata that makes release management easier. Reserve lightweight tags for personal bookmarks.
Listing and Finding Tags
# List all tags
git tag
# List tags with details
git tag -n
# List tags matching a pattern
git tag -l "v1.*"
git tag -l "v2.0.*"
# List tags sorted by version (using version sort)
git tag --sort=-version:refname
# Show details of a specific tag
git show v1.0.0The -l flag filters tags by pattern. --sort=-version:refname sorts tags in descending version order. git show displays the tag metadata and the commit it points to.
# Resolve a tag to its commit hash
git rev-parse v1.0.0
# Show the commit log from a tag
git log v1.0.0..HEAD
# Show what changed since a tag
git diff v1.0.0..HEAD --statTags can be used anywhere you would use a commit hash. They work with git log, git diff, git checkout, and any other command that accepts a commit reference.
Deleting Tags
# Delete a tag locally
git tag -d v1.0.0
# Delete a tag from the remote
git push origin --delete v1.0.0
# Or push an empty reference to delete
git push origin :refs/tags/v1.0.0Deleting a tag locally removes the reference. Deleting from the remote removes it for everyone. Be cautious — if others are using the tag, notify them before deleting.
Once you delete a tag from the remote, anyone who has not already fetched it will not be able to pull it. If the tag was used for a release, consider creating a new tag instead of reusing the old name.
Semantic Versioning
Semantic versioning (semver) is a version numbering convention that communicates the nature of changes in a release. Every version follows the format MAJOR.MINOR.PATCH.
| Component | Increments When | Example |
|---|---|---|
| MAJOR | Breaking changes — incompatible API changes | v1.0.0 → v2.0.0 |
| MINOR | New features — backward-compatible additions | v1.0.0 → v1.1.0 |
| PATCH | Bug fixes — backward-compatible fixes | v1.0.0 → v1.0.1 |
# v1.0.0 — Initial stable release
git tag -a v1.0.0 -m "Initial stable release"
# v1.0.1 — Bug fix release
git tag -a v1.0.1 -m "Fix login timeout bug"
# v1.1.0 — New feature, backward compatible
git tag -a v1.1.0 -m "Add search functionality"
# v2.0.0 — Breaking change
git tag -a v2.0.0 -m "Migrate to new authentication system (breaking)"Follow semver consistently. It helps users understand the impact of upgrading. Pre-release versions can use suffixes like v1.0.0-beta.1 or v1.0.0-rc.1.
Use suffixes for pre-release versions: v1.0.0-alpha.1, v1.0.0-beta.2, v1.0.0-rc.1. The alpha/beta/rc tag indicates stability. Build metadata can be appended with a +: v1.0.0+build.123.
Pushing Tags to Remote
# Push a single tag
git push origin v1.0.0
# Push all local tags
git push --tags
# Push with signing
git push --signed origin v1.0.0Tags are not pushed automatically with git push. You must explicitly push them. Use --push-option=ofollow if your server requires it. The --signed flag signs the push for verification.
# Fetch all tags from remote
git fetch --tags
# Fetch and update existing tags
git fetch --tags --forceBy default, git fetch may not update tags. Use --tags to ensure all remote tags are fetched and updated locally.
Release Workflows
Tags are the foundation of release workflows. They mark the exact commit that shipped to production, enabling rollback, changelog generation, and deployment automation.
# 1. Ensure main is up to date
git switch main
git pull origin main
# 2. Run tests to verify the release
npm test
# 3. Create an annotated tag
git tag -a v2.1.0 -m "Release v2.1.0
Features:
- New dashboard layout
- Improved search performance
Fixes:
- Fixed login timeout on mobile
- Resolved race condition in WebSocket handler"
# 4. Push the tag
git push origin v2.1.0
# 5. Create a GitHub release (if using GitHub)
gh release create v2.1.0 --generate-notesThis workflow creates a tagged release that can be deployed, referenced in documentation, and used for rollback. The gh release create command auto-generates release notes from merged PRs.
# Check out a tagged version
git checkout v2.0.0
# Create a branch from a tag for hotfixes
git switch -c hotfix/rollback v2.0.0
# Deploy a specific tag in CI/CD
git clone --branch v2.0.0 <repo-url>Tags make rollback straightforward. You can check out any tagged version, create hotfix branches from old releases, or reference specific tags in CI/CD pipelines.
Use CI/CD pipelines to create tags automatically when code is merged to main. Tools like semantic-release, changesets, or GitHub Actions can analyze commit messages and create properly versioned tags.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.