Using Tags to track releases with Git

We build professional apps for Android, iOS and mobile web.
Have a look β†’

Introduction

Too often we at jtribe found ourselves examining codebases that had grown to the point of unwieldiness. We'd be revisiting a project, and would often spend some time figuring out precisely where to begin.. again. 😭

Enter tagging with Git. This is something that has saved us eons of time, and is truly an invaluable tool to assist developers in releasing projects to the world.


TL;DR? Gurrrl you lazy!

Tags are awesome and help you track milestones in a project.

  • Always tag on external client releases and major internal milestones
    • You tag so you can easily revisit milestone builds in the future for examination purposes
    • See "Creating a version in Github" below on how to do it, and read the relevant sections below anyway πŸ˜‚.
    • Did you really think I'd tell you everything you needed to know in here?

A Brief History of Tagging

Git has the ability to tag specific points in πŸ• as being important. This is just like important occasions in real-life, such as Birthdays and Anniversaries.

  • This feature is typically used to mark release points of a project (1.0 and so on).
  • Often you'll want to list the tags of a project. This is rather handy when the codebase feels like some horribly frightening dungeon boss you're woefully ill-equipped to combat. To do this, simply type git tag and bob's your uncle. An example of the resulting output can be found below:
$ git tag
v0.1  
v0.2  
v0.3.rc0  

The above command lists all available items in your inventory tags in alphabetical order.

  • The order in which the items appear is unimportant, but for OCD-purposes, try to keep them named v0.1 and so on. This will eliminate confusion later when coming back to the project.
    • Note: If you don't want a prefix of v, don't use it. It's redundant and not strictly required in any sense of the word.
  • It is also recommended on many forums to give milestone releases a pseudonym, e.g. v1.7.0-Fujisan. That way instead of remembering the specific version number, if you're told to fix a bug in build Fujisan you know which version range you're looking for.
    • Note: If you don't want suffixes on your tags, you don't need them. It's up to the individual.
  • Having mentioned that, if you're only interested in the -Fujisan range of builds for example, the git tag command can help you list these too. Simply run git tag -l "-Fujisan" to retrieve a subset of results. An example of the output can be found below:
$ git tag -l "-Fujisan"
v1.7.0-Fujisan  
v1.7.1-Fujisan  
v1.7.2-Fujisan-rc0  
v1.7.3-Fujisan  

Note: We discuss checking out individual tags further below.


On the creation of Tags

Git supports two kinds of tags: lightweight and annotated.

  • A lightweight tag is like a branch that never changes - it is literally just a pointer to a specific commit.
  • Annotated tags are different. They are stored as full objects in the Git database.
  • They have a checksum, and they contain the tagger's name, email and date of tag creation. They also have a tagging message, just like an individual commit does.

It is strongly recommended by forum users everywhere and Github themselves to create annotated tags for these very reasons.

To create a tag, simply run the following git tag -a vX.X -m "my awesome app version X.X"

  • If you don't supply a -m message, git will open vim (or your other, inferior editor) for you, so you can type one in. πŸ‘
  • Let's face it, commits and tags without messages are simply barbaric.
  • You can see the data for a specific tag by running git show vX.X.

‼️ Only annotated tags have the metadata features. So take caution. ‼️


Tagging at a later date

Suppose your commit history looks like this:

$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'master' into current branch  
0d52aaab4479697da7686c15f77a3d64d9165190 adding the thing  
8a5cbc430f1a9c3d00faaeffd07798508422908a updating Readme  
1543261gvdschafbdsg154513w2343512tfgsjal removing unused methods  

If you forgot that you were supposed to tag a release or milestone version at updating Readme, then you can just add it in later. Get the commit and run the following command: git tag -a vX.X 9efrt01 where 9efrt01 is the commit identifier. This will add the tag to the project right where you want it. πŸ’₯


Ahh, push it. Push it real good! 🎺

