SimpleBranch.png

Simple Branching Strategy Part 2: Implementation

In my previous post, I talked about the idea of having a simple branching strategy and why I prefer one where everyone works off the same branch.

In this post I will show you how to create what I believe is the most simple and effective branching strategy.

Take a look at this diagram of a sample project’s code lines:

simplebranch thumb Simple Branching Strategy Part 2: Implementation

Walking through it

The idea here is very simple.  Let’s walk through a development cycle together:

  1. Development starts.  Everyone works off of trunk.  Code is frequently checked into trunk, many developers checking in code 3-4 times a day, as they complete small quality sections of development.
  2. The continuous build server is continuously building and checking the quality of the code every single time code is checked in.  Any integration problems are immediately fixed.
  3. Enough features are done to create a release.  Trunk is tagged for release and a release 1 branch is created representing the currently release production code.
  4. Developers continue to work on trunk not being interrupted by the release.
  5. A customer finds a high priority issue in Release 1.
  6. A Rel 1 Hot Fix branch is created, branched off of Release 1 to fix the high priority issue.  It turns out that a good fix will take some time.  Team decides the best course of action is to apply a temporary fix for now.
  7. Rel 1 Hot Fix is done and merged back into Release 1 branch.  Release 1 is re-deployed to production.
  8. In the meantime another emergency problem shows up that must be fixed before the next release.  Rel 1 Hot Fix 2 branch is created.
  9. The bug fix for Rel 1 Hot Fix 2 is a good fix which we want in all future releases.  Rel 1 Hot Fix 2 branch is merged back to Release 1 branch, and merged back to trunk.  Release 1 is redeployed.
  10. In the meantime work has been going on on trunk, team is ready for Release 2.
  11. Release 2 branch is created…

Breaking it down

I gave a pretty detailed walk-through for a very simple set of actual steps.  But, I hope you can see how simple this process really is.

The basic idea here is that we are trying to decouple releases from development as much as possible.  The team is always going to keep chugging along, building new features and enhancing the code base.  When we decide we have enough features for a release, we simply branch off of trunk and create the release branch.

We can even do some testing on the release branch before we go to production if we need to without impacting future development.

The release branch code-lines never come back to trunk.  They don’t need to, they only exist so that we can have the exact production code and make modifications to it as hot-fixes if we need to.

We branch hot-fixes off of the release branch so that we can work on them independently, because not all hot-fixes go back to the main code-line.  We can make a hot-fix just for the current release, or we can merge it back to trunk to make it a permanent fix.

That is all there is to it.  This kind of branching strategy almost completely eliminates merges.  The only merge you ever do is small merges for hot-fixes.

Your branching strategy does not have to be complicated.  A simple strategy like this can fit almost any software development shop.

Frequently disputed points

Almost immediately when I introduce this simple system someone says:

What about half-completed features?  I don’t want to release half-completed features.  Using this strategy with everyone working off trunk, you will always have half-completed features.

So what?  How many times does a half-completed feature cause a potential problem in the system?  If the code is quality and incrementally developed, it should not impact the rest of the system.  If you are adding a new feature, usually the last thing you do is actually hook-up the UI to it.  It won’t hurt anything to have its back-end code released without any way to get to it.

Continuous integration, (especially running automated functional tests), trains you to always keep the system releasable with every commit of new code.  It really isn’t hard to do this, you just have to think about it a little bit.

If worse comes to worst and you have a half-finished feature that makes the code releasable, you can always pull out that code on the release branch.  (Although I would highly recommend that you try and find a way to build the feature incrementally instead.)

If you know you’re going to do something that will disrupt everything, like redesigning the UI, or drastically changing the architecture, then go ahead and create a separate branch for that work.  That should be a rare event though.

I need to be able to develop the features in isolation.  If everyone is working off of trunk, I can’t tell if what I did broke something or if it is someone else’s code.  I am impacted by someone else breaking things.

Good, that is some pain you should feel.  It hurts a lot less when you’re continuously integrating vs. working on something for a week, merging your feature and finding that everything is broken.

It is like eating a meal.  All the food is going to end up in the same place anyway.  Don’t worry about mixing your mashed potatoes with your applesauce.

If something someone else is doing is going to break your stuff, better to fail fast, then to fail later.  Let’s integrate as soon as possible and fix the issue rather than waiting until we both think we are done.

Besides that, it is good to learn to always check in clean code.  When you break other people and they shoot you with Nerf guns and make you wear a chicken head, you are taught to test your code locally before you check it in.

How to be successful

How can you be successful at this simple strategy?

  • Make sure you have a continuous integration server up and running and doing everything it should be doing.
  • When you work on code, find ways to break it up into small incremental steps of development which never break the system.  Hook up the UI last.
  • Always think that every time you check in code, it should be code you are comfortable to release.
  • Check in code at least once a day, preferably as soon as you make any incremental progress.
  • Test, test, test.  Test locally, unit test, test driven development, automated functional tests.  Have ways to be confident the system never moves backward in functionality.
  • So important I’ll say it twice.  Automated functional tests.  If you don’t know how to do this, read this.
  • Release frequently instead of hot-fixing.  If you never hot-fix you will never have to merge.  If you never have to merge, you will live a longer, less-stressed life.
  • Don’t go back and clean up code later.  Write it right the first time.  Check it in right the first time.

