hg stash

2011-02-28 21:34:32 -0800

I have become accustomed in Git to using git stash to temporarily set aside in-progress changes in my working directory before pulling from upstream. Whenever I use Mercurial now, I find myself wanting analogous functionality. The Googles don't seem to turn up any decent techniques for this, so I have repeatedly reinvented a series incantations to abuse Mercurial's mq extension to provide it. Yet I always manage to forget whatever trick I used by the time I want to do it again. I finally decided to fix it for good, giving myself hg stash and hg pop, allowing a workflow in a dirty working copy that goes something like:

hg stash
hg fetch
hg pop

Here are the relevant .hgrc lines:

[alias]
stash = !hg qinit &>2 /dev/null; hg qqueue --create stash-temp && hg qnew stash && hg qfinish tip && hg strip tip && hg qqueue patches && hg qqueue --purge stash-temp
pop = !hg -R .hg/strip-backup/`ls -rt .hg/strip-backup/ | tail -1` diff -r tip | patch -p 1 -R

Breaking it down:

# hg stash
hg qinit &>2 /dev/null              # initialize mqueue in this directory
                                    # ignore error output since this has likely already been done
                                    # (this could be potentially be problematic if there is some other problem)
hg qqueue --create stash-temp       # create a new patch queue so we don't mess with any existing ones
hg qnew stash                       # create the 'stash' patch with the outstanding modifications
hg qfinish tip                      # apply the patch
hg strip tip                        # now strip it (for the side-effect of the backup bundle)
hg qqueue patches                   # switch back to original patch queue
hg qqueue --purge stash-temp        # delete the temporary patch queue
# hg pop
hg -R .hg/strip-backup/`ls -rt .hg/strip-backup/ | tail -1`     # use the strip bundle as the repository
                                                                # finding it with some shell tricks
                                                                # (likely a better, more portable way to do this)
diff -r tip                                                     # output it as a diff
patch -p 1 -R                                                   # apply that output as a patch
                                                                # and reverse patch since we spun things around
                                                                # with the bundle

Your working copy's .hg/strip-backup/ directory could start to fill up if you use this a lot, so you may want to clean it out occasionally. I decided to not have hg pop automatically cleanup the bundle just in case something goes wrong.

And why not just hg diff > stash.diff && hg revert --all to stash and patch -p 1 < stash.diff to pop? That doesn't really handle binaries, and somehow it feels a little too dangerous to me. But, yeah, for the majority of cases that would probably be sufficient. So I'll leave that here, too:

[alias]
stash = !hg diff > stash.diff && hg revert --all
pop = !patch -p 1