pedorro
pedorro

Reputation: 3327

Mercurial workflow to enable working on multiple separate tasks in parallel

There are numerous discussions here that have addressed issues that seem related to this question, but nothing has really answered it directly. Basically, using Mercurial, I want to be able to work on multiple, independent tasks within the same project, at the same time.

For example, I'm simultaneously tasked with bugs X & Y. I work on X for a while until I hit a point where I need to put it on hold for a few days. Say I need input from someone else who is out of the office. So I want to move on to working on bug-Y. Clearly, one option is to just create a new clone of the stable repository. The problem is that requires a new working directory, new Eclipse project, yada-yada... I'd like to be able to keep one working copy.

With SVN I could create a new branch in the repository for each task and just switch my working copy between them. With ClearCase I could create a new activity for each one. In both cases, I could work on each task independently, in clean environment. Then when I'm done with a task, I can commit/push just that one to the central repo.

I've read about Hg named branches & bookmarks. I'm sure that somewhere in there there's a solution to fit our workflow, but I'm not seeing it yet. Can someone explain the steps I can use to achieve this? Is it possible to create two heads in my local repository that I can just switch between? And then update/commit/push/pull those heads independently? In practice I might never even merge them locally, just push each one to our stable repo when it's ready. Am I just thinking about this in entirely the wrong way? I'm very new to Hg (and DVCS's in general) and trying to develop a workflow for it.

Upvotes: 4

Views: 2228

Answers (5)

James
James

Reputation: 12182

When working on multiple tasks/bugs, I prefer using bookmarks over named branches. They do not clutter your history with branching info (but this may be a personal preference).

You normally just work on the default branch. To keep track of this "main line of development", we create a bookmark named "master" (or however you'd like to call it). Now before you start working on bug X, you create a bookmark "bugX".

  • hg bookmark master
    • ... work on the default branch as always...
  • hg bookmark bugX
    • ... work on bugX
  • hg commit -m "bugX 1"
    • ... work on bugX
  • hg commit -m "bugX 2"

You then must work on bug Y, because you have to e.g. wait for input of someone else. To do this, you first go back to the master bookmark (where you left the "main line"), create a new bookmark for the bug Y and start working on it.

  • hg update master
  • hg bookmark bugY
    • ... work on bugY
  • hg commit -m "bugY 1"

You also have to stop working on bug Y now and you want to continue your work on the "main line". You first grab the newest changes from the central repo and then start working on the master branch. When the feature is finished, you can push it. Be sure to only push the master branch with "hg push -r master":

  • hg update master
  • hg pull --rebase
    • ... work on master
  • hg commit -m "new feature 1"
    • ... work on master
  • hg commit -m "new feature 2"
  • hg push -r master

Sometime laster you can finish bug X:

  • hb update bugX
    • ... work on bug X
  • hg commit -m "bugX fixed"

This bugfix must now be brought into the master branch and be pushed to the central repo. You could merge it with "hg merge bugX" or even better - rebase it. When everything is done, delete the bugX bookmark:

  • hg update bugX
  • hg rebase -b bugX -d master
  • hg bookmark -f master
  • hg bookmark -d bugX
  • hg push -r master

"hg bookmark -f master" is needed to let the master bookmark now point to the last changeset of bugX that has been rebased on top of the master branch (I think this is done automatically with mercurial 2.1).

The same procedure can now be done with bugY and you end up with a straight line history.

In a team, you could even consider pushing the master bookmark to the central repository so that it has not to be maintained after pulling (hg push -B master).

This workflow also is described more or less in this blog post.

Upvotes: 1

Martin Geisler
Martin Geisler

Reputation: 73768

I wrote a guide about using named branches for tasks that you might find useful. You write in your answer:

Here are a few gotchas I found:

  • Merge your feature branch back onto 'default' when your ready to push - you can't just push your branch to the remote repository

You need to hg push --new-branch when you want to allow Mercurial to create a new named branch in the remote repository. This is because branches are global and long-lived — so you should not just create them with temporary names.

  • When you push make sure you select to only push the 'default' branch - if you don't it will try to also push any other feature branches that have not yet been pushed

You can use hg push --branch X to only push branch X (and any ancestors, of course).

  • Hg will complain that your push is creating new remote branches - that's ok as long as the branch is already merged locally

Actually, merging it locally has nothing to do with this message — it comes every time you introduce a new branch and it's not important if it's merged or not. Named branches are really the tool you use when you want to have multiple heads in a shared repository. By naming the branches, you avoid confusion when people pull and update: hg update default will still give you the main line of development even though there might be a X branch with highly experimental and unstable code.

Upvotes: 1

pedorro
pedorro

Reputation: 3327

Ok - so I think I've figured this out. I think I'll be using named branches. Thanks for everyone's help.

Here are a few gotchas I found:

  1. Merge your feature branch back onto 'default' when your ready to push - you can't just push your branch to the remote repository
  2. When you push make sure you select to only push the 'default' branch - if you don't it will try to also push any other feature branches that have not yet been pushed
  3. Hg will complain that your push is creating new remote branches - that's ok as long as the branch is already merged locally

If anyone looking at this has further comments and/or suggestions I'll be glad to hear them. I'm not 100% satisfied with this solution yet.

Upvotes: 0

krtek
krtek

Reputation: 26597

The process you're describing is really simple to implement with Mercurial, and there's many way to do it.

For example, you can use anonymous branches :

  1. Put a tag or a bookmark on the changeset you want to use as a start for both development.
  2. Develop your first bugfix, doing as many commit as you need
  3. When you want to start the other line of development, juste update to the previously saved changeset
  4. Develop the second bugfix, and commit the changes

You just created two anonymous branches in your working copy starting at the decided changeset.

You're absolutely not limited to the number of anonymous branches or their starting point, you can even create new anonymous branches on your anonymous branches.

In some cases, tools like TortoiseHG or the the GraphLog extension can really help you understanding which are the parents of each branches and what's the best way of merging them back.

Bookmarks are only a way to easily keep track of various changeset, you can put bookmark on each of your new heads. Depending on the version of Mercurial you're using, the bookmark will "follow" each new commit you make in its particular branch or not.

You can also use named branch to achieve the same purpose, but the problem is you can't easily delete a named branch after it's been created, the name will still be their.

PS: this workflow, or something very similar is described in the following blog post : http://stevelosh.com/blog/2010/02/mercurial-workflows-branch-as-needed/

Upvotes: 3

Andrew Huey
Andrew Huey

Reputation: 852

I generally just go ahead and create named branches for any sub-project or non-trivial bug fix. You can switch back and forth between branches easily with 'hg update'. When I'm done with something, I just merge it back into default.

Here's an article with some good info on branching in Mercurial: http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/

Upvotes: 1

Related Questions