Recently I was part of a team trying to decide on a branching strategy for a new project. I had some clear ideas about what I thought made sense, but I found it hard to explain to my colleagues exactly why. To avoid justifying my ideas with hand-waving and mumbling in future, I decided to spend some time working out exactly what factors are involved in such a decision.
Git does a wonderful job of making branching easy, but knowing when to branch and when to merge can still be tricky. Getting this wrong can cause headaches later on when it comes to releasing features or handling urgent bugs in already released code, so it’s certainly worth giving it some thought.
In 2010, Vincent Driessen proposed gitflow as one potential solution to this problem. It’s a very successful strategy that’s worth getting to grips with, but it’s not necessarily the right fit for your team. There are many factors involved in deciding a branching strategy that may mean you need something different.
First, some definitions. I’ll be talking about your mainline, meaning your repository’s default branch (usually master). I’ll also mention feature branches to refer to a branch where developers first commit code, that’s not the mainline.
Now, let’s look at the factors we need to consider when choosing a branching strategy.
Do you ship at the end of every sprint whether it’s ready or not? Do you release code every day? Multiple times a day? Perhaps you release once a month, or just whenever you feel like it’s time. This is one of the things that varies most between different teams and it has a big impact on how you should structure your branches.
Put simply, the more often you release, the nearer your feature branches should be to the mainline. GitHub flow, used by GitHub is a good example of this — developers branch from the mainline, develop their feature and then merge back to the mainline for immediate release. If, however, you release once every two weeks it makes more sense to merge to a ‘holding’ branch (like gitflow’s develop and release branches) before code reaches the mainline.
How confident are you that, once a feature has been developed, it will actually do what it was supposed to do? How do you confirm that the code works as expected? If you have some form of quality assurance or acceptance testing, at what stage is it done? There are lots of options around this, but it generally boils down to either early stream or late stream QA. The early variant means that a feature is tested before it is merged, the late variant means it’s tested afterwards. If your QA is early stream then you can probably get away with having your feature branch close to the mainline. If it’s late, then a release branch is probably where your QA should take place, so that failures can be rectified before they reach the mainline.
The only exception to that rule is if you have either particularly spare release cadence (so there’s time to fix things), or a reasonably high bug tolerance, for example if a project is pre-release or is an internal tool that isn’t mission critical. In these cases it’s generally wise to avoid additional long-lived branches and get straight to the mainline.
How likely is it that a given feature will be released, assuming that it passes QA?
Release planning is another subject entirely, but your branching strategy needs to support your process. They key is to avoid a feature hitting the mainline until it’s approved for release. Gitflow achieves this via the develop and release branches, but you could achieve the same effect with just a mainline and a release branch.
Every branching strategy is a variation on the theme of keeping code out of your mainline until you want it there, balanced against the management overhead caused by having lots of unmerged branches. If your instinct is to avoid merging until the last minute, think about why. Perhaps you need to schedule development more carefully. Conversely, if you’re having to undo merges and cherry pick things a lot then perhaps you’re too keen to merge.
Ultimately, you have to be pragmatic. A complex strategy that mirrors your processes perfectly is only workable if your tooling is up to the job. It’s wise to start simply and add long-lived branches as you need them. Also bear in mind that git is very forgiving. Mistakes happen and they can be rectified — it doesn’t necessarily mean that your strategy is faulty.
Jez Halford is a software development coach helping teams in the UK to be more agile, scale better and automate more. Visit jezhalford.com to find out more.