Limitations of Branching and Merging with TFS

To paraphrase the old nugget about distributing objects, the golden rule about [tag]branching[/tag] your codebase is Don’t Branch Your Codebase. In the past, I’ve worked for organizations whose attitude towards managing code could best be summarized as Branch First, Ask Questions Later (or indeed, I branch, therefore I am). Branches add overhead, and you shouldn’t use them except where you need to provide medium or long term isolation between coding activities on the same codebase. If your multi-site, multi-zeros-before-the-decimal-point-priced source control system allows you to branch from your branch from your branch (and so on), don’t feel compelled to do this. Unless of course you have figured out how to make money out of it (in which case, feel free to leave a comment here to tell us how).

I’m with the [tag]Pragmatic Programmers[/tag] when they say

Tags and branches can (and should ) be simple to use. The trick is to use them in the correct circumstances.

For us, with TFS, the correct circumstances are just for releases. We create branches when we want to support what we have handed over to the customer, without interfering with our ability to move ahead with the next release. If any issues come back on a release, we can solve that problem on the branch, giving the customer a fix and nothing but a fix. We can then merge that fix down to Main, usually automatically, thus incorporating into future releases. So far so good. But even with this deliberately simple approach, there are pitfalls…

I’ve written before about how pleased (and surprised) we were with Team Foundation Server. We recognize that it is young and relatively thin on features compared to other Agile development platforms, but it is certainly stable and – very importantly – extensible.

We’ve been putting the branching and [tag]merging[/tag] side of [tag]TFS[/tag]’s [tag]source code control[/tag] system to the test for some time now, and there are some things that are ‘interestingly different’ from what we’re used to with, for example, [tag]CVS[/tag]. Some of these differences must be considered limitations, and should be dealt with in later versions of TFS. In the meantime, here are some limitations that we’ve found with TFS, and how we deal with them.

Complicated Scenario #1
It doesn’t take long to find yourself sitting right here: A release that has gone to production (you released it to QA over a month ago) has been found to contain a problem. No problem right? You just saunter over to the release branch for that release, make the fix, test, re-release, and merge the fix back to Main. The problem is that because you work on a 4-weekly release cycle, you’ve already created a release branch from Main, to cater for your most recent release (which is currently with QA). In my opinion, the correct approach would be to merge the fix down onto the new release branch. This is the ‘hot’ branch – it’s where the change is needed the most. And in any case, any changes made here will find their way down to Main when this branch in turn is merged. Unfortunately, TFS is too restrictive about the targets of its merges. If I am merging a branch (and assuming I have not branched from that branch) the only merge target than TFS offers me is the place from where I branched – in this case, the Main.

To get the production fix into QA for the next release cycle, I now have to do something which makes me feel, well, kinda dirty. I have to merge up. I think that it’s simple code control hygiene to always merge downwards. Doing otherwise is like rubbing a dog up the wrong way – you’re likely to get bitten. For example, merging upwards on many systems can lead to items going full circle and getting merged on top of where they’ve come from.

A general point worth making here is that when performing branching and merging, it’s important for developers to keep a clean consistent model of the branching strategy in their minds. Difficulties in using branches are much more likely to stem from unclear patterns of use and poor communication than due to bad tools. Simple rules like ‘always merge downwards’ can be very helpful.

OK TFS forces us to merge upwards, but it’s not all bad. At least its interface makes the operation easy. When you begin to perform a merge on Main, the targets that it offers you are all the branches that have been made from Main. It’s just a matter of selecting the branch you want to ‘bounce’ the production fix into (I’m calling it a ‘bounce’ because that’s what it looks like – the fix is coming down from a release branch to Main, and straight back up again to the next release branch). Very importantly, the dialog box that appears as part of this merge allows you to chose a particular changeset rather than all unmerged changes. For a bounce, we just want to merge the recent changeset that was created when checking in the production fix merge.

Complicated Scenario #2
A developer is working on some changes for the upcoming release, but they don’t check in their changes to Main before the release branch is created. It’s that sinking feeling you get when you miss your turnoff on the motorway/highway. In the case of TFS, the analogy is a good one because you have to make an annoying long trip to get back on route. Whereas in CVS, you can just flip over to the branch and check in your changes there, TFS will not allow you to check in anywhere except to the point from where you checked out. This means that the developer is obliged to go ahead with the check-in (on Main), and then (holding their nose) merge that change upwards into the new release branch.

