Tags are permanent names for commits — the markers that turn "the commit we shipped in September" into v1.4.0. Releases, hotfix bases, and every "which version is live?" question ride on them, and creating one well-formed tag is a two-command habit.

Lightweight vs annotated #

Both kinds, and why annotated wins
$ git tag v1.4.0-lite                      # lightweight: just a pointer
$ git tag -a v1.4.0 -m "First stable journal release"
$ git show v1.4.0
tag v1.4.0
Tagger: Aospix Team <team@aospix.com>
Date:   Tue Oct 20 2026

First stable journal release

A lightweight tag is a bare pointer — fine for private bookmarks. An annotated tag is a real object with author, date, and message, which is what releases deserve: it shows up in git show, carries GPG signatures if you add -s, and survives tooling that expects metadata. See creating releases context in git tag and releases.

The everyday commands #

List, show, tag the past, verify
$ git tag                        # all tags, alphabetical
$ git tag -l "v1.4*"             # filtered
$ git tag -a v1.3.1 f3e2d1c -m "point release"   # tag an old commit
$ git show v1.4.0 --stat         # what the tagged commit changed

Tags do not travel with git push by default — the classic surprise:

Sending tags to the remote
$ git push origin v1.4.0         # one tag
$ git push --tags                # all local tags
$ git fetch --tags               # bring them down elsewhere

Versions worth tagging #

Semantic versioning is the convention that makes tags meaningful: vMAJOR.MINOR.PATCH — breaking, feature, fix. The habit that matters is tagging the exact commit that shipped: deploys verify against git describe --tags, and bug reports arrive attached to a version instead of a shrug:

Describe any build by its nearest tag
$ git describe --tags
v1.4.0-3-g9a8b7c      # 3 commits after v1.4.0, at 9a8b7c
Tag patternPurpose
v1.4.0Release
v1.4.1Point release / hotfix
v2.0.0-rc.1Release candidate
laptop-2026-10-21Non-version markers (machines, snapshots)

Deleting and moving #

Removal on both ends
$ git tag -d v1.4.0-lite                  # local
$ git push origin :refs/tags/v1.4.0-lite  # remote

Tags are meant to be permanent — moving one (delete, re-tag, force-push) breaks everyone's git describe and package checks. If a release was wrong, release v1.4.1; the history of versions is the point.

The commits between tags are log territory; the branching that precedes a release is branch basics. The Git series continues.