Simplified Feature Branching - Source control done right

Introduction

As one does typically develop features in parallel, and some features can not be released while others can, a lot of software teams seem to have problems with their source control.

In this post I will describe Simplified Feature Branching usable with git or any other DVCS.

This model is not rocket science, and is a further simplification of Adam Dymitruk's post on feature branching.

It assumes you use proper release cycles and versioning during the software development lifecycle.

Whenever I mention "feature" in this post, I actually mean "feature" or "bugfix", but I am a lazy b*d.

The main idea: simplification

Make everything as simple as possible, but not simpler - Albert Einstein

Whenever things start to get complicated, we should attempt to simplify them by breaking it up into smaller parts. This is exactly what Simplified Feature Branching does. We make the distinction between branching and integration.

Feature (and bugfix) branches

In large development teams we typically have the problem that several things are developed in parallel, and need to be integrated afterwards. What we will do is separate these two concepts.

We will forget about integration for now, and will just create a branch for every new feature or bugfix we perform. We will give the branch a proper name (usually that will be some kind of an ID we get from a tracking tool).

The Development repository would look like this:

  • Development
    • master
      • [Bugfix] *
      • [Feature] *

For example:

  • Development
    • master
      • Bug-sales-123123
      • Bug-marketing-5454
      • Feature-sales-444
      • ...

All branches would be children of Development/master. Exceptions are not allowed, unless you really, really need it and know what you are doing.

This is exactly the same as Adam's model.

Integration branches

Integration branches are the branches where we integrate the different features in a new branch. A typical workflow during development would look like this:

git fetch 
git checkout development/master -B Bugfix-1231 
...
git checkout development/master -B Feature-5454
...

Once we are satisfied with this integration, we typically deploy this dev branch to the shared development environment.

Never alter development/master!!

Important to note here, is that the whole process described here is targeting the development process, not release management, and this is exactly where the simplification starts.

Integration branches are just temporary placeholders. Think about it! Integration branches should be dropped and recreated once a release is finalized!!!

I would even suggest you to make this explicit by having a distinct repository for the release integration. As one typically goes through a process where multiple clients might have requested different features, I would opt for the following approach:

  • Repo: development
    • master
      • [Bugfix] *
      • [Feature] *
  • Repo: releases
    • master
      • staging
      • QA/[customer] *

Here is the simplification: integration branches are just temporary things, which can be dropped and recreated as you want. Let's say you want to setup a QA environment for a certain customer in the releases repo:

git fetch
git checkout development/master -B QA/JohnTitor
git checkout development/Bugfix-1231 -B Bugfix-1231
git rebase QA/JohnTitor
git checkout QA/JohnTitor
git merge Bugfix-1231
git checkout development/Feature-5454 -B Feature-5454
git rebase QA/JohnTitor 
git checkout QA/JohnTitor
git merge Bugfix-1231
git push release QA/JohnTitor -f

This will allow you to have proper branches per customer QA environments and a staging environment (for the final release), while having an acceptable merge tree. IF you want a single commit per feature branch (which makes it easy to revert a feature if necessary), it is advisable to run a interactive rebase in order to make sure every feature is a single commit. 

Once a the version on the staging environment has been approved by all the customers, we do the following:

git checkout master
git merge staging
git tag v1.2.3

As all changes are now integrated in the master, we can drop all the feature branches.

git branch -D Bugfix-1231
git branch -D Feature-5454
git branch -D ...

So all your releases are on the main branch. Once a release is done, you open up git on the development repository, and type the following:

git checkout master
git pull --rebase releases

And voila, your development repository is up to date!!!

And an added bonus

One does not have to have a single development repository, for example one could have one per development team/country/division/... (In my current project we will use a separate repository for outsourced work for example). This approach would also integrate very nicely with code reviews and other CI-related things.

By creating this simplified feature branching model, one clearly separates responsibilities using multiple repositories, and make sure the whole integration process is centralized and separated from development.

Happy simplified feature branching everyone!!

PS: do not forget to enable git rerere when merging git branches; this might save you a lot of time... In fact Adam even suggests sharing your merge cache folder...