I've mentioned plenty of times that we use Mercurial at work. Well the other day Dowski mentioned that he started playing with Mercurial Queues (mq) and found it to be pretty helpful. As I'm always interested to see where these more advanced DVCS concepts lead, I gave it a try.
My basic use case is that I'm working on a feature and I have to change gears to work on something else. This usually involves pulling from the main repo, doing whatever new work I need to do and pushing it back before going back to where I left off. When using mq, the idea is that you are working on a set of patches locally that, when finished, you'll push or send to someone. The way these patches are organized is in a stack. Each patch gets a name and they can be applied in a specific order, with the age of the patch being the default.
So, the smart way to start would be to create a new patch for a new feature. In my case, this is rarely the case, so I have to figure out another way. I usually have some commits and a bunch of stuff I didn't commit just yet, so here's what I do:
> hg ci -m 'Commit my outstanding change before pulling'
> hg log -l 5 # check for the latest revision I want to effectively "rebase" to
> hg export -r $REV > working.patch
> hg strip $REV # this reverts the entire repo back to the point of the revision
> hg pull -U # get the latest
At this point my repo is all up to date and my only record of my previous work is my patch file I exported. Not very cool, so lets fix that first by storing my work in the queue.
> hg qinit -c # this versions the patch queue so you can save patches even after their done
> hg qnew -m 'Add my working patch for later' working-feature
> patch -i working.patch -p1
> hg qrefresh
While it make not be clear what happens is the patch gets saved on the queue in a patch called "working-feature". The qnew creates the patch, the changes are made and the qrefresh updates the current patch with the changes. It should also be noted that this updates the patch's changeset in the repo. These patches are actual changesets so you can use the other hg commands. The bisect command is usually given as a good example, but anything should work such as hg diff.
Now that I have patch in the queue, I can see what has happened.
> hg qapplied
This will tell me what patches have been applied. There are effectively two stacks involved. There is the applied stack and the series stack. The applied stack is considered to be applied to the repo, meaning the source files contain the changes in the patch. The series stack lists all the patches in the queue whether they have been applied or not.
In this example, I want to take my curent work, the working-feature patch, and not have it applied since the changes are unfinished. I then want to make changes for some other feature, commit them, push and finally start back where I left off.
> hg qpop # takes my currently applied patch and un-applies it, yet keeps it in available patches in the queue
> hg qnew -m 'A hotfix for production' fix-for-bug # create a new patch for my fix
# fix the bug!
> hg qrefresh # update my bug fix patch
> hg qnew -m 'Update the tests for the bug' fix-for-bug-tests # create patch updating the tests
# update the tests
> hg qrefresh # update my second patch
# ready to commit!
> hg qfinish fix-for-bug && hg qfinish fix-for-bug-tests
# another option
> hg qfinish -a # turn all the applied changesets into real commited changesets
> hg push
> hg qpush working-feature # back to where we left off
Things can obviously get more complicated than this, but off hand it makes a good deal of sense once you give it a try. I should also mention that there might be better ways to deal with external patches like I did initially. There is a qimport command (for example) that seems promising assuming you're working with patches people send.
The biggest benefit of using mq was that it was relatively painless to go back and make a new patch. This may seem like a small issue, but for me knowing that I can quickly save my work for later without branching or cloning is a huge win. My biggest complaint always ends up being that I've gone and written code, committed (b/c that is the point of being distributed) and found that I'll have to jump through hoops to only push a certain set of changes that are finished. MQ has always been presented as the way to handle my use cases, but experimenting never yielded the confidence to commit to using it. At this point, I feel much better about using mq consistently and integrating it into my workflow. Also, thanks to the folks in #mercurial on freenode for all the explanations and helping me wrap my head around what is happening.