Your branching strategy can support Continuous Delivery, or make it an impossible goal. You should assess the impact of how you branch on your ability to deliver software at all times, and you’ll find some branching techniques that work, while others that make software delivery more like walking in the dark through a field of rakes.
Continuous Integration is the practice of integrating code changes frequently, typically multiple times a day. This means you should check your code multiple times a day and keep your main branch deployable. Continuous Integration is a prerequisite for Continuous Delivery.
The name “Continuous Integration” provides solid hints about the crucial parts of the practice. Everyone should integrate their code into a shared branch (feature branches don’t count) and this should be done continuously, which means you’re doing it all the time; at least once a day, but ideally more often.
You’ll often speak to developers who want to stretch the definition of Continuous Integration, but you can’t escape those foundations. Merging the main branch into a long-lived branch feels like Continuous Integration, but you’ll notice no changes come back for ages until someone finally merges to main. Then you have to perform a large, complex merge, which you should avoid.
The DORA research on Continuous Delivery includes the capabilities of Continuous Integration and trunk-based development. The statistics suggest you can get similar benefits as long as you limit yourself to 3 (or fewer) short-lived branches (less than a day old).
Watch the episode
You can watch the episode below, or read on to find some of the key discussion points.
Watch Continuous Delivery Office Hours Ep.3
The worst branching strategy
Since the ability to branch code was invented, developers have applied a great deal of creativity to how to use branches. The most common approach is feature branching, where each feature gets a branch of main that evolves separately until the feature is complete, and it’s merged back into main. Release branching allows development to continue on main by taking a cut of the main branch that will be released. This allows hotfixes to be applied to the release branch without further destabilizing it.
The utility of branching strategies is often eroded by the coordination overhead of maintaining the separate branches and merging different changes back together. The more complex the branching strategy, the more likely it is that you’ll have merge conflicts and lost bug fixes. For example, you might fix a release branch and forget to merge the fix back to main, so the next release reintroduces the bug.
This is why the worst branching strategy is Gitflow. This is a complicated branching strategy that creates dedicated branches for features, releases, and hotfixes alongside permanent main and develop branches. The overhead of Gitflow vastly outweighs its benefits.
This is where trunk-based development shines, as it removes unnecessary complexity.
The best strategy is trunk-based development
Trunk-based development is the process of making all commits directly to the main branch. This is complemented by out-of-band reviews that don’t block merging and by feature toggles that decouple deployments from releases. It should be possible to deploy your software from the main branch at all times, even if features aren’t complete.
The DORA research allows up to 3 short-lived branches, which can be useful for teams working remotely (like open-source project teams), who can use branches and pull requests to coordinate their work. Even so, the goal is to keep branches short-lived and to merge frequently.
Trunk-based development is complemented by automated builds and checks that run when code is committed to the main branch. If a problem is found during these checks, the team should prioritize the fix over other development work.
Elite performance comes from small batches
Teams with the best software delivery performance work in small steps. Trunk-based development and Continuous Integration are crucial practices for controlling batch size. Problems are discovered sooner and are easier to fix when you only have a small amount of change to reason about.
Making frequent commits makes it easy to back out a bad change. If a test fails, you can discard changes since the last commit and try again, instead of trying to debug the problem. This is especially true when using AI coding assistants or other code generation techniques.
Ultimately, for trunk-based development to succeed without friction, the entire team must be aligned on the process. It doesn’t work if only some of the team are on board.
Happy deployments!
Continuous Delivery Office Hours is a series of conversations about software delivery, with Tony Kelly, Bob Walker, and Steve Fenton.
You can find more episodes on YouTube, Apple Podcasts, and Pocket Casts.