By default, our trusty git push command doesn't push tags to the remote. 😭

  • You'll need to push your individual tag as follows: git push origin [tagname]. You can use your existing alias for this, if you have one.
  • If you have multiple tags you want to push, and don't want to keep typing that command for the sake of your nerves, you can run git push origin --tags to transfer all tags to the remote that aren't already there.
  • That said, it's my personal recommendation that you make a new alias to push tags, and make it part of your workflow. gpt should suffice for this.

Having done one (or both) of the above, when somebody pulls from the repo they'll get the tags as well. Yaaaaay! πŸŽ‰


Gretchen, stop trying to make fetch happen!

You can't really checkout or fetch a specific tag. Boo!

  • You can checkout a branch and give it a specific tag for examination only as follows: git checkout -b [branchname] [tagname]. Key versions should never be modified once they are released. You will want to create a new branch off master as per normal if you wish to make changes.

    • Edit: I've been told you can in fact checkout a tag. But it will be a detached HEAD and a pointer to a specific commit. I would still personally discourage anyone from doing this unless you know what you're doing with Git.

Majors, Minors and Patches! Oh my!

It's generally recommended to make your version numbers as follows: MAJOR.MINOR.PATCH

  • MAJOR: When you make large changes to the software in a non backwards compatible fashion.
  • MINOR: When you add some functionality, but the software is still backwards compatible.
  • PATCH: When you fix bugs in a backwards compatible manner.

Further extensions are allowed for Pre Release builds (pre) and Release Candidate builds (rcX)

  • Note that MAJOR, MINOR and PATCH should always increase numerically by 1 to avoid confusion. If you feel a burning desire to skip v9.0 and go straight to v10.0, please make sure it's well documented with a damn good reason. This is of course so any new people on the project don't lose their minds at the sheer illogicality of it all.

Creating a version in Github

Right, now we've got all of that waffle out of the way. We're onto the equally thrilling version creation process!

  • On Github, navigate to the repository's main page.

  • Under your repository name, click Releases.

  • Click Draft a new release.

  • Type a version number based on the vMAJOR.MINOR.PATCH format, as discussed above.

  • Select a branch that that contains the content you wish to release - this will usually be master, unless you're releasing a beta build.

  • Give a title and description that details the release.

  • If you wish to include compiled binaries, you can add them in the drag-and-drop box.

  • If the release is unstable, make absolutely sure you check the appropriate box.

  • Once you're ready to publicise the release, click Publish Release. Otherwise, hit Save Draft so you can come back to it later.


Give me specifics, dammit!

You can share each and every release you create on Github with a unique URL.

  • Under your repository name, on the main page of the repository, click Releases.
  • Find the version you want a link to, and on the left side of the page click the version number.

You can also dynamically link to the latest version with a unique URL.

  • Under your repository name, on the main page of the repository, click Releases.
  • Right click on Latest Release and copy the URL to share it. The suffix of this URL is always /releases/latest.

Fin, δ»•δΈŠ, Finish

A staggeringly vast amount of research was put behind this brilliantly witty piece of prose, so I hope I've explained everything in a blatantly obvious sort of way.
However, if you have any issues with any of the above, feel free to @cocotutch or @jtribeapps on Twitter and we'll be happy to point you in the right direction. πŸ˜€


FAQs (pronunciation: Facks)

  • Do you need more convincing on the usage of Semantic Versioning?
  • "Gretchen, stop trying to make fetch happen!" -- Regina George, Mean Girls.
    • That movie is probably the most quotable one I know.
  • "A Brief History of Tagging" was inspired by the Stephen Hawking book called "A Brief History of Time."
    • It's a rather delightful read, that I'm more than happy to recommend.
  • "Majors, Minors and Patches! Oh my!" is inspired by a quote from The Wonderful Wizard of Oz, which happens to be one of my all-time favourite books and movies.
  • δ»•δΈŠ is Japanese for "Finish" and is pronounced "Shi-ah-ge." Fin is French for Finish (the alliteration, my god), and is pronounced exactly as it appears it should be.
  • "Ahh, push it. Push it real good" -- Salt n Pepa, "Push It"