Tagging Releases

Reviewed & published by Brayan K

When you ship a version, you want a permanent, memorable marker for that exact commit. Tags do precisely that. By the end of this lesson you'll create lightweight and annotated tags, push them, delete them, and version your releases with semantic versioning.

Part of the free Git course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

1️⃣ Lightweight vs Annotated Tags

A tag is a fixed name for one commit; it doesn't move when you commit again. A lightweight tag (git tag v1.0.0) is just that name. An annotated tag (git tag -a v1.1.0 -m "...") is a full object storing who tagged it, when, and why — the recommended choice for real releases, and the only kind that can be signed.

# A tag is a fixed name for one specific commit — usually a release.
# Unlike a branch, a tag does NOT move when you make new commits.

# LIGHTWEIGHT tag — just a name pointing at the current commit
git tag v1.0.0

# ANNOTATED tag — a full object with tagger, date, and a message.
# Recommended for real releases (and required to be signed).
git tag -a v1.1.0 -m "Release 1.1.0 — adds dark mode"

# Tag an OLDER commit by giving its hash
git tag -a v0.9.0 9z8y7x6 -m "Beta release"

2️⃣ Listing & Inspecting Tags

git tag lists every tag, and git tag -l "v1.*" filters by pattern. git show <tag> reveals what it points to — for an annotated tag you also see the tagger, date, and message; a lightweight tag just shows its commit.

# List and inspect your tags.

# List all tags (alphabetical/version order)
git tag

# Filter with a pattern
git tag -l "v1.*"

# Show what a tag points to. For an ANNOTATED tag you also see the
# tagger, date, and message; a lightweight tag just shows the commit.
git show v1.1.0

3️⃣ Pushing & Deleting Tags

Here's the catch that surprises everyone: a normal git push does not send tags. Push one with git push origin v1.1.0, or all of them with git push --tags. Delete a tag locally with git tag -d, and remove it from the remote with git push origin --delete.

# ⚠️ Tags are NOT pushed by a normal git push. You must send them.

# Push one specific tag
git push origin v1.1.0

# Push ALL your local tags at once
git push --tags

# Delete a tag locally...
git tag -d v0.9.0

# ...and delete it on the remote too (note the colon / --delete form)
git push origin --delete v0.9.0

4️⃣ Semantic Versioning

Tags are most useful when their names mean something. Semantic versioning uses MAJOR.MINOR.PATCH: bump MAJOR for breaking changes, MINOR for new backward-compatible features, and PATCH for backward-compatible bug fixes. A glance at v2.3.1 tells users how risky an upgrade is.

Your turn. Cut an annotated release tag and publish it. Fill in the three blanks.

# 🎯 YOUR TURN — replace each ___ then run it in your terminal.
# Goal: cut and publish a release tag.

# 1) Create an ANNOTATED tag for version 1.0.0 with a message
git tag ___ v1.0.0 -m "First release"   # 👉 the flag that makes it annotated

# 2) Confirm it exists
git ___                                  # 👉 the command that lists tags

# 3) Publish it to the remote (tags don't go with a normal push)
git push origin ___                      # 👉 the tag name to push

# ✅ Expected: step 1 is quiet, step 2 lists v1.0.0, step 3 reports
#    "* [new tag] v1.0.0 -> v1.0.0".

Common Errors (and the fix)

Pro Tips

📋 Quick Reference

CommandPurpose
git tag v1.0.0Create a lightweight tag
git tag -a v1.0.0 -m "msg"Create an annotated tag
git tagList all tags
git show v1.0.0Inspect a tag and its commit
git push origin v1.0.0Push one tag
git push --tagsPush all tags
git tag -d v1.0.0Delete a tag locally

Mini-Challenge: Version a Project

No commands given this time — just the plan. Walk a tiny project through four releases using correct semver tags.

# 🎯 MINI-CHALLENGE: version a small project with semver.
# No commands given — just the plan. Run each step in your terminal.
#
# 1. Make a commit and tag it v1.0.0 (annotated) — your first release
# 2. Add a backward-compatible feature, commit, and tag the right version
# 3. Fix a bug, commit, and tag the right PATCH version
# 4. Make a breaking change, commit, and tag the right MAJOR version
# 5. Run "git tag" and confirm: v1.0.0, v1.1.0, v1.1.1, v2.0.0
#
# ✅ Expected: four tags following MAJOR.MINOR.PATCH correctly.

