At Innovation Factory we offer our clients two solutions for hosting our Innovation Suite applications: we can host it for them as a software-as-a-service solution or they can host it on premises, i.e. in their own IT environment. This means that we have several deployments of our suite that we need to maintain. In this article we show how we use Git branches and tags for this purpose.
Development with story branches
Every new feature and bugfix originates from a story in the Pivotal Tracker. The work that is done for these stories is committed to the master branch. This branch should be stable at all times; no tests should fail when you run the test suite in master. For this reason it is usually a good idea to work on a story in a separate branch and merge this branch back into master when the story is ready for acceptance.
Such a story branch has a name that briefly describes the story. This name is namespaced with ’stories’ and the initials of the developer who created it. For example, when Kyle Broflovski adds an exception handling mechanism to our application, he can do this in a branch called ’stories/KB/add-exception-handling’.
git checkout -b stories/KB/add-exception-handling

The master branch of our example application

Creating a story branch for adding an exception handling mechanism

Building the exception handling mechanism in its own story branch
Kyle then becomes the ‘owner’ of the branch. This means that other people may also work in this branch, but Kyle is the one who is responsible for deleting it once it is merged into master. In other words: if you create a story branch, you’ll also have to destroy it when it is no longer in use.
git checkout master
git merge stories/KB/add-exception-handling
git branch -d stories/KB/add-exception-handling

Merging the story branch into master

Removing the story branch
If somewhere along the line you have pushed the branch to origin, make sure to delete it there too.
git push origin :stories/KB/add-exception-handling
The master branch is regularly deployed to our acceptance server, where the product owners can test the stories and either accept or reject them.
Releases and deployments
After a while we have made enough changes to our applications to do a new release. We record the release history in Git by tagging the last commit that is part of the release.
git tag kenny

Creating a new release tag ‘Kenny’
The tag is a release name that all developers agree on. It is not a version number, because a name is easier to remember and talk about during development. However, externally we could use version numbers for our releases. So a release that is known as ‘Kenny’ by the dev team might be known as release 1.0 by our clients.
Ideally we would immediately upgrade all the deployments to the newest release. In practice this is not always possible, for example because we don’t have direct access to an on-premises deployment. This means that we not only have to keep track of which releases exist, but also of which deployment is currently on which release. For this purpose we give every deployment its own branch namespaced with ‘deployments’ (why we use branches and not tags here will become apparent in the next section).
Let’s assume that we have two deployments of our software: one is our SAAS install and one is an install for client Amazing-co. We then create two deployment branches, named ‘deployments/saas’ and ‘deployments/amazing-co’, respectively.
git checkout -b deployments/saas
git checkout -b deployments/amazing-co

Creating deployment branches for the SAAS and Amazing-co deployments
When a deployment is on a certain release, both the deployment branch and the release tag will point to the same commit. That is, if no hotfixes have been applied…
Hotfixes
Sometimes a bugfix is so important that we cannot wait for the next release to roll it out to the various deployments. But we don’t want to do an intermediate release which contains all kinds of new and perhaps untested features just to apply one hotfix. Instead, we use separate hotfix branches for our releases. Once we do a release we not only create a tag, but also a corresponding hotfix branch. This branch has the same release name, but namespaced with ‘releases’. Thus, for a release named ‘kenny’ the hotfix branch is called ‘releases/kenny’.
git checkout releases/kenny

Creating a hotfix branch for the ‘Kenny’ release
A hotfix branch should honour its name and contain only bug fixes, not new features. A hotfix can be a cherry-picked commit from the master branch, but also a release specific patch that will be replaced by a different fix in the upcoming release (e.g. if we cannot cherry-pick from the master branch because the affected code has been refactored in the mean time). For clarity we prefix commit messages of hotfixes with ‘HOTFIX:’.

Cherry-picking a bug fix from master into the hotfix branch for the ‘Kenny’ release
Once a hotfix has been rolled out to a deployment, we update its deployment branch to reflect this. We do this by merging the hotfix branch into the deployment branch. The example below shows how we update our SAAS deployment with the latest hotfixes for the ‘Kenny’ release.
git checkout deployments/saas
git merge releases/kenny

Applying a hotfix to the SAAS deployment by merging the hotfix branch for the ‘Kenny’ release into the SAAS deployment branch
When a deployment is updated to a new release, we discard the hotfixes in favour of the changes in the master branch. So if we upgrade our SAAS deployment from the hotfixed ‘Kenny’ release to the new ‘Stan’ release, we first rewind the SAAS deployment branch to the original ‘Kenny’ release tag and then fast-forward along the master branch to the ‘Stan’ release tag. However, before we can do all of this we need to remove the deployments/saas branch from our remote, otherwise it won’t let you push the changes as it thinks we’re behind of the remote branch.
git push origin :deployments/saas
git checkout deployments/saas
git reset –hard kenny
git merge stan
git push origin deployments/saas

Before upgrading to the ‘Stan’ release, the SAAS deployment is at the head of the ‘Kenny’ hotfix branch

The SAAS deployment has been rewinded to the ‘Kenny’ release tag

The SAAS deployment has been fast-forwarded from the ‘Kenny’ release tag to the ‘Stan’ release tag
Once all the deployments have been updated to a new release, the hotfix branch for the previous release becomes ‘abandoned’. Although it is not in use anymore, we don’t delete it. It is part of the history of our applications and it may contain work that can be reused in another context in a new release.

After upgrading the Amazing-co deployment to the ‘Stan’ release the ‘Kenny’ hotfix branch is now ‘abandoned’
Experimental branches
If you want to try out a nice new plugin or do some prototyping, an experimental branch is the way to go. An experimental branch will usually not be merged into master, but contains work that may be integrated into the master branch in an altered form. The name of an experimental branch is namespaced with ‘experiments’ and the initials of the owner. For example, Kyle Broflovski can try out a Facebook integration plugin in a branch called ‘experiments/KB/facebook-integration’.
git checkout -b experiments/KB/facebook-integration

Experimental work on Facebook integration taking place in a separate branch
Wrap-up
We have been using the above strategy for a few months now and it really fits well in our development and release cycle. It would be interesting to know about other strategies, so feel free to share yours in the comments below.