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.