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 rebase changes onto 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 an 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 rebase. First make sure you have the latest master. Then...

git rebase 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

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 rebased 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 rebase each feature branch onto the release branch so that it's new base commit is the most recent commit from the release branch.

# Make the most recent commit on release/1.2.0 be the base commit for the feature/f1 branch
git checkout feature/f1
git pull
git rebase release/1.2.0
# Apply the commits from feature/f1 onto the release/1.2.0 branch
git checkout release/1.2.0
git rebase feature/f1
# Make the most recent commit on release/1.2.0 be the base commit for the feature/f2 branch
git checkout feature/f2
git pull
git rebase release/1.2.0
# Apply the commits from feature/f2 onto the release/1.2.0 branch
git checkout release/1.2.0
git rebase feature/f1

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 rebase release/1.2.0
git tag -a v1.2.0
git push --tags