Tags & Releases
A tag is a named pointer to a commit, used most often for releases. There are two kinds: lightweight (just a name pointing at a commit) and annotated (its own object with author, date, message, optional GPG signature). Default to annotated tags for anything you publish — they carry provenance.
Create, list, push, sign, and delete tags
EXAMPLE
# 1) Annotated tag with a message (the right default for releases)
git tag -a v1.2.3 -m 'Release 1.2.3 — bug fix for shipping calc'
# 2) Lightweight tag — quicker, no metadata. Fine for personal bookmarks.
git tag prod-2026-06-11
# 3) Tag a past commit by hash
git tag -a v1.2.2 9fceb02 -m 'Belated tag for the prior release'
# 4) Sign a tag (GPG or SSH) — verifiable provenance
git tag -s v1.2.3 -m 'Signed release 1.2.3'
git tag -v v1.2.3 # verify signature
# 5) List tags, with pattern filtering
git tag
git tag --list 'v1.*'
git tag --sort=-version:refname # newest first, semver-aware
# 6) Push tags to the remote — they are NOT pushed by default
git push origin v1.2.3
git push origin --tags # push every local tag
git push --follow-tags # only push annotated tags reachable from HEAD
# 7) Delete a tag locally and on the remote
git tag -d v1.2.3
git push origin :refs/tags/v1.2.3 # legacy syntax, still works
git push origin --delete v1.2.3 # newer syntax
# 8) Move a tag to a different commit (last resort — published tags should never move)
git tag -fa v1.2.3 <newSha> -m 'Move tag; only do this BEFORE pushing'
# 9) Check out the code for a tag — detached HEAD
git checkout v1.2.3 # work in detached HEAD
git switch --detach v1.2.3 # explicit (Git 2.23+)
# 10) Pipe tags into a release notes section
git log v1.2.2..v1.2.3 --pretty=format:'* %s (%h)' --no-merges
# 11) CI flow: bump version, commit, tag, push
# scripts/release.sh (sketch)
# v="v${1:?usage: release VERSION}"
# git tag -a "$v" -m "Release $v"
# git push --follow-tags
Why it matters
Treat tags as immutable once pushed. Moving or deleting a published tag breaks every clone, every CI artifact, every reference in changelogs. The cost of moving a tag is real even when nothing visibly explodes — it silently corrupts other peoples sense of what \"v1.2.3\" means.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…