It always starts with good intentions. You start with
git init. You have a crisp, clean, new repository, untouched by human hands.
But the way that you choose, in those first few hours, to handle code branching and merging can either lead you slowly to nirvana… or to the depths of despair.
And don’t forget the merge conflicts. Frequent, painful merge conflicts.
So what’s the best Git branching strategy right now? What should you use to help you achieve continuous delivery?
In this article we’ll find out.
Why does it matter?
Here’s what happens if you don’t pick a successful branching model:
Developers trip over each other, because all of the work is being done in “long-lived” feature branches. This means that developers are creating a branch to work on some code, and not closing it for weeks or months. So when the code is merged back into the main branch, you have hours of fixing horrible merge conflicts.
Your code isn’t always in a deployable state.
New team members find it difficult to get started. They need to spend time with the wise old developer to learn about all the historical reasons why branches are such a mess.
The customer becomes really frustrated and keeps asking why it’s taking so long to get their feature requests done.
So how do you fix this?
Pick the simplest branching strategy that works.
Recommended: Main branch + short-lived branches + frequent merging
Although you can choose any kind of branching strategy you want, many teams have settled on this approach:
Your main or master branch should always be deployable. This means that anyone should be able to take the latest commit from the master branch, and be able to confidently deploy it into production, right now.
Use short-lived feature branches when developing new code.
Frequently merge these branches back into main or master.
Then, here’s what you should do as part of the stages in your CI/CD pipeline:
Run your unit tests
Build an artifact for your application - e.g. a Docker image, a JAR for Java, or an RPM for Linux.
Deploy the artifact to each target environment, one by one. - first Dev, then Staging, then Production.
And how do you do short-lived feature branches? It’s impossible!
Use feature toggles or feature flags.
If you’re working on some big new feature request, which you know is going to take several months: break it down into smaller branches.
Add a feature toggle - which is a piece of code that will switch your new feature on or off. Keep the toggle switched off.
This means that you can add all the bits of code to support the new feature into the codebase, but keep them disabled until all of the work has been completed.
Then, your final piece of work on this new feature is to switch on the feature toggle.
What about Git Flow? Is that recommended?
I wouldn’t use Git Flow these days. Even though it’s the top result when you search Google for “git branching strategy”.
It’s a well-intentioned, but out-of-date approach, which doesn’t take into account of all the cloud and automation tools that have made it easier for us all to adopt continuous delivery.
Git Flow is based around the concept of feature branches, release branches, a hotfix branch, and lots of git tags.
It’s focused more towards applications which have longer release cycles – e.g. every few weeks or months.
But now we have platforms and pipelines that can take your code, configure a cloud server and deploy it straight into production within minutes, Git Flow is…. less than optimal.
If you’re starting a new project, and are working towards continuous delivery (and you should be - it will make your life easier!) then you shouldn’t use Git Flow.
What if we don’t have lots of tests?
The perfect CI/CD pipeline should have a healthy amount of automated tests, so that you know your code is rock-solid.
If you don’t have that, you probably don’t want to automatically deploy to production.
(I mean, you can try it if you really enjoy getting called up at weekends when the software crashes.)
Instead, start working hard towards implementing a suite of automated tests (functional tests, like simulating clicks through the application).
Then you can consider doing automated deployments to production.
The master or main branch should always be deployable.
Use short-lived branches to add new code or fix bugs.
Add feature toggles so that you can globally disable a new feature, while you’re still working on it (in your short-lived feature branches.)