# your commands here

🎉 Lesson Complete!

Practice quiz

What is a Git tag?

  • A movable branch label
  • A commit message
  • A fixed, named pointer to a specific commit
  • A remote URL

Answer: A fixed, named pointer to a specific commit. A tag marks one specific commit with a memorable name, typically for releases.

How does a tag differ from a branch?

  • A branch moves forward as you commit; a tag stays pinned to one commit
  • Tags move with new commits; branches don't
  • They are identical
  • Tags can't be pushed

Answer: A branch moves forward as you commit; a tag stays pinned to one commit. Branches advance with each commit, while a tag stays fixed on the commit it marks.

Which command creates a LIGHTWEIGHT tag?

  • git tag -a v1.0.0
  • git tag --light v1.0.0
  • git branch v1.0.0
  • git tag v1.0.0

Answer: git tag v1.0.0. git tag <name> with no -a creates a lightweight tag — just a name pointing at a commit.

Which creates an ANNOTATED tag?

  • git tag v1.0.0
  • git tag -a v1.0.0 -m "message"
  • git tag --quick v1.0.0
  • git commit --tag

Answer: git tag -a v1.0.0 -m "message". git tag -a creates an annotated tag, a full object with tagger, date, and message.

What extra information does an annotated tag store?

  • Tagger name, date, and a message
  • Nothing extra
  • The whole repo
  • A branch list

Answer: Tagger name, date, and a message. Annotated tags are real objects holding the tagger, a timestamp, and a message.

Why are annotated tags recommended for releases?

  • They're smaller
  • They move automatically
  • They carry metadata (who/when/why) and can be signed
  • They skip the staging area

Answer: They carry metadata (who/when/why) and can be signed. Annotated tags record who tagged, when, and why, which matters for real releases.

By default, does `git push` send your tags to the remote?

  • Yes, automatically
  • No — tags must be pushed explicitly
  • Only annotated tags
  • Only on the first push

Answer: No — tags must be pushed explicitly. Tags aren't pushed by default; use git push origin <tag> or git push --tags.

Which command pushes ALL your local tags?

  • git push
  • git tag --push
  • git send-tags
  • git push --tags

Answer: git push --tags. git push --tags uploads every local tag to the remote.

In semantic versioning v2.3.1, the '3' is the...

  • MAJOR version
  • MINOR version
  • PATCH version
  • Build number

Answer: MINOR version. In MAJOR.MINOR.PATCH, the middle number is the MINOR version, bumped for backward-compatible features.

Which command deletes a local tag?

  • git tag -r v1.0.0
  • git untag v1.0.0
  • git tag -d v1.0.0
  • git rm v1.0.0

Answer: git tag -d v1.0.0. git tag -d <name> deletes a tag locally.

Continue this course

Frequently asked questions

What's the difference between a tag and a branch?

A branch is a movable label that advances every time you commit — it tracks an ongoing line of work. A tag is a fixed pointer to one specific commit and never moves on its own, which is exactly what you want for marking a release like v1.0.0. You commit on branches; you tag milestones.

Should I use a lightweight or an annotated tag?

Use annotated tags (git tag -a) for anything that matters, especially releases. An annotated tag is a full Git object storing the tagger's name, the date, and a message, and it can be GPG-signed. A lightweight tag (git tag <name>) is just a bare name pointing at a commit, with no metadata — fine for a quick private bookmark, but not for shared releases.

Why didn't my tags show up on GitHub after pushing?

Because a normal git push does not send tags — only commits on branches. You have to push tags explicitly: git push origin <tagname> for one tag, or git push --tags to send all of them. This is a very common surprise: your release tag exists locally but the remote never received it until you push it.

What is semantic versioning?

Semantic versioning (semver) is the MAJOR.MINOR.PATCH convention. You bump MAJOR for breaking changes, MINOR for new backward-compatible features, and PATCH for backward-compatible bug fixes. So v1.4.2 means major 1, minor 4, patch 2. Tagging releases with semver tells users at a glance whether an upgrade is risky (major) or safe (patch).

How do I delete or move a tag?

Delete a tag locally with git tag -d <name>, and remove it from the remote with git push origin --delete <name>. Tags are meant to be immutable, so 'moving' one is really delete-and-recreate — and if it was already pushed and others rely on it, retag with a new version instead. Rewriting a published tag confuses anyone who already fetched it.

Related lessons