Advanced

Framing the moment you are proud of

Tags are how git takes a photo of a commit and puts it on the wall. I created one the day a release shipped and never had to hunt for its hash again.

What you will see

To https://github.com/You/repo.git * [new tag] v1.0 * [new tag] v2.0

About 2 min of reading

Try It

Pin a human-readable name to a commit and share that pin with the remote. I tagged the day a release shipped so nobody ever had to hunt for its hash again.

1

Commit something and create an annotated tag on it. The tag name points at that exact commit and stores a message with it.

printf 'v1\n' > app.py git add app.py git commit -m initial git tag -a v1.0 -m "First release" git tag

Before you run it, say out loud what it will print. Then open the answer.

What it prints
v1.0
`git tag` with no arguments lists every tag in your repo. An annotated tag remembers who, when, and why through `git tag -a` plus a message.
2

Add a lightweight tag, which is just a name with no metadata. Both names now show in the list, each pointing at a commit.

git tag v2.0 git tag

Before you run it, say out loud what it will print. Then open the answer.

What it prints
v1.0 v2.0
`v2.0` is lightweight, no message, tagger, or date stored. Reach for `git tag -a` when you are sharing a version with other people.
3

Push the tags to the remote. Tags are not sent by a normal push; you have to ask for them explicitly with --tags.

git push origin --tags

Before you run it, say out loud what it will print. Then open the answer.

What it prints
To https://github.com/You/repo.git * [new tag] v1.0 * [new tag] v2.0
If you forget `--tags`, the tags never leave your machine and teammates will wonder why they cannot see the release you just marked.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

A tag pins a commit, and pushing shares that pin with the remote so everyone can find it.
1 Create a tag on a commit
↓
2 Store the tag message with it
↓
3 Push tags to the remote
↓
4 Users checkout the tag name
↓
5 They land on the same commit
Why this works
A tag does not move

Unlike a branch, a tag points at one commit forever:

git tag v1.0 <hash>

That immovability is the whole point. A branch moves forward as you commit; a tag stays put so it always names the same snapshot. That is why releases can trust v1.0 to mean the same thing next year.

When you have a choice

Which tag to reach for

TypeStores metadata
AnnotatedYes, full message and tagger info
LightweightNo, just a hash

Annotated tags win for releases because they record who created them and why. A lightweight tag has its place for scratch marks you only use yourself.

Examples

Mark a release point

git tag -a v1.0 -m "First release"

An annotated tag pins a name to a specific commit and stores a message with it. After this, v1.0 is a permanent, human-sized handle for a commit that otherwise looks like a wall of hexadecimal. That is how you tell people which point in history you shipped.

Send the tags along

git push origin --tags

Tags are not sent with a normal push, git treats them as separate. --tags carries every tag to the remote so other people can find the release. Missing this once, and I spent minutes wondering why the team could not see the version I had just marked.

Two kinds of tag

git tag v2.0          # lightweight pointer
git tag -a v3.0 -m "x"  # annotated with metadata

A lightweight tag is just a name pointing at a commit. An annotated tag stores the tagger's name, email, date, and message. For anything you share with the world, annotated is the better default because it carries the story of when and by whom it was marked.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Cleaning up the mess before you share it
Previous Lesson
Cleaning up the mess before you share it
Next Lesson
Many checkouts, one repo
Many checkouts, one repo →