A tag names a specific commit, usually a release. Unlike a branch, a tag does not move, so it is a stable reference to what shipped. Annotated tags also carry a message, author and date, which lightweight tags do not.
Before you start
You should be comfortable with commits and pushes. This article covers creating, pushing and using tags.
Step-by-step walkthrough
Step 1: Prefer annotated tags
git tag -a v1.2.3 -m "Release 1.2.3" creates an annotated tag with metadata, which is what release tooling expects and what can be verified. A lightweight tag is just a ref, with no message or author, so it carries less information.
Step 2: Push tags explicitly
git push does not push tags by default, so you must run git push origin v1.2.3 or git push --tags. A tag that exists only locally is invisible to everyone else, which is a common “the release is missing” cause.
Step 3: Keep tags immutable
A tag identifies what was released, so moving or reusing it breaks anyone who depended on that version and undermines reproducibility. If a release is wrong, cut a new version rather than deleting and re-tagging, and document the reason.
Worked scenario
The release is tagged and the tag pushed.
git tag -a v1.2.3 -m "Release 1.2.3"
git push origin v1.2.3
git ls-remote --tags origin | grep v1.2.3 # confirm it is on the remoteWalk through the example
The annotated tag records who tagged it and why. Pushing the tag makes it available to others, and ls-remote confirms it landed. Build tools can then check out the exact commit for a reproducible release.
Common mistake
Forgetting to push tags, so the release exists only locally. Another is deleting and re-creating a tag to fix a mistake, which silently changes what a version means for anyone who already fetched it.
Verify the behavior
Create a tag, push it, and confirm it appears on the remote with ls-remote. Check out the tag and confirm it points at the intended commit. Try to push another commit and confirm the tag does not move.
Interview exercise
Why use an annotated tag instead of a lightweight one for a release?
Answer and reasoning
An annotated tag stores a message, the tagger and a date, and can be signed and verified, so it captures who released what and when. It is a full object, not just a ref, which release and package tooling can rely on. A lightweight tag has none of that context.
Continue learning
Compare versioning in Release versioning and delivery in Build once, promote. Read the Git tagging documentation and try the Git interview questions.