Command Palette

Search for a command to run...

Hectal
PHASE 6Advanced ~14 min· topic 3 of 5

Topic 6.3

Tags & Releases: SemVer, Annotated vs Lightweight

In one line

A tag is a permanent, human-friendly label pointing at one specific commit — genuinely different from a branch because it never moves — and the standard way to mark a real, shippable release.

0/5 · 0%

Think of it like this

A branch is a bookmark that moves forward as you keep reading; a tag is a sticky note marking one specific, permanent page you want to be able to find again instantly, forever, exactly as it was. A tag never moves once created — it points at exactly one commit, permanently.

Key ideas

  1. 01

    git tag v1.0.0 creates a LIGHTWEIGHT tag — just a name pointing directly at your current commit, with no additional metadata at all, functionally similar to a branch that simply never advances. git tag -a v1.0.0 -m "First stable release" creates an ANNOTATED tag instead — a full Git object with its own message, tagger name, and date, genuinely recommended for anything meant to represent a real release.

  2. 02

    SEMANTIC VERSIONING (SemVer) is the near-universal convention for version numbers: MAJOR.MINOR.PATCH (e.g. 2.4.1) — MAJOR increments for breaking changes, MINOR for new, backward-compatible functionality, and PATCH for backward-compatible bug fixes. Following this convention lets anyone depending on your project understand, from the version number alone, roughly how risky an upgrade is likely to be.

  3. 03

    Tags, unlike branches, are NOT pushed to a remote by default — git push <remote> <tagname> pushes one specific tag, and git push <remote> --tags pushes every tag at once. This is a genuinely common early surprise: creating a tag locally and assuming it's automatically visible to collaborators or a hosting platform's 'Releases' page, when it actually needs its own explicit push.

  4. 04

    git checkout <tagname> lets you inspect a project's exact state at that specific tagged release — genuinely useful for reproducing a bug reported against a specific old version, or comparing behavior between two release points, without any ambiguity about exactly which commit you're looking at.

  5. 05

    GitHub/GitLab RELEASES are a platform feature built directly on top of Git tags — creating a 'Release' on the platform is typically just attaching release notes, and sometimes compiled binary artifacts, to an underlying tag. The tag itself is the real, portable, core-Git concept; the platform's release page is a convenience layer on top of it.

Code & diagrams

tags-and-releases.shmarkdown

Annotated tags, SemVer, and the push step people forget.

cd ~/scratch/my-first-repo

# A lightweight tag — just a name, no extra metadata
git tag v0.1.0-lightweight

# An annotated tag — the recommended form for real releases
git tag -a v1.0.0 -m "First stable release"

# See the difference
git show v0.1.0-lightweight   # shows the commit directly
git show v1.0.0               # shows the TAG object first: message, tagger, date — then the commit

# List every tag
git tag

# Tags are NOT pushed automatically — this is easy to forget
git push origin v1.0.0
# or, to push every tag at once:
git push origin --tags

# Inspect the exact state of a specific released version
git checkout v1.0.0
# (detached HEAD — you're viewing history, not on a branch; git switch back to a branch when done)
git switch main

# Delete a tag if it was created by mistake
git tag -d v0.1.0-lightweight              # locally
git push origin --delete v0.1.0-lightweight # and on the remote, if it was pushed

Explain it without notes

01

What's the practical difference between a lightweight tag and an annotated tag, and which should you use for a real release?

02

You created a tag locally and told a teammate to pull it, but they can't find it. What's the most likely explanation?

Practice

01

Create both a lightweight and an annotated tag on the same commit, then use git show on each to see the concrete difference in what information is displayed.

02

Create a tag, confirm with git tag that it exists locally, then push it explicitly and confirm (via a second clone, or a hosting platform's UI) that it's now visible remotely.

Trade-offs

  • ↔

    Lightweight tags are quick and require no extra thought, which is fine for personal, throwaway markers — but for anything representing a real, shippable release that others depend on, the small extra step of an annotated tag (a real message, a real author record) is worth it for the same reason a real commit message is worth it: it's a permanent record future-you (or a teammate) will be genuinely glad exists.

Done when you can

  • I can create both lightweight and annotated tags and explain the difference.

  • I understand Semantic Versioning's MAJOR.MINOR.PATCH convention.

  • I know tags must be explicitly pushed and aren't shared automatically like regular commits.