I no longer work at Microsoft, so please don't bother leaving a comment here or trying to contact me through my MSDN blog.
You can find my new blog at http://www.technologytoolbox.com/blog/jjameson. My new site also provides copies of all posts from my MSDN blog.
While attending TechReady (an internal Microsoft training conference) last week, I learned a lot -- not only about future versions of our products, but also numerous tips and tricks for current versions. One of the most valuable insights I gained was from a session on branching in Team Foundation Server (TFS). If you've read my previous post on structuring Visual Studio solutions, then you know that I'm a proponent of branching from the start in order to easily support parallel development and periodically stabilizing for a release.
I had previously read the TFS Branching Guidance on CodePlex, although I admit it has been a rather long time. Nevertheless, I still understood the commonly used Main, Dev, and Release branches. However, I discovered during the session last week that I had a fundamental misunderstanding about baseless merges in TFS. Prior to last week, I thought a baseless merge occurred when the source and target do not share any ancestry in the branching tree. In other words, I thought that as long as the target resides on a branch that can be traced through some lineage to the source branch, then TFS has sufficient "knowledge" (i.e. algorithms) to merge changes from the source to the target.
As I stated before, this was a misunderstanding on my part. When I asked a question about trying to delay the branching for stabilization for as long as possible, the presenters of the session -- James Pickell and Mario Rodriguez -- pointed out that a baseless merge occurs whenever the target is not in a "first level" branch from the source. In other words, you can automerge from parent-to-child (or child-to-parent), but you cannot automerge from grandchild-to-grandparent.
So, what does all of the mean in practical terms?
It all comes down to how -- and when -- you actually branch your code.
In the interest of not reinventing the wheel, allow me to pilfer one of the images from the updated TFS Branching Guide 2.0:
Note that this is a basic branch plan, but it is sufficient to demonstrate the concept. You may very well have a more complex branching strategy (e.g. a large organization like Microsoft in order to support "feature teams"). However, the essential pattern still applies.
The question that I asked during the session was essentially why not postpone branching for as long as possible? In other words, why not branch Release first, and then branch for hotfixes and service packs as necessary? In my mind, this alternative approach reduces the merge effort by only branching at the point in time when we actually need a branch (e.g. to stabilize for a release). At some later point in time after the release when we actually need a hotfix or service pack branch, then we'll create it from the Release branch. In response to my question, Mario termed this "reactive branching" -- which seems like a very good way to describe it. To help visualize the difference, I mocked up the following figure.
There are a couple of significant problems with reactive branching:
So, in summary, while it may seem a little backwards to create your Service Pack branch before your Release branch, there are compelling reasons to do so. As for me, I now consider my "reactive branching" strategy to be a thing of the past.
Thanks to James and Mario for setting me straight!
By the way, if you haven't read the branching guidance created by the VSTS Rangers, I highly recommend it. Very good stuff.