Proper use of Git tags
Posted May 23, 2022 ‐ 3 min read
In the Linux kernel project, the first Git-managed project in existence, due to
its proper use of Git tags, the revision v4.11-rc7-87-g28cf22d0ba28
is
equivalent to 28cf22d0ba28
. This is due to existence of the annotated
v4.11-rc7
tag for an ancestor commit.
The nicer string above is the output of git describe 28cf22d0ba28
. The git describe
command can relate any commit to tags in the history. Any command
that accepts the Git hash behaves the same when the output of git describe
is
passed instead. It works in the following way: when Git is presented with
[anystring]-g[hash]
, it throws away the [anystring]-g
prefix and treats the
[hash]
part as the desired commit to resolve.
Git tags let us prettify any Git hash with the software version from which it is derived. However in many projects Git tags are often not used to their full potential in the best case, and in the worst case they are being misused.
In this post I provide bunch of recommendations to assist in achieving the nicety that is obtainable from Git tags in any project.
Tag push permissions
A common pitfall is to let any developer push Git tags. The following scenario happened to me in more than one company:
- Someone pushed a
test
tag. - Someone else created
test
subdir in the project's root.
Now, git log test
is an ambiguous command that does not know what to do.
Should it show the commits starting from the commit pointed by test
, or the
commits from HEAD
that modified that test
directory? Or maybe the developer
has a local test
branch? Headache.
If possible, configure the Git server to accept tag pushes only from release managers.
Tag naming
Tags are unique and live forever in the repo.
Pick good tag names that do not cause ambiguity with your branch name convention.
A nice convention is the following: to mark versions, start with v
. That way,
shell completion works nicely upon trying to complete v
. If you drop the v
and instead go with the version number immediately .e.g 1.
, shell completion
will struggle to show completions between tags starting with 1
and all
commits whose git hashes start with 1
.
Only used annotated tags, not lightweight tags
By default git tag
creates lightweight tags (non-annotated tags). Do pass
the -a
switch to create annotated tags. This way, meta-data from the creation
of the tag is registered just like with commits. Also, git describe
would
work out of the box and won't need the --tags
flag that is needed to force it
to consider lightweight tags too.
Don't rely on tags alone for versioning
Git tags are just complementary information to Git, they are not the source itself. Use both Git tags and a source tree file to tell the version of the code. This is usually the version string in the package manager manifest of your ecosystem of choice. But how to do that properly? i.e. which commits should be tagged? This takes us to the next recommendation —
The commit that changed the version in source is the one to be tagged
By convention, the commit that changed the version in the source is the one
that should be tagged, not the commit that merged it into the main branch. This
way, git describe
shows the expected result.