[Python-Dev] Hg: inter-branch workflow

Tim Delaney timothy.c.delaney at gmail.com
Sun Mar 20 22:16:12 CET 2011


On 21 March 2011 04:32, Thomas Wouters <thomas at python.org> wrote:

>
> Merging and merge changesets are a fact of DVCSes, and while I (as a grumpy
> luddite misanthrope) greatly prefer the automatic (and mostly silent) merge
> as BitKeeper does it, in the long run the actual merging and the merge
> changesets are unavoidable and something to get used to, not dodged around
> (at least not at this cost.)
>

Agreed 100%. I really don't understand the antipathy to branching and
merging. I understand the desire to distribute a collapsed changeset - it's
changing history, but as long as you're absolutely sure that it's never been
shared to another repository, *even another local one* then you're OK.

As far as I can see, people here are fighting against the tools, and as a
result making life much much harder for themselves. Patch, Export/Import,
Mercurial Queues - they're all recipes for ending up with an inconsistent
history across repos in the hands of inexperienced users (and as much as I
consider myself a decent user of Mercurial, I'm very much a neophyte when it
comes to MQ).

The way I set up Mercurial for my team was to have a single master
repository, which was then cloned as many times as desired by developers.
Clones were also made to do automated builds/tests in. Nothing was *ever*
done in the master's workspace (it was always empty).

All work was done in a named branch per task named for the task number. You
could collapse changesets so long as they had not been shared (though we
preferred to keep the entire history - made code reviews and pairing much
easier).

The advantages I saw of this:

1. It's a much simpler workflow. You pull and push between repositories,
update to the named branch you're working on, and commit. You only need to
merge *from* your task branch in most cases, except when merging a change
between feature branches (e.g. named branch -> 3.1 -> 3.2 -> 3.3).

The only complication is if you start your work in e.g. 3.2 but it needs to
be backported to 3.1. In that case, you can either do an export/import/dummy
merge forwards to get the change onto 3.1, or if the change has never been
shared you could *transplant* the named branch onto the 3.1 feature branch
(but that is a history change, using the transplant extension, so should
only be done if the named branch has never been shared outside that repo).
For this reason, you should always branch from the earliest possible
location - you can always merge forwards, but backwards is hard because of
the extra associated history). If the task is for a bugfix, always try to
branch from the point where the bug originated.

2. Work sits in named branches, and can be reviewed there. All you have to
say in the issue tracker is "branch X in repo URL". Work doesn't need to be
merged to the feature branches until it's been reviewed.

This does mean that a branch can be based on an outdated version of the
feature branch. A merge from the feature branch will fix that, but does make
reviewing harder. This is the main reason I've seen to want to rebase - but
in general I still think it's more trouble than it's worth. Live with the
merges - if you really want to, you can always create *another* named branch
to do the merge in e.g. for the first merge from feature branch to task 1234

hg update 1234
hg branch 1234_merged_with_3.2
hg merge 3.2
hg commit -m "Initial merge 1234_merged_with_3.2"

For the second and later merges:

hg update 1234_merged_with_3.2
hg merge 3.2
hg commit -m "Merged 3.2 to 1234_merged_with_3.2"
hg merge 1234
hg commit -m "Merged 1234 to 1234_merged_with_3.2"

Then you have a "clean" branch to review, and a branch that will merge
cleanly with the feature branch. This combined branch is the one that you
will then merge to the feature branch.

3. When a branch is finished, it can just be closed, then merged to the
feature branch(es). Note that you do want to merge the close changeset as
well - this prevents leaving extra heads around.

4. When a branch is abandoned, it can just be closed. It stays in the
history, so if someone wants to take it up again they've got the previous
work sitting there and can either resume, or use it to work out what went
wrong. Note that closing a branch does nothing except hide it from hg heads
and hg branches.

5. It's very easy to just pull or push a single branch (although I'm
personally in favour of all branches eventually ending up in the master
repository). Pulling a single branch from another developer's repo is a good
way to work on a branch together.

6. Working on someone else's code is much much easier. Say I have an
environment set up, with various ignored configuration files, etc. A good
example would be an Eclipse workspace. You really don't want to have to set
up a separate workspace for each task or feature you're working on (which
you would need to do if you're using separate clones for each task). If you
have each task on a named branch, you can just hg update 1234 and your
existing workspace is now ready to work on another task (you might want to
hg purge as well to get rid of generated artifacts such as .pyc files).

I've worked extensively with this workflow, and it was *really easy*. The
entire team was working happily in about a week, and we really found no
reason to change how we used Mercurial once we started doing this. Yes - you
end up with a much branchier workflow, but I found that to be an advantage,
rather than a disadvantage, because I could easily isolate the changes that
composed any particular task.

Tim Delaney
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20110321/2a07d6ec/attachment-0001.html>


More information about the Python-Dev mailing list