An occasional merge up isn’t going to hurt anyone, but if a company relies on this fall back too often, I suspect that they will end up with a very complicated pattern of TFS use that will lead to confusion and errors – the kind of stuff that gives branching and merging a very bad name.

I don’t know whether [tag]Microsoft[/tag] have designed out any possibility of more flexible merge targets, or more flexible check-in targets in TFS, but if they haven’t I sure hope this is something that’s on the way in the next release.

  1. #1 by Brendan McKenna on April 2, 2007 - 5:40 pm

    Hi Brendan,

    We do a branch for every release of our product – including ones that customers don’t see. Our situation is that we have multiple customers running off of different versions of the codebase, so we have to ensure that the versions that the customers have are ‘clean’. In our situation (we’re not using TFS, we use a product called Perforce), the relative simplicity of having existing branches representing each of our product versions means that should a customer encounter a problem, we don’t have to roll back to a particular revision level (tag/label or whatever) in order to address the problem, we just go ahead and check out the version we need.

    It does make things a little more difficult since when the time comes that the customer wants to upgrade to a newer revision of the software than what they currently have, we have to merge in those changes with the new version, but we’ve developed a set of procedures in-house that makes the whole process rather painless.

    Having release-specific ‘main’ branches, though, does make life simpler for us (oh, our release cycle is a bit longer than 4 weeks, too — 3-4 months).

  2. #2 by Brendan Lawlor on April 3, 2007 - 8:29 am

    Hi Brendan – good to hear from you.

    In so many ways, process for product development is more straightforward than process for a service providers. Except when it comes to source control. We typically (though not always) have one customer per project. When the day comes for us to develop a product, I think that we would adopt an approach similar to your own.

    In essence it’s not that different from ours: a branch per release. Operationally it’s different in that you have a lot more active branches open to cope with various customers using various releases. This means that for you, the limitations of TFS that I spoke of would be even more pronounced. Lucky that you’re using Perforce then 😉

    You have made something clearer for me – TFS will need to catch up with the flexiblity of CVS/Perforce/Clearcase etc in order to deal safely with product-based development.

  3. #3 by Ben Strackany on May 6, 2007 - 7:22 pm

    Good post, Brendan. I’m also getting used to TFS and its way of doing things. FYI, you can actually merge anywhere you want by doing a “baseless merge” — basically running TF.exe from the command line from one branch to another. It’s not as easy as the GUI, & you’ll get a bunch of “resolve conflicts” prompts, but it does allow you to avoid merging up, down, & all around to try to get your changes where they need to go.

  4. #4 by Brendan Lawlor on May 8, 2007 - 8:27 am

    Hi Ben,
    Thanks for that. A colleague here in DSI pointed me in the direction of baseless merges as well. If I understand correctly, it gets its name from the fact that it is a simple two-way merge (i.e. not with reference to a common parent). A merge like that seems less safe and reliable than one based on a common starting point, where the line numbers in the deltas have some kind of common meaning.

    For any two revisions of a file on CVS (on the Head, or a branch) you can draw a line of history between them, and pick any point along it to be the common parent, for the purpose of a merge. If TFS would only maintain the history of branched files, rather than starting them from scratch every time a branch is done, then a similar safe merge would be possible between branches.

    But perhaps this practice of resetting the history of a branch is a requirement of the directory-space branching that TFS uses (as opposed to the revision-space branching of CVS).

  5. #5 by Richard on August 20, 2007 - 1:17 pm

    “If TFS would only maintain the history of branched files, rather than starting them from scratch every time a branch is done, then a similar safe merge would be possible between branches”

    You can install the Power Tools and then use the /followbranches flag to retrieve the history information.

    History Command
    Use the history command to display the revision history for one or more files and folders. The /followbranches option returns the history of the file branch’s ancestors.

    There is also a codeplex project to enable the option in the GUI

  1. More Limitations of TFS Branching at DeCare Systems Ireland Blog

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: