“The build server uses the Git plugin for Jenkins to monitor all the branches on the local repository. Whenever a developer pushes to the repository, Jenkins will see the change and try to merge it into the stable branch. If the build passes, the merge is committed. If it doesn’t pass, the FeatureBranch doesn’t get merged – and it will stay unmerged until another change is made against it.”
This feature means that broken builds have almost no impact on team productivity. In fact – it can even be more productive to allow a broken build than to try to prevent it all the time.
How do you do it?
Let’s talk the mechanics of how to do this. I’ll assume that you’ve set up a Git repository, you’ve got a Jenkins server, and you’ve installed the Git plugin for Jenkins. If you haven’t done that yet, go do it now – I’ll wait.
Now, go in and create a new job. In the “Source Code Management” section, you should see the Git option. Select it – you’ll get a bunch of options. There’s a lot here, and you really need to understand Git to understand them, but here’s the quick start version:
- Repositories – URL of Repository: enter in your Git repository’s URL. Something like ‘git@mygitserver:path/to/repository’.
- Branches to build – if you leave this blank, it will default to ‘**’. This means that every branch will get built whenever any change is committed to them. That works fine if you’re using a dedicated repository, or don’t have any parallel development branches (including maintenance branches). However, you can put in any glob pattern you like – for example, ‘stories/**’.
Now you want to hit the ‘Advanced’ button. Not the first Advanced button, just under the ‘URL of Repository’ box – no, you want the second Advanced button, under the ‘Branches to build’ section. (There aren’t any fancy-pants UXI designers here!) Fill in these values:
- Checkout/merge to local branch (optional): Put in the name of the branch you want to merge to. Yes, this is optional, but it means you can do things like use the Maven Release Plugin. If you don’t want to do that, don’t bother – this is just local to the Jenkins workspace.
- Merge options: tick the ‘Merge before build’ box. This will give you two more options. In the ‘Branch to merge to’ box, put the name of the branch in. I use ‘staging’ for my target branch, but you can use ‘master’ or whatever you want.
Okay, now go down to the ‘Git Publisher’ section at the bottom of the page. In this area, you want to:
- Tick the ‘Git Publisher’ box.
- Tick the newly revealed ‘Merge Results’ box.
Right! Now you’re good to go. Let’s talk about what will happen.
How the builds work
Here’s a typical scenario: a developer creates a feature brach (Feature 1 – the bottom line) off the current HEAD of the integration branch (‘a’, on the middle line). She does some work, commit it and push it to the build server. The resulting build is successful, and so the change is merged back to the integration branch.
At this point, another developer creates another feature branch (Feature 2 – the top line). He does some work, commit it and push it to the build server. This build fails – the work in not merged in. Presumably, the developer will get emailed about it. With a more conventional approach to builds, this is where problems occur – people will not be able to make successful builds until something is done. However, that’s not a problem with this feature!
The first developer, meanwhile, has continued on with her work, commits it and pushes it back. Jenkins sees the change and builds it – ignoring the broken branch! This then gets merged back into the integration branch, and all is good.
Finally, the second developer fixes the build. Jenkins will try to merge the changes into the integration branch – this may succeed, in which case it will build it, or it may fail with conflicts. In the latter scenario, the second developer will need to merge the integration branch into the Feature 2 branch first. However, once the branch is up-to-date (or, at least, doesn’t have conflicts), Jenkins will build and fold the changes back to the integration branch.
So what can I get out out it?
Here’s the big takeaway from all this: broken builds are no longer a blocker for the team – they are only a blocker for the developer (and his pair!) working on the feature branch. As there are no impacts on the rest of the team, it becomes possible to be more lax about build failures.
“If everything seems under control, you’re just not going fast enough.” – Mario Andretti
The purpose of the build server is to save the team time. When a broken build is a team blocker, then people want fewer broken builds – otherwise they don’t get the advantage out of having a build sever, and they ignore it. But if a build never breaks, then the team is being too cautious – they are religiously running all the tests and other quality controls on every commit, even if there is no real chance of the checks failing. This becomes a drag by itself – even if it’s a fast build.
Once you take the “broken builds block the team” out of the picture though, then a broken build becomes a tradeoff. Going to grab a drink, or take a ‘bio break’? Commit and push! Time for lunch, or going home? Commit and push! Just think it’s going to work, and you need to swap over to a different task? Commit and push! Let the build server find out if it worked – that’s its job.
If a build is going to take, say, five minutes to run, and it will only fail one time in ten, then letting the build server do the checks will save you forty-five-minutes out of fifty. Pushing a few times a day, like everyone should? Then over a week it could save you up to two hours – that’s an extra day’s worth of productivity a month.
This doesn’t mean that a broken build can be ignored. After all, the functionality in that branch won’t be made available to anyone until the build is fixed. But it means that the broken build become non-urgent, not unimportant.
(Actually, I’d advise anyone doing this to keep an eye out for ‘abandoned’ branches – branches that haven’t been folded back into the integration branch. This can be scripted, or made easier by tools like Gitweb or FishEye)
So that’s how and why I learnt to stop being afraid of broken builds.