Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage concurrent development with mercurial?

This is a best practice question, and I expect the answer to be "it depends". I just hope to learn more real world scenarios and workflows.

First of all, I'm talking about different changes for the same project, so no subrepo please.

Let's say you have your code base in an hg repository. You start to work on a complicated new feature A, then a complicated bug B is reported by your trusted tester (you have testers, right?).

It's trivial if (the fix for) B depends on A. You simlply ci A then ci B.

My question is what to do when they are independent (or at least it seems now).

I can think of the following ways:

  1. Use a separate clone for B.
  2. Use anonymous or named branches, or bookmarks, in the same repository.
  3. Use MQ (with B patch on top of A).
  4. Use branched MQ (I'll explain later).
  5. Use multiple MQ (since 1.6)

1 and 2 are covered by an excellent blog by @Steve Losh linked from a slightly related question.

The one huge advantage of 1 over the other choices is that it doesn't require any rebuild when you switch from working on one thing to the other, because the files are physically separated and independent. So it's really the only choice if, for example, A and/or B touches a header file that defines a tri-state boolean and is included by thousands of C files (don't tell me you haven't seen such a legacy code base).

3 is probably the easiest (in terms of setup and overhead), and you can flip the order of A and B if B is a small and/or urgent fix. However it can get tricky if A and B touches the same file(s). It's easy to fix patch hunks that failed to apply if A and B changes are orthogonal within the same file(s), but conceptually it's still a bit risky.

4 can make you dizzy but it's the most powerful and flexible and scalable way. I default hg qinit with -c since I want to mark work-in-progress patches and push/pull them, but it does take a conceptual leap to realize that you can branch in MQ repo too. Here are the steps (mq = hg --mq):

  1. hg qnew bugA; make changes for A; hg qref
  2. mq branch branchA; hg qci
  3. hg qpop; mq up -rtip^
  4. hg qnew bugB; make changes for B; hg qref
  5. mq branch branchB; hg qci
  6. To work on A again: hg qpop; mq up branchA; hg qpush

It seems crazy to take so many steps, and whenever you need to switch work you must hg qci; hg qpop; mq up <branch>; hg qpush. But consider this: you have several named release branches in the same repository, and you need to work on several projects and bug fixes at the same time for all of them (you'd better get guaranteed bonus for this kind of work). You'd get lost very soon with the other approaches.

Now my fellow hg lovers, are there other/better alternatives?


(UPDATE) qqueue almost makes #4 obsolete. See Steve Losh's elegant description here.

like image 701
Geoffrey Zheng Avatar asked Sep 15 '10 15:09

Geoffrey Zheng


1 Answers

I would always use named branches, because that lets Mercurial do its job: to keep your project history, and to remember why you made which changes in what order to your source code. Whether to have one clone or two sitting on your disk is generally an easy one, given my working style, at least:

  1. Does your project lack a build process, so that you can test and run things right from the source code? Then I will be tempted to have just one clone, and hg up back and forth when I need to work on another branch.

  2. But if you have a buildout, virtualenv, or other structure that gets built, and that might diverge between the two branches, then doing an hg up then waiting for the build process to re-run can be a big pain, especially if things like setting up a sample database are involved. In that case I would definitely use two clones, one sitting at the tip of trunk, and one sitting at the tip of the emergency feature branch.

like image 87
Brandon Rhodes Avatar answered Sep 21 '22 16:09

Brandon Rhodes