Mercurial Rebase

I read Martin Fowler’s entry on using mqueues in Mercurial to squash a series of commits into a single commit, and while the post is informative, there’s an easier way: the Mercurial rebase command.

The rebase extension has been included in Mercurial since 1.3, although it’s been available since sometime in the 1.2 release, and can perform a number of useful alterations of a repository. For Martin’s use case, his 5-step mqueue sequence is accomplished with two much more simple commands:

hg tag "Pre-rebase"
hg rebase -s  --collapse

The tag is necessary because the rebase command will not operate on descendants or ancestor, and will not automatically create a new tip to hold the rebase. It’d be nice to be able to dispense with the tag, and it isn’t necessary if you’re (for example) rebasing from a branch onto another branch which already has other changes – the key point here is that you need to have a different tip that you’re rebasing onto which isn’t either an ancestor or descendant of the branch that you’re rebasing.

Here’s a simple use case. First, I’ll set up the repository:

% mkdir squash
% cd squash
% hg init
% echo AAA > A
% echo BBB > B
% echo CCC > C
% echo DDD > D
% hg addremove
adding A
adding B
adding C
adding D
% hg ci -m 1
% hg mv A M
% hg ci -m 2
% hg mv B N
% hg ci -m 3
% hg mv C O
% hg ci -m 4
% hg mv D P
% hg ci -m 5
% hg glog
@ changeset: 4:347a96580b84
| tag: tip
| user: Sean Russell
| date: Wed Jul 15 07:26:40 2009 -0400
| summary: 5
|
o changeset: 3:e1e2c4e27fcf
| user: Sean Russell
| date: Wed Jul 15 07:26:34 2009 -0400
| summary: 4
|
o changeset: 2:47b3a7f41d78
| user: Sean Russell
| date: Wed Jul 15 07:26:28 2009 -0400
| summary: 3
|
o changeset: 1:e0879f674e71
| user: Sean Russell
| date: Wed Jul 15 07:26:24 2009 -0400
| summary: 2
|
o changeset: 0:2902dfa1725a
user: Sean Russell
date: Wed Jul 15 07:26:12 2009 -0400
summary: 1

Here’s the actual rebase. First, switch to the revision that you want to rebase [onto]{style=“font-style: italic;”}, then create a tag to create a new tip, then perform the rebase. In this example, I want to collapse revisions 1-4, so I switch to revision 0:

% hg up 0
4 files updated, 0 files merged, 4 files removed, 0 files
unresolved
% hg tag Pre-collapse
% hg rebase -s 1 --collapse
saving bundle to /home/ser/squash/.hg/strip-backup/e0879f674e71-temp
adding branch
adding changesets
adding manifests
adding file changes
added 2 changesets with 5 changes to 5 files
rebase completed
% hg glog
@ changeset: 2:3420d5add3eb
| tag: tip
| user: Sean Russell 
| date: Wed Jul 15 07:26:40 2009 -0400
| summary: Collapsed revision
|
o changeset: 1:a98523a2e8f9
| user: Sean Russell 
| date: Wed Jul 15 07:26:50 2009 -0400
| summary: Added tag Pre-collapse for changeset 2902dfa1725a
|
o changeset: 0:2902dfa1725a
| tag: Pre-collapse
| user: Sean Russell 
| date: Wed Jul 15 07:26:12 2009 -0400
| summary: 1

The rebase command is quite useful, and the rebase page gives examples of a number of use cases. For cases like this, it’s much easier than using the raw mqueue operations upon which it is based.