Imitating "pure" continuous integration in branching workflows

Feature branching remains controversial among CI enthusiasts – here are a few ways to find the middle ground

A common objection people raise when we’re talking about testing and feature branches is that it’s not “pure” CI.

And that’s true. You don’t have everyone’s changes stewing together on one code line. But that’s kind of the point. Using a single code line tends to make that code line rather unstable. But "pure" CI does carry the advantage of knowing right away if your changes play nicely with your teammates' changes.

So how do we get the best of both worlds? How do we get feedback about integration without creating chaos on a critical branch? I’ll outline three different methods that you and your team can try.

Rebase your development branch

The first is to rebase your branch during development. Rebase re-sets commit of origin for your branch, then the new changes you’ve made on the branch are re-played on top of that.

Pure CI_rebase before merge

Running CI against your rebased branch provides a pretty accurate preview of how the new code will work with what’s already on master. So it’s a good idea to do this once or twice a day, and for sure right before you merge to master or your release branch.

Rebase is best for when you’re the only person working on that branch.

Otherwise, it’ll mess up everyone else who is working on that branch and force them to reconcile the clones on their workstations with what’s now in the repo. And they will probably get very grumpy with you for making them untangle all that.

Automatically merge feature branches

Another popular option is to have Bamboo merge master into your feature branch each time you build. This solves a couple of problems: it prevents your branch from drifting away from master, and it shows you how your changes will interact with your teammates’. It also offers a couple of advantages compared to rebasing against master several times a day.

First, your history remains in tact, whereas rebase re-writes the repo’s history to make it appear as if you’d created your branch at a different point in time. Second, you can automate merging with Bamboo. Third, when you automate this with Bamboo, you get to choose whether to actually push the merged code to your branch, or just use the merge as a preview.

CD workflows_automerges

There’s one caveat, though.

Do your CI builds use shallow clones for the checkout step? It's generally a good idea since it speeds up the checkout step and conserves a bit of disk space. But... in order to perform merges, you need the repository's history so Git can look back and find the point where the two branches diverged (called the “common ancestor”). Auto-merging is therefore incompatible with shallow clones since only the current revision of your code will be pulled down. So for builds that are going to employ auto-merging, cache the repo on your build agents instead of using shallow clones.

Pro tip: In Bamboo, it's possible to use shallow clones on master or a release branch, but not on your feature branch – just override the repository settings on your plan branch.

Use a shared integration branch

A third option that is even closer to pure CI is to include an integration branch in your team’s workflow – a concept you'll find in the Gitflow branching model, where this branch is called "develop". When you’ve completed implementation on your feature branch and you’ve got a clean CI run there, merge up to the integration branch.

CD workflows_Gitflow

If your work conflicts with your teammates’, go back to the feature branch and resolve the conflict. Repeat that cycle until you get a clean CI run on both your feature branch and the shared develop branch. At that point, you can create a pull request and merge to master.

It’s best to merge the feature branch into master instead of merging the integration branch upstream. Even though you just got a clean build on integration, that branch may have some half-baked features on it that aren’t ready for release. If you’re using feature flags, that may not matter so much. But even so: by merging the feature branch to master, stakeholders and the rest of your team will be able to see that merge in the repo history and it’ll be really clear exactly what was merged in (especially if you’re including issue keys in your branch names).

CI Git_repo

The fact that Martin Fowler, Jez Humble, and other CI/CD enthusiasts came out against feature branching when it first became popular a few years ago left a strong impression on the software community – developer blog posts and posts to StackOverflow on the subject abound. CI purists are unlikely to be swayed by any idea I've offered here.

But that's ok. For the rest of us – we CI pragmatists – feature branching offers a way to keep master clean, without degrading the rigor of our testing practices.

Posted by Sarah Goff-Dupont

8 min read