Git Tag: Mark Releases and Milestones in Your History
Git tags let you permanently mark specific commits: typically releases or milestones. This tutorial covers creating lightweight and annotated tags, listing and pushing them, and the most common mistake developers make: forgetting that git push doesn't send tags automatically.
Beginner8 min readUpdated
What is a Git tag?
A Git tag is a named pointer to a specific commit that never moves. Tags come in two types: lightweight (just a pointer, no extra metadata) and annotated (stores a message, author, and date, recommended for releases). Tags must be pushed to a remote separately from commits.
The short version
- 1List existing tags:
git tag - 2Create an annotated tag:
git tag -a v1.0.0 -m 'Release 1.0.0' - 3Push a tag to remote:
git push origin v1.0.0 - 4View tag details:
git show v1.0.0 - 5Delete a tag locally:
git tag -d v1.0.0 - 6Delete a tag on remote:
git push origin --delete v1.0.0
Why it matters
You shipped a stable release but a week later you can't find the exact commit it was built from. Or you tagged a release locally and your teammates can't see it because you never pushed the tag. Sound familiar?
Tags are the standard way to mark release points (v1.0.0, v2.3.1) in your Git history. Unlike branches, they don't move. A tag permanently points to one commit, making it the reliable anchor for changelogs, rollbacks, and CI deployments.
Where it usually goes wrong
- Creating a tag locally but forgetting that
git pushdoes not push tags automatically - Using lightweight tags for releases instead of annotated tags, which carry no author, date, or message
- Tagging the wrong commit because you didn't check
git logfirst - Deleting a tag that was already pushed without removing it from the remote too
Git tag, step by step
Step 1: List all existing tags
Before creating a tag, check what tags already exist in the repository. Use
-lwith a glob pattern to filter by prefix.Terminal# List all tagsgit tag# Filter by pattern (e.g. v1.*)git tag -l "v1.*"# Show tags in chronological ordergit log --tags --simplify-by-decoration --onelineTip: Tags are listed alphabetically by default, which breaks for versions like v1.9.0 vs v1.10.0. Use
git tag -l --sort=-version:refnamefor correct semantic version ordering.Step 2: Create a lightweight tag
A lightweight tag is simply a name pointing to a commit, with no message, no author, and no date. Useful for temporary local bookmarks, but not recommended for public releases.
Terminal# Tag the current commit (HEAD)git tag v1.0.0# Tag a specific commitgit tag v1.0.0 9b1e4faCareful: Lightweight tags carry no metadata. Tools like GitHub Releases, CI pipelines, and changelog generators rely on annotated tag objects. Use annotated tags for anything public.
Step 3: Create an annotated tag (recommended for releases)
An annotated tag stores a message, the tagger's name and email, and a timestamp, making it a full Git object. Use
-afor annotated and-mfor an inline message.Terminal# Annotated tag on HEADgit tag -a v1.0.0 -m "Release version 1.0.0"# Annotated tag on a specific commitgit tag -a v1.0.0 -m "Release version 1.0.0" 9b1e4fa# View the tag details (message, tagger, date)git show v1.0.0Tip: Follow semantic versioning:
vMAJOR.MINOR.PATCH. Breaking changes → major, new features → minor, bug fixes → patch.Step 4: Push tags to remote
git pushdoes not push tags. You must push them explicitly, either one at a time or all at once with--tags.Terminal# Push a single taggit push origin v1.0.0# Push all local tags not yet on the remotegit push origin --tagsCareful:
git push --tagspushes every local tag including lightweight ones. To push only annotated tags alongside your latest commit, usegit push --follow-tags.In Gitoryx: Tags appear as labels directly on commits in the Gitoryx commit graph: no need to run git log --decorateHow it worksStep 5: Checkout a tag
Checking out a tag puts you in 'detached HEAD' state, meaning you're viewing the repository exactly as it was at that tagged commit. Any commits made here won't belong to a branch.
Terminalgit checkout v1.0.0# HEAD is now at 9b1e4fa... (detached)# To make changes based on a tag, create a branch from it:git checkout -b hotfix/v1.0.1 v1.0.0Tip: If you need to make a hotfix on a tagged release, always create a new branch from the tag rather than committing in detached HEAD.
Step 6: Delete a tag
Deleting a local tag does not remove it from the remote. You must delete it in both places separately.
Terminal# Delete a local taggit tag -d v1.0.0# Delete the tag on the remotegit push origin --delete v1.0.0Careful: Deleting a tag that others may have already pulled causes confusion. Communicate the deletion to your team before removing a public tag from the remote.
Mistakes to avoid with git tag
- Forgetting to push tags
git pushonly pushes commits and branch refs: tags are entirely separate. A tag that exists only locally is invisible to teammates, CI pipelines, and GitHub Releases.- Fix: After creating a tag, always run
git push origin <tagname>orgit push origin --tagsto make it available on the remote. - Using lightweight tags for releases
- Lightweight tags store no metadata. Tools like GitHub Releases, semantic-release, and changelog generators rely on annotated tag objects to generate release notes.
- Fix: Use
git tag -a <name> -m '<message>'for any tag intended as a public release. Reserve lightweight tags for private local bookmarks. - Tagging the wrong commit
- It's easy to tag HEAD without realising it's not the right commit, especially after a recent pull.
- Fix: Run
git log --oneline -5before tagging to confirm HEAD is correct. When in doubt, tag a specific SHA:git tag -a v1.0.0 -m 'msg' <sha>.
Git tag in Gitoryx
Gitoryx displays all tags inline on the commit graph: you can see at a glance which commits are tagged, create or delete tags with a right-click, and push them to remote in one click.
- Tags appear as labels directly on commits in the Gitoryx commit graph: no need to run
git log --decorate - Right-click any commit to create or delete a tag without copying a SHA
- Push tags to remote in one click from the tag context menu
- Gitoryx distinguishes annotated and lightweight tags visually in the graph
Free plan · no account required · macOS, Windows and Linux
Git tag: frequently asked questions
- What is the difference between a lightweight and annotated tag?
- A lightweight tag is just a named pointer to a commit with no extra data. An annotated tag is a full Git object that stores a message, the tagger's name and email, and a timestamp. Annotated tags are recommended for releases because they carry metadata and are treated as proper release objects by most tools.
- Why can't my teammates see my tag?
git pushdoes not push tags automatically. Rungit push origin <tagname>to push a specific tag, orgit push origin --tagsto push all local tags to the remote.- How do I tag a previous commit, not HEAD?
- Pass the commit SHA as the last argument:
git tag -a v1.0.0 -m 'message' <sha>. Find the SHA withgit log --oneline. - Can I move a tag to a different commit?
- Yes, but it requires force:
git tag -f v1.0.0 <new-sha>. If the tag was already pushed, also force-push it:git push origin -f v1.0.0. Only do this before others have pulled the tag. - How do I list tags sorted by semantic version?
- Use
git tag -l --sort=-version:refnameto list tags in descending semantic version order. This is more reliable than alphabetical sort for versions like v1.10.0 vs v1.9.0.
Related reading
- Git Log: How to Browse Your Commit HistoryTutorial · 9 min
- GitFlow Explained: The Classic Branching ModelTutorial · 11 min
- Git Commit: The Complete Beginner's GuideTutorial · 9 min