Moving Changes to Feature Branches After-the-Fact in Mercurial

This post is a few years old now, so some details (or my opinions) might be out of date.
I would still love to hear your feedback in the comments below. Enjoy!

At my workplace we use Mercurial. We don’t usually work in feature-branches, but in the default branch instead. This is usually not problematic, but I keep running into the following situation: I started working on feature A (on the default branch), when suddenly I am forced to work on (and ship) feature B instead, for whatever reason. When that happens, I usually say to myself “God damn it! I wish I worked on A in a branch to begin with!”.

Enter hg rebase. Here’s what you do.

First, let’s create a small repo and work on some task:

$ hg init repo 
$ cd repo/ 
$ touch readme 
$ hg add adding readme 
$ hg commit -m "add readme" 
$ echo "task 1" > task.txt 
$ hg add adding task.txt 
$ hg commit -m "work on task 1" 
$ echo "task 1" >> task.txt 
$ hg commit -m "work some more on task 1" 

Here’s how our log looks like now:

$ hg log
changeset: 2:729895012a70
tag: tip
user: nurdok
date: Sun Dec 23 13:20:38 2012 -0800
summary: work some more on task 1

changeset: 1:f71e084223c8
user: nurdok
date: Sun Dec 23 13:20:15 2012 -0800
summary: work on task 1

changeset: 0:ac29a6da9b78
user: nurdok
date: Sun Dec 23 13:18:12 2012 -0800
summary: add readme

Now let’s say we didn’t finish working on task 1 and for some reason we need to put it aside and start working on a different task. We want to move changesets 1 and 2 to a branch for a while. Here’s how to do it:

First, we need to create the branch we want to transfer them to, at the correct point (which is revision 0):

$ hg update -r0
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg branch task-1
marked working directory as branch task-1
(branches are permanent and global, did you want a bookmark?)

Now we need to create an “empty” commit for the branch. This is needed because as of now the branch doesn’t really exist and it needs to, for the rebase command to work. If you want to transfer the commits to an existing branch (that has some commits already), you don’t need this step.

$ hg commit -m "created task-1 branch"

Now, all there’s left is to perform the rebase command:

$ hg rebase --base 1 --dest 3
saved backup bundle to /home/rachum/repo/.hg/strip-backup/f71e084223c8-backup.hg

The --dest option is where to “stick” the changesets and the --base option defines the changesets that will be moved (it selects the first common ancestor with the revision specified in --dest and downwards). Here’s how our log looks like now:

$ hg log
changeset: 3:79318074f4a9
branch: task-1
tag: tip
user: nurdok
date: Sun Dec 23 13:20:38 2012 -0800
summary: work some more on task 1

changeset: 2:a9d9c50a1bdb
branch: task-1
user: nurdok
date: Sun Dec 23 13:20:15 2012 -0800
summary: work on task 1

changeset: 1:25e0d60da309
branch: task-1
user: nurdok
date: Sun Dec 23 13:23:07 2012 -0800
summary: created task-1 branch

changeset: 0:ac29a6da9b78
user: nurdok
date: Sun Dec 23 13:18:12 2012 -0800
summary: add readme

We stored task-1 away and we can start working on other stuff in the default branch.

Discuss this post at the comment section below.
Follow me on Twitter and Facebook

Similar Posts