Updating Your Mercurial Repository

... while working on uncommitted changes.

Sometimes when you are working on a fix - or an RFE, you'd like to sync-up with your parent's repository and pull any changes it contains without having to commit your own work in progress. Here is my own recipe - direct from my mercurial cookbook.

First you will need to make sure that the mq and fetch extensions are enabled in your .hgrc file. Ok, you don't really need fetch - you can do with the pull/update/merge/commit sequence - but personally I like fetch better. To enable mq and fetch, simply put those two lines under [extensions] in your .hgrc:


Although I am not very comfortable with mq, since I don't speak diff & patch fluently, I have found it very useful for this use case. I am sure that mq is much more powerful than what my clumsy usage use it for - but I am now rather comfortable with the way I use it in this use case.

The idea is as follows:

  1. Use hg status and zip to create a zip file containing all the files in which you have uncommitted changes. This is just in case something goes wrong.
  2. Use mq to create a patch file for those changes, and to unapply them so that you get back a clean repository in which you can pull the parent updates.
  3. Use hg fetch to pull the changes from the parent repository.
  4. Use the patch generated by mq in order to reapply your uncommitted changes, leaving them uncommitted, just as they were before. This is the part that may fail, and we have saved a copy of the files you were working on in a zip just for that case.

Before you start this sequence however - make sure to add all the new files you have created to mercurial. You can use hg status -nu to list all the files that are not tracked by mercurial yet. If any of these is part of your changes, add it to mercurial using hg add. This will make sure that this file is also included in the patch that we will generate using mq later on.
Then try hg status -ma. Check that all the files listed are part of your changes and that nothing is missing. If everything is OK, choose a name for labelling your work in progress. Something without whitespaces in it of course - since we will use this name for our zip and patch files - let's say you've decided to name it MyChanges. When this is done, you are ready to roll!

    # make a Zip of your changes - just to be safe 
    # (Note: the command below is in bash syntax)
    zip -r MyChanges.zip $(hg status -nma)
    # create a patch containing your changes
    hg qnew -f MyChanges
    # 'unapply' the patch, leaving the repository with
    # no uncommitted changes.
    hg qpop -a
    # Now hg status should see no uncommitted changes.
    # and hg heads  should see only one head (tip)
    # now pull & update & merge
    hg fetch
    # now reapply the patch, to get back your changes as
    # new uncommitted changes:
    gpatch -p 1 < .hg/patches/MyChanges

There should be no problem applying the patch created by mq in .hg/patches/MyChanges provided that none of the files you were working on was modified by someone else in the parent repository. If one of these files had been modified by someone else, then it is likely that the gpatch command will fail to update that file. If it does, it will create a file.rej file for each file in which the patch couldn't be applied.

So if any .rej file is created by gpatch (don't worry, it will tell you if it creates any), then you will need to merge your changes in the correponding file manually. The easiest way to do that - unless you speak diff and patch fluently, is to expand the MyChanges.zip file somewhere else, and then use your favorite interactive merge tool - for instance the good old filemerge from Teamware, to reintroduce your changes in that file.

At the end - you should have an updated repository again containing your uncommitted changes - on which you can continue working as if nothing had happened.

If, after a while, you need to update again, you can redo that whole sequence. Just make sure to use a new name for your changes - for instance, MyChanges2.

Well, that's my own recipe. I realize I might not be using the full power of mq, but it has worked for me until now...

I hope it might help you too!




With mq, fetch is (almost) useless, coz you never merge anymore.

There's a nice post on dealing with .rej files at http://gnuarch.org/gnuarchwiki/Process_\*.rej_files, Yes, it's emacs, but at least it tells you what .rej files are.

Why call gpatch instead of qpush? You can still fix the .reg hunks and do a qrefresh to update your patch file.

Posted by Weijun on April 22, 2008 at 11:15 AM CEST #

I haven't tried qpush yet. Maybe I should give it a try...
If I do qpush and just after hg status - what will I see? A list of modified files, or nothing?
I don't like qrefresh much because after qrefresh hg status no longer shows anything... And I like to see the list of files I've been working on with hg status...
Thanks for the suggestion anyway, I'll try it!
-- daniel

Posted by daniel on April 22, 2008 at 04:35 PM CEST #

qpush is similar to commit, it creates a new changeset, only managed by mq. I regard it as a safe commit, because with qpop/qpush, you can always remove/reapply the patch without fearing it will break anything.

After a qpush, hg status shows nothing.

Yes, after qrefresh, hg status shows nothing. But, that's what mq is meant for, saving the current changes into a patch file so that you can start another patch by calling qnew again. That's what a queue does anyway. If you start working on several bugs at the same time, you'll realize the benifit of it.

Posted by Weijun on April 22, 2008 at 06:44 PM CEST #

I've found "hg qdiff" very handy for looking at the changes that are going on inside a mq managed patch.

Posted by Tim Harris on April 01, 2010 at 09:49 AM CEST #

Post a Comment:
Comments are closed for this entry.

Daniel Fuchs blogs on Scene Builder, JMX, SNMP, Java, etc...

The views expressed on this blog are those of the author and do not necessarily reflect the views of Oracle.


« June 2016