How We Branch and Release

Shift Flow

There are two important features that we require from a branching model: simplicity and release composition.

Simplicity

We have a dynamic team. The code owners and release a mangers change frequently. Further, our engineers wear many hats. None of them specialize in release or code management. We need a branching model that is easy to grok and limits the possibility of human error. Github Flow provides a simple branching model. But, having individual developers be responsible for their own releases didn't match well with our engineering processes and merging adolescent code to master is more cavalier than we are comfortable with. However, the single long lived master branch in Github Flow is compelling and appeals to our desire for something simple.

Release Composition

One of the problems we often encounter is what I'll call "release logistics". Marketing may want to release a new change to our app tour that they hope will increase stickiness. Sales may want to release a security feature that will impact a new opportunity. Our Customer Success Team may want to release features that have been requested by their enterprise customers. The Customer Solutions Team may need a fix to ship as soon as possible. The Product Team often wants to change the order of when features land so that they can curate the user experience just so. The reality is that scheduling changes is not an engineering problem alone. Sometimes, it's not an engineering problem at all. Scheduling change is often a business problem. So, for us, we can't just merge to develop and wait for the conveyor belt to bring the change to production. We need to compose releases from a set of staged features that are ready for release.

The Branching Model

Shift Flow is intended to support parallel development branches while maintaining the flexibility of what we include in a given release.

Master

Shift Flow has a single, long lived branch, master. Master contains a commit for each release tagged with the semantic version. We merge changes into master only after a release. Master itself is never released. You should always release from a release branch even if you want to rollback to a previous release. In this case you should create a release branch from the previous tag and release it.

git fetch && git fetch --tags
git checkout -b release/1.0.0 v1.0.0

We do this for consistency purposes. It helps everyone involved know that branches with in the release namespace are being prepared for release.

Features & Hot Fixes

Since we use a single long live branch rather than two, creating branches for features and hot fixes is the same. Features should be under the feature name space and hot fixes should be under the hotfix namespace. Features an hot fixes should be further name spaced under the ticket they are addressing so that we can easily tie the change to the request in our ticketing system.

  • The branch naming convention for features is feature/TICKET_ID/SHORT_FEATURE_DESCRIPTION. For example, feature/SHIFT-1234/create-login-form.

  • The branch naming convention for hot fixes is hotfix/TICKET_ID/SHORT_FIX_DESCRIPTION. For example, hotfix/SHIFT-1235/make-left-nav-clickable.

When you are ready to create a new feature or hot fix you should create a new branch off of the tip of master. This branch should be used for review by your peers and product for validation.

You should create a new branch like this:

git checkout master
git pull
git checkout -b feature/SHIFT-1234/create-new-login-form

If you need to keep your branch up to date with master you should merge. First make sure you have the latest master. Then...

git merge master

Commits on Feature and Hot Fix Branches

During development, commit as often as you'd like and describe those commits in any way that works for your development process. When you're finished development squash your commits into the format CHANGE_TYPE(FEATURE): DESCRIPTION. For example, fix(Navigation): Don't open new window when clicking a nav menu item

Hot fixing a release or feature

Sometimes you'll need to patch an upcoming release rather than production. To do this follow the hot fix workflow described above but, instead of branching from master branch from the release branch.

Release

When you are ready to compose a release a new branch is created off of the tip of master. The branch should be name spaced under release/. The branch itself should be named after the expected version of the next release. For example: release/1.0.0. Any features that you'd like to release should be merged onto this branch. This is the branch that you test. This is the branch that you release.

You should create a new release branch like this:

git checkout master
git pull
git checkout -b release/1.0.0

Let's put this into practice with an example. Assume we have two branches: feature/f1 and feature/f2. Let's also assume that both of these branches have gone through validation and we would like to test and release them as version 1.2.0. First we should create a new release branch from the tip of master.

git checkout master
git pull
git checkout -b release/1.2.0

Next, we want to merge each feature branch onto the release branch so that it's new base commit is the most recent commit from the release branch.

# Merge the feature into the release branch
git checkout release/1.2.0
git pull
git merge feature/f1
git merge feature/f2

Lastly, we need to push our release branch to origin.

git push

Finishing a Release

Once you've release your code to production you need to tag master so that we know that the version you've just released points to a specific commit in our commit history.

git checkout master
git merge release/1.2.0
git tag -a v1.2.0
git push --tags

Environments