4

4

There has been a whole lot of discussion about "Branch Repositories" vs. "Named Branches". If they are both OK ways of achieving the same thing, and ultimately look pretty much the same as far as the repository is concerned, it seems to me that Kiln might be able to abstract away the difference (at least to a certain extent).

Right now, a branch repository is a repository that has been developed separately from development in a different branch repository but the two share a common ancestral revision. The only difference with a named branch is that the two lines of development are within one repository.

To edit each branch in the branch repository case, you MUST have 2 separate repositories (And also working copies, since you are doing work to them). In the named branch case, however, you typically switch between named branches within a single repository to work on each one. It would be possible, however, to have 2 separate repositories in the named branch case and simply have each repository set to pull from a different head. In this case, named branches where you only work on one head per repository/working copy, things work pretty much like how things work with branch repositories.

So, if you have been following along so far and haven't gotten lost, we've established that named branches can work similarly to branch repositories. Given that, could Kiln switch which head is "current" when cloning a repository? If that is possible, it would seem that Kiln could possibly treat named branches almost the same as it treats branch repositories.

The differences would be:

  1. that a new branch repository would get created in the web UI when a changeset with multiple heads gets pushed in...one head is the existing repository, and the new head(s) create new branch repositories.
  2. When you clone a "normal" branch repository, it works as it does now, but when you clone a Named Branch branch repository, you are actually cloning the full repository the named branch resides in but you are cloning it in such a way that Kiln automatically sets the current named branch to the branch you are cloning.

I realize I may have lost many people, and I suspect I have made a number of incorrect assumptions, but is what I proposed possible? If not, what prevents it, and if so, what problems might arise?

Also, if I am wrong, please point out where I am wrong so that we all may learn!

flag

2 Answers

7

I think of named branches as lightweight branches and branch repositories as heavy branches. They are theoretically similar, but have some important differences in practical usage.

Let me start with a brief explanation of our branch-per-feature development process (which makes named branches very important to us), and then I will discuss how it would work differently if branch repositories were used.

In our branch-per-feature process, development creates branches and QA merges them. The "default" branch is our primary repository. The goal is for this to always be a tested and deployable version of our project. Developers create a new named branch for every development item, whether it be a new feature, a bug fix or just simple refactoring. When the developer resolves the related FogBugz case, someone else performs QA on the branch and if it looks good, merges the feature branch into default. At any given time, we can see all the features ready for testing by looking at the heads in our repository.

The most important feature of this process is that it allows us to work on an arbitrary number of features in parallel, without ever having a broken feature hold up the deployment of an unrelated working feature.

Here's an example (with time moving from bottom to top, of course).

| A2    - commit A2 as possible fix for A - default still unaffected
| |     - Features B and C can now be pushed into production
| |     - QA on A reveals catastrophic failure - default is still good
2 \     - B passes QA: merge into default
|\ \
1 \ \   - C passes QA: so merge into default
|\ \ \
| C | | - commit new high priority feature C on new named branch
|/ / /
| B /   - commit new feature B on new named branch
|/ /
| A     - commit new feature A on new named branch 
|/
|
0 default

In this case, I would update to changeset "2", build and push the tested code into production. If the A feature branch is low priority and difficult to fix or test, it might sit out there for a while, but it won't cause any problems for continued development.

You could, theoretically, perform analogous operations with branch repositories, but you would end up with three copies of your code and no way to visualize even the simple diagram I created above. Named branches only require a single repository and the "crazy train tracks" diagram just works out of the box.

As a practical matter, branch repositories are wholly unsuited to this process.


Problems with fully cloned repositories in this scenario:

  • Abstracting away the difference in Kiln would create an alternate universe for users of the client tools, including hg at the command line, tortoiseHG in the file browser, VisualHQ within Visual Studio, and all the other tools that would see repositories where Kiln shows branches. Users working with both Kiln and the client tools would have to switch back and forth between two mental models of how the source control system operates.

  • We have created 131 named branches since feb 10th. Under the branch repository model, we would need 131 copies of our project on at least a few of our testing and build machines. That comes to about 260 Gb of storage for three months of development. This project has been under continuous development for over 8 years. In addition, just testing a branch would require a 2Gb clone operation.

  • We would also need quite a bit of scripting and odd workarounds to be able to shift from one clone to the other without breaking our project (IIS directories, registered DLLs, and probably lots of other things that I am not aware of because I have not attempted this). With named branches, shifting to a new branch is a simple update command.

  • I cannot easily tell which of my 131 branch repositories has unmerged code. This seems to me to be a very serious drawback. With named branches, I can view all the heads very easily.

  • Each branch repository effectively remains a head forever, since they cannot be deleted. When a named branch is merged into default, there is a clear visual "crazy train tracks" indicator that the branch is not longer a head, and an explicit "heads" view to back it up.

  • Since the client tools provide no visibility outside the current repository, it would be very easy to leave orphaned code in a repository or to begin working with one that has an outdated version of the default branch code.

  • How can I tell at a glance which version of any given branch repository has been merged into our primary code branch? Was it the latest or was there a bugfix commit after I performed the merge?


I am sure that there are development processes that work well with the branch repository model, but branch-per-feature is not one of them. Glossing over the differences in Kiln is not going to change that.

link|flag
1 
Steve, thanks for the great writeup of how your process works. The more I read and think about the differences in the branching models, the more named branches seem preferable. One question I have, however, is how does your workflow handle 2 different things. 1.) Released versions and updates to those versions 2.) Feature branches that spawn mini-feature branches off of them or cases where there are dependencies between features (eg. feature D depends on part of both features B and A...does D development have to wait for both A and B to finish?) – cdeszaq May 14 2010 at 13:51
1) We don't track releases because our project is internal to a single client. If we did, I would just create a named branch for each release and leave it as an open head. Features and bug fixes could be merged in as needed. – Steve Coffee May 14 2010 at 14:38
2) If you have a feature D that is truly dependent on A and B, I would set it up like this: Create feature branches for A and B normally. to create branch D after some work was done on A and B, merge A and B, but check the result of the merge into new named branch D. Development can then proceed on all branches. As A and B progress, their changesets can be merged into D. If there is truly a logical dependence, they you would not merge D into default until A and B are complete, but that is a constraint imposed by a real relationship of the features, not by the development process itself. – Steve Coffee May 14 2010 at 14:41
"I cannot easily tell which of my 131 branch repositories has unmerged code. This seems to me to be a very serious drawback. With named branches, I can view all the heads very easily." This is the critical feature for our workflow. – Tim Henigan Jul 13 2010 at 17:13
Wouldn't this process end up leaving lots of named branches in your repository and start cluttering things up? – Mike Feb 15 2011 at 16:21
3

The best way we've found to do this is the hg-remotebranches extension. Once it's installed, you clone your repo, and then pull from each branch repo, without merging. What you'll end up with is a multi-headed repo, where each head is tagged with the branch repo name. For example, my Kiln repo looks something like this:

o devel/default
|
o o 1-2/default
|/
o o 1-1/default 
|/
o
|

Each time you push or pull, the tags are updated according to which repo you're pushing to. You will have to remember to use hg nudge (a.k.a. hg push -r .) to make sure you don't push all of the heads.

link|flag

Your Answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.