MQ to Changeset Evolution: A Dummy Guide

So, not having had time to post on here for a long time. I realized there's a problem a bunch of us at Mozilla are facing, we've been using mercurial queues for I don't know how long, but we're increasingly facing a toolchain that isn't compatible with the MQ workflow. I found patches in my queue inadvertently being converted into actual commits and other such things. I'm no expert on versioning systems, and as such mercurial queues provided me with an easy method of just having a bunch of patches, and a file which orders them, and that was easy for me to understand and work with. Seeing an increasing amount of tools not supporting it though, I decided to make the switch, and I'd like to document my experience here, some of my suggestions may not be optimal, please let me know if any of my suggestions are unwise. I also use Windows as my primary OS, mileage on other operating systems may vary, but hopefully not by much.

First, preparation, make sure you've got the latest version of mercurial using ./mach bootstrap, when you get to the mercurial configuration wizard, enable all the history editing and evolve extensions, you will need them for this to work.

Now, to go through the commands, first, the basics:

hg qnew basically just becomes hg ci we're going to assume none of our commits are necessarily permanent, and we're fine having hidden, dead branches in our repository.

hg qqueue is largely replaced by hg bookmark, it allows you to create a new 'bookmarked branch', list the bookmarked branches and which is active. An important difference is that a bookmark describes the tips of the different branches. Making new commits on top of a bookmark will migrate the bookmark along with that commit.

hg up [bookmark name] will activate a different bookmark, hopping to the tip of that branch.

hg qpop once you've created a new commit becomes hg prev an important thing to note is that unlike with qpop, 'tip' will remain the tip of your current bookmark. Note that unlike with qpop, you can 'prev' right past the root of your patch set and through the destination repository, so make sure you're at the right changeset! It's also important to note this deactivates the current bookmark.

Once you've popped all the way to the tree you're working on top of, you can just use hg ci and hg bookmark again to start a new bookmarked branch (or queue, if you will).

hg qpush when you haven't made any changes bascially becomes hg next, it will take you to the next changeset, if there's multiple branches coming off here, it will offer you a prompt to select which one you'd like to continue on.

Making changes inside a queue

Now this is where it gets a little more complicated, there's essentially two ways one could make changes to an existing queue, first, there is the most common action of changing an existing changeset in the queue, this is fairly straightforward:

  • Use `hg prev` to go to the changeset you wish to modify, much like in mq
  • Make your changes and use `hg ci --amend` much like you would `hg qref`, this will orphan its existing children
  • Use `hg next --evolve` as a qpush for your changesets, this will rebase them back on top of your change, and offer a 3-way merging tool if needed.

In short qpop, make change, qref, qpush becomes prev, make change, ci --amend, next --evolve.

The second method to make changes inside a queue is to add a changeset inbetween two changesets already in the queue. In the past this was straightforward, you qpopped, made changes, qnewed, and just happily qpushed the rest of your queue on top of it, the new method is this:

  • Use `hg prev` to go to the changeset you wish to modify, much like in mq
  • Make your changes and use `hg ci ` much like you would `hg qnew`, this will create a new branching point
  • Use `hg rebase -b [bookmark name/revision]`, this will rebase your queue back on top of your change, and offer a 3-way merging tool if needed.
  • Use `hg next` to go back down your 'queue'


Basically hg qfin is no longer needed, you go to the changeset where you want to push and you can push up until that changeset directly to, for example, central. ./mach try also seems to work as expected and submits the changeset you're currently at.

Some additional tips

The hg absorb extension I've found to be quite powerful in combination with the new system, particularly when processing review comments. Essentially you can make a bunch of changes from the tip of your patch queue, execute the command, and based on where the changes are it will attempt to figure out which commits they belong to, and essentially amend these commits with the changes, without you ever having to leave the tip of your branch. This not only takes away a bunch of work, it also means you don't retouch all of the files affected by your queue, greatly reducing rebuild times.

I've found that being able to create additional branching points, or queues, if you will, off some existing work on occasion is a helpful addition to the abilities I had with mercurial queues.

Final Thoughts

In the end I like my versioning system not to get in the way of my work, I'm not necessarily convinced that the benefits outweigh the cost of learning a new system or the slightly more complex actions required for what to me are the more common operations. But with the extensions now available I can keep my workflow mostly the same, with the added benefit of hg absorb I hope this guide will make the transition easy enough that in the end most of us can be satisfied with the switch.

If I missed something, am in error somewhere, or if a better guide exists out there somewhere (I wasn't able to find one or I wouldn't have written this :-)), do let me know!


# Jan on 2019-02-03 at 10:52

Some additions:

* hg amend is a bit shorter than hg commit –amend and it doesn’t ask you to update the commit message.

* hg evolve is similar to hg next –evolve maybe?

* hg pick is great for pushing a random commit on top of whatever is current tip. Like qpush.

* hg pdiff is like MQ’s hg qdiff

* hg split/fold are nice. fold is a bit like MQ’s qfold.

* I actually rarely use bookmarks and prefer |hg wip| as configured by ./mach bootstrap.

# Steve Fink   on 2019-02-04 at 23:36

`hg evolve` handles a bunch of different things, and doesn’t advance you to the next patch. `hg evolve; hg next` is probably about the same as `hg next –evolve`. Personally, I have

next = –evolve

in my ~/.hgrc so I can just say `hg next`. I never wouldn’t want the –evolve; it won’t do anything if it doesn’t need to.

The biggest advantage of this workflow over mq is that merges work properly, so you get far fewer conflicts. `hg rebase -d inbound` is more likely to work than `hg pull –rebase` with mq, and vastly more likely to work than `hg qpop -a; hg pull -u; hg qpush -a`.

# Florian Qu├Ęze on 2019-02-11 at 12:28

If hg qref is in your muscle memory, you can just use hg ref instead, as “hg refresh” is conveniently an alias of hg amend.

This post has 1 feedback awaiting moderation...

Form is loading...

August 2022
Mon Tue Wed Thu Fri Sat Sun
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
 << <   > >>
Certain events have made me realise it's probably a good idea to have a 'blog' to share ideas and get feedback...


  XML Feeds