- Developers who already know basic commit and branch actions
- Readers who want to understand command boundaries and risk
Command Reference
git tag Tutorial
Introduces git tag for release points, explains lightweight versus annotated tags, and covers basic tag publishing.
- A basic mental model of worktree, index, and commits
- Comfort reading `git status` and a small commit graph
- Using local cleanup commands on already shared history
- Continuing to rewrite before confirming a recovery path
The short version
git tag gives a stable name to a specific commit, most often for releases.
Common forms
git tag v1.0.0
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin --tags
What problem this command solves in a workflow
git tag operates at the reference layer, binding a stable name to a specific commit. Unlike branches, tags typically never move once created, so it solves the problem of "giving a permanent name to a point in history" rather than managing day-to-day development workflow.
Typical use cases
- Tag release versions (e.g.,
v1.0.0) so the team and CI/CD systems have a clear release anchor point. - Use annotated tags (
-a) to record the tagger and a message, which suits formal release processes. - Lightweight tags are handy for local, temporary markers that you do not need to push to the team.
Diagram view
Signed tag workflow (GPG)
Signed tags provide cryptographic proof of who created the tag and that it hasn't been tampered with.
Setup
First, generate or import a GPG key, then tell Git which key to use:
# Generate a new GPG key (if you don't have one)
gpg --full-generate-key
# List your keys and find the key ID
gpg --list-secret-keys --keyid-format=long
# Configure Git to use this key
git config --global user.signingkey <KEY-ID>
Creating and verifying signed tags
# Create a signed tag (-s implies annotated)
git tag -s v2.0.0 -m "Release v2.0.0"
# Verify a signed tag
git tag -v v2.0.0
Verification shows the GPG signature status and the tag message. A "Good signature" confirms the tag is authentic.
Tag push strategies
Tags are not pushed automatically with git push. You must push them explicitly:
# Push a specific tag
git push origin v1.0.0
# Push all local tags at once
git push origin --tags
# Push only tags reachable from a specific branch
git push origin --follow-tags
Recommendation: Use --follow-tags (with push.followTags true in config) to push only annotated tags that are on the current branch. This avoids accidentally pushing experimental lightweight tags.
Lightweight vs annotated tags
| Feature | Lightweight Tag | Annotated Tag |
|---|---|---|
| Created with | git tag v1.0 | git tag -a v1.0 -m "message" |
| Git object | Reference only | Full tag object |
| Metadata | None | Tagger, date, message |
| Can be signed | No | Yes (-s flag) |
| Best for | Local markers, quick references | Releases, public version points |
Shown in git log | As commit hash | As tag object with message |
| Pushed by default | No | No (requires explicit push) |
Rule of thumb: Use annotated tags for anything you share with the team. Use lightweight tags only for private, temporary markers.
Tag naming conventions
Consistent tag names make automation and collaboration easier:
- SemVer:
v1.2.3— the most common convention. Thevprefix is widely adopted by CI/CD tools. - Date-based:
2024-01-15-release— useful for time-driven release schedules. - Pre-release:
v1.0.0-alpha.1,v1.0.0-beta.2,v1.0.0-rc.1— following SemVer pre-release identifiers. - Avoid spaces and special characters — use hyphens and dots only.
Configure push.followTags to automatically push annotated tags:
git config --global push.followTags true
Deleting tags
Local deletion
git tag -d v1.0.0
Remote deletion
# Using --delete
git push origin --delete v1.0.0
# Or push nothing to the remote tag ref
git push origin :refs/tags/v1.0.0
Delete all local tags and re-fetch from remote
git tag -l | xargs git tag -d
git fetch --tags
Caution: Deleting a published tag that others have already fetched can cause confusion. If you must correct a tag, communicate the change to your team.
Special cases and boundaries
- When a tag name and a branch name conflict in the same namespace, ambiguity arises, so naming should be distinctive.
- Tags are created locally by default and are not automatically synced to the remote with
git push. - A lightweight tag is just a reference pointer, while an annotated tag is a full object with metadata — prefer annotated tags for releases.
- Renaming a commit that already has a tag requires
-fto force-overwrite, but use caution to avoid misleading collaborators.