emacs mercurial

Setting default-directory for Mercurial MQ patches in Emacs

Emacs’ diff-mode is a great tool to work with patches. You can move inside a patch by files or by hunks, it highlights the changes in each line and you can apply and revert individual hunks. However, diff-mode doesn’t work out-of-the-box with Mercurial’s MQ extension. To make it work, we first have to make Emacs recognize an MQ patch automatically like this:

(add-to-list 'auto-mode-alist '("\\.hg/patches/" . diff-mode))

However, applying and reverting hunks will not work, because Emacs can not find the files mentioned in the patch, as it assumes that the paths are more or less relative to where the patch file lies. To fix this we add a function to diff-mode-hook:

(defun mq-patch-set-default-directory ()
  (when (string= ".hg" (nth 2 (reverse (split-string default-directory "/"))))
    (setq default-directory (expand-file-name (concat default-directory "../../")))))
(add-hook 'diff-mode-hook 'mq-patch-set-default-directory)

A possible usage scenario for diff-mode with MQ could be that you want to apply parts of an (unapplied) MQ patch to your working copy, maybe because the patch as a whole doesn’t work anymore or you want to throw it away and only intend to keep a few bits of it.

Whatever you’re doing with this, I hope you’ll find it useful.


  1. Thanks for this tip – it is really useful when applying hunks.
    However there is one frustrating side effect: if I do C-x C-f (find-file) while visiting a patch file, the directory that is shown in the mini buffer becomes the parent of .hg. This is frustrating when the original intent is to open another patch file so I have to cd back to .hg/patches/. Is there a way apply this trick only for diff-mode but not to find-file?
    Thank you,

  2. Good point. I’m using dired-jump from dired-x, so this isn’t a problem for me. It would be cleaner, but also more complex, to override default-directory only when applying hunks and for diff-goto-source. You could do that with some around advice.

Leave a Reply

Your email address will not be published. Required fields are marked *