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.

Further resources

Share this post
Follow author