Hopefully that helps you to simplify your branching process.  Feel free to email me or post here if you have any questions, or are skeptical that this could work.

  • Pingback: Simple Branching Strategy Part 1: Back to Basics « Making the Complex Simple()

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #616()

  • Darrell

    This is exactly the strategy we use on our team, and it works great. I definitely agree with every point in the “How to be successful” section, but can’t overemphasize the importance of being able to run your tests locally in this scenario though – we put a bit of effort into making sure our automated tests (mixture of NUnit and Fitnesse) will not only run locally, but are easy to run locally, so we can test as much as possible before checking in. Before this was setup well, we had a hard time keeping the build green.

    One other thing to note with this approach is that it’s so unbelievably easy that new members to the team are brought up to speed instantly. What’s an easier branching strategy than don’t branch if you don’t need to?

  • Pingback: Source control and branching strategies « Daniel van Wyk's Blog()

  • http://blog.gfader.com/ Peter Gfader

    #1 +1
    Couldn’t agree more with this strategy.
    I was actually thinking that this strategy is done by everyone, because its so simple and easy… but it doesn’t seem so.

    #2
    Automated test are VERY important … you said it twice already ;-)

    #3 -1
    >>Don’t go back and clean up code later.
    >>Write it right the first time
    Cant agree with that one. It is very hard to get everything right the 1st time.
    Be a boy scout developer!
    -Fix code when you see something not nice
    -Checkin small changes

    Follow the boy scout rule:
    Leave the campground cleaner than you found it.

    .peter.gfader.
    http://blog.gfader.com/
    http://twitter.com/peitor

    • http://simpleprogrammer.com jsonmez

      Thanks Peter,

      About #3. What I mean there is that you shouldn’t create code that is sloppy with the idea that you will go back later and fix it. I agree 100% about being a boy scout developer.

      I am trying to say there that someone should not check in code that hasn’t been refactored, or hasn’t had static code analysis violations that they know about cleaned up with the thought of coming back to it later.

  • Pingback: הבלוגים של אורט » ארכיון » links for 2010-06-14()

  • http://bigpigvt.blogspot.com RobH

    Nice couple of posts with some stuff to “chew on.” A couple of thoughts.

    First, I’m struck that in your example Release2 reintroduces the bug that Release1 HF1 was supposed to fix. There’s nothing in this process that prevents that from happening.

    Second, legacy applications (which I would argue is what the majority of developers work on) rarely have a robust set of tests – or an architecture that even supports testability. So while CI and automated testing will eventually train the team to keep trunk in a ready to release state it may be a good long while before you hit the tipping point where that’s realized. In the meantime branch-by-feature seems like a reasonable middle way.

    Regards,
    Rob

    • http://simpleprogrammer.com jsonmez

      Not always do you apply a fix from a previous release to the new release. Sometimes for the new release you do a different fix, that is more appropriate. The old release fix might be a panic “have to just get this working with duct tape” type of fix that you don’t want to move forward. You want to fix it the right way for the next release.

      You are right about legacy code, but shouldn’t we move in this direction? Even if we can’t get there right now. We should have our goals set on this kind of simple branching strategy and figure out how to get there.

      Thanks for the comments.

    • Tim

      I think the example has shown that hot fixes “can” be RI’d to the trunk. So there is no more risk than what is being done in today’s traditional branches. The same could happen in a dev, main, prod branch setup where fixes in the prod branches may not RI back to main. This is something that has to be managed whether your setup is like John’s or you have a more traditional Dev –> Main –> Prod style.
      Also, remember the importance of labels within branching. Most SC gatekeepers worry about losing snapshots or the ability to revert back when simplifying branching. Labels can help alleviate these concerns.

  • Wes

    I’m a bit late to this discussion, but I have a question about loosing historical builds with this model. In this example, once I’ve merged hotfix 1 back into my release 1 branch, I have completely lost that build as it existed before the hotfix. In an ideal world, every time I created a hotfix it would only fix exactly that one bug, and it would be tested completely and work stupendously before I merged back in to release 1. But we don’t live in an ideal world, people make mistakes, and sometimes I might just need to get back to release 1 as it existed before hotfix 1. I love the simplicity of this model, but I see that as a serious drawback. Is there any way around this or maybe something I’m just not understanding here? Thanks.

    • http://simpleprogrammer.com jsonmez

      Hi Wes,

      Good question. If you want to preserve the branch before the merge was done, you can do 1 of 2 things.
      1. Just use the prior SVN number (assuming you are using SVN, before the merge)
      2. Just tag right before the merge.

      I try to keep it simple and don’t tag unless I am finding that I am historically needing to do this.

      • Wes

        Thanks. I didn’t think about about tagging. We use TFS here, and this has become a much discussed topic in the past couple days. After reading this, I was on board. I hate all the merging back and forth between the trunk and dev that happens in the standard branching strategy; it’s always seemed very sloppy to me,, so I’m ready to implement this. Sadly, my seniors don’t agree :(

  • Chris

    It’s a tough call. A more granular branch and merge strategy is always better. The problem is that it takes more resources. This is a huge problem, not just an annoyance. Time is money and the larger your code base and the more branches you have and the more versions you support, the more it gets out of control. If you have the resources to manage it, like Microsoft, then go for it, but most companies now-a-days need to be nimble and efficient so tell your seniors they need to KISS the process (as in Keep It Simple Stupid).

    Thanks for a great article