Any and all comments are welcome regarding this series of posts (okay, you can comment on other posts too). We woul appreciate any feedback pointing out alternatives to these strategies, whether they helped you or not and maybe your experiences dealing with branching strategies. This series of posts will cover all of the major patterns and how to handle branching and merging for all of the situations we can think of! If you think of any more, please let us know.
Branch By Release
In the first on a series of posts regarding branching strategies, I’m going to start off with the ‘super’ pattern (why I call it a ‘super’ pattern is discussed at the end of the post) – Branch By Release. What does the Branch by Release pattern look like and why use it? The figure below shows the pattern and maps out the usage for it (double-click the image to enlarge it).
Figure 1 – Branch by Release, basic pattern
This pattern is most useful when you are supporting a single version of an application (say a website for example). It can also be used for multiple version support but that can get fairly complicated when you get into branching for isolation, and long running features that may take several versions to implement.
The basic structure as shown in the figure is to build and when you are ready for test, create a new active branch for development and release the code on the “parent” branch (I put parent in quotes because even though it is the parent, branch relationships are generally bi-directional and so this designation is for a frame of reference only). While code is in production you can make fixes to it even while the next version is under development. When the fix has been implemented, simply merge down from production to the active branch.
This is perhaps the simplest of all branching and merge patterns. The reason why this is frequently unsuitable for complex branching and merging, as noted above, are when frequent, temporary branches or long term branches are needed that may span releases. While you can use this pattern for those types of requirements, by itself, it does not offer support for complex scenarios without a lot of extra work.
Dealing with Bugs
Now that you’ve seen the basics, how do you deal with bugs? There are two scenarios for fixing bugs – when one occurs in code under test and when one occurs in code in production. These two scenarios are represented in Figures 2 and 3 respectively.
Figure 2 - Bug in Test Figure 3 – Bug in Prod
A bug that is found in Test is the simplest example because you can simply make the fix in test and merge it down to the active branch for the next release and then the fix is in both versions.
A bug found in Production is a little bit more involved – but not much more. If at all possible, see if the users can wait until the next release is out – that way you don’t have to mess with Production and you can follow the pattern for fixing the bug in test. If the users absolutely need it now (or the code under test is due to be released too far in the future) you can fix and test the bug using the code in production and merge the changes down to the code that is under test and then to the active dev branch.
The next question to be addressed is what to do with the test environments. If you have the luxury of multiple test environments, you can simply test the production changes in a separate test environment. If you only have one test environment, you must stop the current round of tests (for Release 2 in Figure 3 above), release the code fixes for production into test and then release to production. At that point you need to merge the changes from production (Rel 1) down into Release 2. Then re-release the code from the Release 2 branch into the Test environment. Once those tests have passed, merge the changes from the Release 2 branch down to the active development branch for the next release.
The last item to consider is common code. There are two options for dealing with common code. The first is to have the common code on its’ own branch and to simply reference the project containing the common code (i.e. never deal with the branch directly, just code on your local machine that you retrieved from this branch). This presents LOTS of problems. The biggest is that the common code can change from under you – maybe even daily. And if you manage to overcome this problem you have to deal with synchronizing releases which can also be problematic. So you might be thinking, “Jeff, why don’t I just reference the dll’s from the most current release of the common code?” Well, you can do that under a certain circumstance. That is – the dll’s must also be in version control (i.e. please don’t reference the common code by using a dll found on a server share somewhere – you are just asking for pain when that dll gets “suddenly” updated out from under you). The other issue is that you cannot really update the common code, if needed, without seriously ticking off the people who own that code – maybe they’re more friendly in your organization when you introduce code changes that they weren’t aware of…
But what if you are going to need the latest release of the common code and YOU want to choose when to get a new version? That leads to the second option – branch the common code into your active dev branch (Figure 4).
Figure 4 – Common Code
This allows you to do two things: 1) You can actually change the common code without screwing up the common code project (don’t do this unless you plan out with the common code owners how to version this and get your changes back into the main common code branch) and 2) You can perform updates on the branched common code (i.e. merge down from the common code dev branch (or, preferrably the QA branch) to your active dev branch) when you feel like the common code is stable enough for you to use. This elimintes the problem of the code changing out from under you. There is one drawback to this approach – once you do the first branch from the common code to your branch and then you branch from say Release 1 to Release 2 there is no longer a relationship between your branch of the common code and the main branch. In TFS you can solve this problem by performing a baseless merge between your new branch of common code and the main branch of common code which will create a relationship between the branches.
Pros and Cons
So when should you use this pattern and when should you avoid it?
- This is the simplest model to use
- It’s a great choice for single release web applications
- You use the same structure for hot fixes and maintenance releases
- There is a minimal amount of branching
- Not as flexible as other patterns
- More difficult to manage multiple releases (more merges are required depending on how many versions you support and they get more difficult as you move along)
- Because file history needs to be traced back to the previous branch, it takes more work to trace
At the beginning of this post I mentioned that I classified this as a super pattern. There are many several other major patterns available – branch by quality (Prod/QA/Dev), feature branches, and release by manifest. The reason why this particular pattern gets the designation of a super pattern is because it can be the top level when used in combination with other branching patterns (yes, you can combine patterns which will be discussed in a later post – but it can get very, very complicated). So, for example, you may use this branch by release strategy and for each release you may have a series of features that are broken up into their own branches. You may decide for each feature to have a Dev and QA branch (the ‘Prod’ branch in this case would be the main branch for the entire release). However, I can’t think of a good situation in which you would ever use this as a sub-pattern for one of the other major patterns.