Tags as release markers
A Git tag is an immutable label on a commit. Annotated tags carry a tagger name, date, and message; lightweight tags are just a name. Use annotated tags for releases - they are first-class objects, GPG-signable, and queryable.
Creating tags
# Annotated
git tag -a v1.4.0 -m "Release 1.4.0"
# Signed (recommended for releases)
git tag -s v1.4.0 -m "Release 1.4.0"
# Lightweight (not recommended for releases)
git tag v1.4.0-alpha
Pushing tags
Tags are not pushed by default:
git push origin v1.4.0
git push --tags # push all tags (risky on large repos)
git push --follow-tags # push commits and reachable annotated tags
--follow-tags is the sweet spot - tags travel with their commits but unrelated tags do not.
Triggering CI on tags
GitHub Actions example that builds and publishes when a tag matches v*.*.*:
on:
push:
tags:
- 'v*.*.*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GitLab and other CIs use the same pattern - filter pipelines on a tag ref.
SemVer and prereleases
Stick to Semantic Versioning. CI logic can detect prerelease tags:
if [[ "$TAG" =~ -(alpha|beta|rc) ]]; then
npm publish --tag next
else
npm publish
fi
Generating changelogs from tags
git log v1.3.0..v1.4.0 --oneline --no-merges
# Or with conventional-changelog:
npx conventional-changelog -p angular -i CHANGELOG.md -s
Listing and inspecting tags
git tag # list all
git tag -l 'v1.*' # filter
git show v1.4.0 # tagger info + commit details
git tag --contains <sha> # which tags include this commit?
git describe --tags HEAD # nearest tag (handy in CI)
Tag protection
On GitHub or GitLab, configure tag protection rules so only release pipelines can create tags matching v*. This prevents accidental retags.
Deleting and moving tags
git tag -d v1.4.0
git push origin --delete v1.4.0
# Re-create at a new commit:
git tag -a v1.4.0 -m "Release 1.4.0" <new-sha>
git push origin v1.4.0
Avoid this on published tags - downstream consumers may have pinned the SHA.
The pipeline contract
Make your CI's tag pipeline the only path to production. Manual npm publish from a developer laptop is the historical cause of countless "wrong version shipped" incidents. Tag, push, watch CI - that is the contract.