Lesson 17 of 30
A branch moves. A tag doesn't — it's a permanent name for one exact commit, which is exactly what a version number needs to be.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A tag is a fixed pointer to one commit. Unlike a branch, a tag never moves — once v2.4.0 points at a commit, it points there forever (unless you force it to move, which you shouldn't). That permanence is the whole point: a version number needs to mean the same thing today and in five years.
Git has two kinds of tags. A lightweight tag is just a name pointing at a commit — nothing more. An annotated tag is a full object in Git's database: it has its own message, author, timestamp, and can be GPG-signed. For anything you'd call a release, use annotated.
You've merged the commits for 2.4.0 into main and you're ready to cut a release:
git tag -a v2.4.0 -m "Release 2.4.0: pagination fix, new auth flow"
-a makes it annotated; -m gives it a message, same as a commit. Check what you made:
$ git show v2.4.0
tag v2.4.0
Tagger: Adesh Shukla <adesh@example.com>
Date: Wed Sep 9 14:02:11 2026 +0530
Release 2.4.0: pagination fix, new auth flow
commit f9e8d7c6b5a4938271605f4e3d2c1b0a9f8e7d6c
Author: Adesh Shukla <adesh@example.com>
Date: Wed Sep 9 13:58:44 2026 +0530
fix: correct pagination offset on last page
Notice it's a real object with its own tagger and message, sitting on top of the commit it points to. A lightweight tag (git tag v2.4.0-quick, no -a) would just be a name — git show on it shows the commit directly, no tag metadata at all.
Tags don't push by default — you have to say so explicitly:
git push origin v2.4.0
# or, to push every tag you have locally:
git push origin --tags
On GitHub, push a tag and you can turn it into a Release: a tag plus release notes, plus optionally attached binaries (a built artifact, a changelog file). The tag is the git-level object; the Release is GitHub's layer on top of it, tying that exact commit to a human-facing changelog and download page.
git checkout v1.0 finds the commit either way — but they carry no metadata of their own. For anything a person outside your terminal will see (a release, a deploy marker), annotated is the right default.git push. This trips people up constantly: they tag locally, push commits, and then wonder why the tag isn't on GitHub. You need git push origin <tagname> or --tags explicitly.git tag -f v2.4.0 <newcommit> will force it to point elsewhere, but if anyone already pulled the old v2.4.0, they now have a different commit under the same name than you do. If a tag is wrong, cut v2.4.1 — don't rewrite what a released version number means.Every other pointer in Git — a branch, HEAD — is designed to move as you work. A tag is the deliberate exception, and that's what connects it to the idea of the three trees: Git already has a mechanism for "a fixed reference to a specific snapshot," and a tag is just that mechanism given a permanent, human-readable name instead of a raw commit hash.