A tag is a branch that does not move
A branch is expected to move; a tag is expected never to. That is the entire difference, and it is why releases are tagged and features are branched.
Use annotated tags for releases: they are real objects, they record who tagged and when, and they can be signed. Lightweight tags are fine for a private bookmark.
git tag v1.0.0 # lightweight: a name for a commit
git tag -a v1.0.0 -m "First release" # annotated: an object with an author, a date, a message
git tag # list
git tag -l "v1.*"
git show v1.0.0
git tag -d v1.0.0 # delete locally
Tags are not pushed by accident
git push origin v1.0.0 # one tag
git push --tags # all of them
git push --follow-tags # commits, plus annotated tags pointing into what you pushed
git push origin :refs/tags/v1.0.0 # delete it on the server
Somebody has already built from v1.0.0. If you re-tag a different commit, two machines with the same tag now have different code, and only one of them is wrong — in ways that take a day to find. Ship v1.0.1 instead.
Versions that carry information
Semantic versioning is a promise to the people depending on you: the number tells them whether they can upgrade without reading anything. It is only worth using if you keep the promise — a "patch" that breaks an API is worse than no scheme at all.
| Change | Bump | Example |
|---|---|---|
| Breaking change | major | 2.4.1 → 3.0.0 |
| New feature, still compatible | minor | 2.4.1 → 2.5.0 |
| Fix only | patch | 2.4.1 → 2.4.2 |
| Not ready yet | pre-release | 3.0.0-rc.1 |
Describing where you are
That string goes into the footer of an application and turns "it is broken" into an exact commit. git describe --tags --dirty adds a marker when the build had uncommitted changes, which is a bug report all by itself.
$ git describe --tags
v1.2.0-14-g832dbe3
# the last tag, how many commits since, and the commit id
What a release actually is
A tag says which commit. The release is the process around it: a changelog people can read, artefacts built from that exact commit, and a note of what to do if it has to be rolled back. Platforms hang all of that off the tag — GitHub Releases, GitLab Releases — which is why the tag has to be pushed before any of it exists.