Git Tagging
Mark releases properly. Lightweight vs annotated tags, why push ignores tags, deleting safely, tagging old commits, and how tags drive semantic-versioned releases.
What a Tag Is
A tag is a named reference to a specific commit. Teams often use tags to mark releases such as v1.0.0, v1.1.0, or prod-2026-07-14.
Unlike branches, tags normally do not move. They point to an exact moment in history.
Tip: Use tags to mark important milestones such as production releases, stable demos, or compliance snapshots.
Lightweight vs Annotated Tags
Git supports two common tag types.
Lightweight Tag
A lightweight tag is just a simple name pointing to a commit.
git tag v1.0.0
This is quick and useful for personal or temporary markers.
Annotated Tag
An annotated tag stores extra metadata such as the tagger name, date, and message.
git tag -a v1.0.0 -m "Release version 1.0.0"
Annotated tags are generally better for official releases.
Listing Tags
To list all tags:
git tag
To filter by a pattern:
git tag -l "v1.*"
This is useful when a repository has many releases.
Tagging Older Commits
You do not have to tag only the latest commit. First find the commit ID:
git log --oneline
Then tag that specific commit:
git tag -a v0.9.0 a1b2c3d -m "Backfill tag for pre-release"
This is common when teams forget to tag a release at the time it happened.
Pushing Tags to a Remote
Tags do not automatically go to the remote when you push a branch.
Push one tag:
git push origin v1.0.0
Push all tags:
git push origin --tags
If your deployment pipeline uses tags as release triggers, this step is essential.
Deleting Tags
Delete a local tag:
git tag -d v1.0.0
Delete a remote tag:
git push origin --delete v1.0.0
Be careful when removing release tags because other systems or teammates may rely on them.
Checking Out a Tag
You can inspect the repository at a tagged release:
git checkout v1.0.0
This usually places you in detached HEAD state because you are on a commit, not a branch.
If you want to make changes starting from that tag, create a branch:
git switch -c hotfix-from-v1.0.0
Note: Checking out a tag is excellent for reproducing a past release, testing an older version, or debugging a regression.
Release Example
A simple release workflow could look like this:
git switch main
git pull
git tag -a v2.0.0 -m "Release version 2.0.0"
git push origin main
git push origin v2.0.0
Now the code and the release marker are both available remotely.
When to Use Each Tag Type
Use lightweight tags when:
- you need a quick local marker
- the tag is informal or temporary
Use annotated tags when:
- the tag represents a real release
- you want metadata and a message
- the tag will be shared with the team
What You Should Remember
Tags mark important commits. Lightweight tags are simple pointers, while annotated tags carry release-friendly metadata. Tags are not pushed automatically, so remember to send them to the remote when needed. When checking out a tag, be aware of detached HEAD and create a branch if you plan to continue working.
For real release workflows, annotated tags are usually the better choice.
Test Your Understanding
Exercise 1: Picking the right release marker
Scenario: Your team is creating an official v2.0.0 release and wants tag metadata plus a message.
Question: Which kind of tag from the tutorial is the better fit?
Exercise 1: Picking the right release marker
Choose the tag type that stores release-friendly metadata and a message.
Exercise 2: Publishing the release tag
Scenario: You created v2.0.0 locally and your deployment pipeline watches for tags on the remote.
Question: What important step from the lesson must you remember?
Exercise 2: Publishing the release tag
Identify the extra action needed because tags are not pushed automatically with branch pushes.
Exercise 3: Working from a tag
Scenario: You checked out v1.0.0 to investigate an older release and now need to make a hotfix based on that state.
Question: What is the safest next step from the tutorial?
Exercise 3: Working from a tag
Choose the action that avoids staying in detached HEAD when continuing work from a tag.
Frequently Asked Questions
What is the difference between a lightweight and an annotated Git tag?
A lightweight tag is just a name pointing at a commit. Nothing else is stored. An annotated tag is a real Git object with a tagger, a date, a message and optionally a GPG signature. That difference matters in practice: git describe only considers annotated tags by default, and you cannot tell who created a lightweight tag or why. Use annotated tags (git tag -a v1.2.0 -m "...") for anything released, and lightweight tags for private bookmarks.
Why don't my tags appear on GitHub after pushing?
Because git push does not include tags. Push one with git push origin v1.2.0, or all of them with git push origin --tags. If you want annotated tags pushed along with commits automatically, git push --follow-tags sends the annotated tags that are reachable from the commits being pushed, which is usually the behaviour people expect, and is worth setting as a habit for release work.
How do I delete a Git tag locally and remotely?
git tag -d v1.2.0 removes it locally, and git push origin --delete v1.2.0 removes it from the remote. Be careful with released tags: anyone who has already fetched keeps their copy, and if your release tooling or a package registry resolved that tag, deleting it can break builds that referenced it. The safer convention for a bad release is to publish a new tag rather than to remove the old one.
Can I tag a commit from the past?
Yes. Pass the commit hash: git tag -a v1.0.0 9fceb02 -m "Initial release". The tag's own date is when you created it, not the commit's date, which occasionally matters for tooling that sorts by tag date. This is the usual way to add a version tag retrospectively when a project started without them, and git log --oneline gives you the hashes to work from.
What happens when I check out a tag?
You get a detached HEAD, because a tag points at a fixed commit rather than a moving branch. That is fine for inspecting or building a release. If you need to make changes, a hotfix on an old version, create a branch from it: git switch -c hotfix/1.2.1 v1.2.0. Committing while detached produces commits that belong to no branch and become unreachable once you switch away.
How do tags relate to releases and semantic versioning?
A tag is the Git primitive; a "release" on GitHub or GitLab is a layer on top of a tag, adding notes and downloadable artefacts. The convention is a v prefix and semantic versioning, v1.4.2, where the major number changes on a breaking change, the minor on a backwards-compatible feature, and the patch on a fix. Most release automation, including semantic-release, works by reading commits since the last tag and creating the next one, so consistent tagging is what makes the automation possible.