2014-05-14

Tagged releases using git flow

I’ve used git flow for most of my software projects — specifically for those that have versioned releases. The original post describing git flow is still the best overview of how it works. In short, you have a master branch where every commit is a merge commit. Each of these merge commits represents a new release, and is tagged with the version number of that release. The merge brings in all of the subsidiary commits and feature branches that make up that release. Ongoing work happens on a separate develop branch. This is where you merge in completed new features and bug fixes on a day-to-day basis. develop should always be a stable version of the software — you don’t merge a feature branch into develop until it passes all of your tests and is “complete” with regards to the feature you’re trying to implement.

My favorite part of this model is how each release is just some tagged commit on the master branch. You want to see the code for the latest released version? That’s easy — git checkout master. You want version 1.2.5 specifically? Use git checkout 1.2.5 instead.

Unfortunately, the git flow tool has implemented a slightly different behavior for awhile now. That patch makes git flow tag the last commit on the release branch, instead of the merge commit on the master branch. The reasons for this might be perfectly valid, but it’s not what I want, and it’s not what the original git flow post described. That means that I can’t use git flow release finish as-is.


To recap the usual process:

$ git flow release start ${VERSION}
[ bump version numbers and release dates if needed ]
$ git flow release finish -s -m ${PROJECT}-${VERSION} ${VERSION}

The first command creates a new release branch called release/${VERSION}. If you need to make any changes that bump version numbers or release dates in the actual files in your repository, you do that on this new release branch. You then finalize the release, which merges the release branch (along with any new commits on develop) into the master branch. It also creates a tag named ${VERSION}, and because of the -s option, signs it with my GPG key.

The problem is that this tag is placed on the wrong commit. That’s easy to fix, though:

$ git tag -sf -m ${PROJECT}-${VERSION} ${VERSION} master

I also like to create a -dev version tag on the latest develop branch, so that git describe always gives me a nice looking version number, regardless of which branch I’m on:

$ git tag -s -m ${PROJECT}-${VERSION}-dev ${VERSION}-dev develop

And that’s it!