Git patches in Gnus

I took over maintaining the Linux kernel’s MMC/SD/SDIO subsystem recently, and quickly found that I was spending too much time saving, applying and compile-testing submitted patches (and trying to remember which of these I’d done for a given patch). The following Emacs/Gnus function helps with that — with a single keypress when looking at a mail that contains a patch, it applies the patch to my git tree, runs the kernel’s “checkpatch” tool to check for common errors, and kicks off a compile test in the background. I’m not much of an elisp coder, so feel free to critique it if you can.

(defun apply-mmc-patch ()
    "Take a gnus patch: apply; compile-test; checkpatch."
    (interactive)
    (setq default-directory "/home/cjb/git/mmc/")
    (setq compilation-directory "/home/cjb/git/mmc/")
    ; First, apply the patch.
    (dvc-gnus-article-apply-patch 2)
    ; Run 'git format-patch', and save the filename.
    (let ((patchfile (dvc-run-dvc-sync
        'xgit (delq nil (list "format-patch" "-k" "-1"))
        :finished 'dvc-output-buffer-handler)))
      ; Compile the result.
      (compile "make modules")
      ; Now run checkpatch.
      (let ((exit-code (call-process "perl" nil nil nil
                     "scripts/checkpatch.pl"
                     patchfile)))
    (if (eq exit-code 0)
        (message "Checkpatch: OK")
      (message "Checkpatch: Failed")))))

(define-key gnus-summary-mode-map "A" 'apply-mmc-patch)

Productivity

The main purpose of this post is to show off a link I found documenting some of the under-used features of emacs — Effective Emacs. (Thanks to Edward O’Connor’s blog for the link.)

I’ve been on an optimisation binge recently, making sure that I’m getting the best out of my editor and shell. I decided to document some of the features I’m using:

zsh:

  • Hostname completion based on the contents of your ~/.ssh/known_hosts file. This requires you to turn off HashKnownHosts (see below), and add the following to your ~/.zshrc:
       hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[0-9]*}%%*}%%,*})
       zstyle ':completion:*:hosts' hosts $hosts
  • Remote filename completion over ssh, which works wonderfully with public key auth, remote host completion, and the ssh ControlMaster tip below. This is enabled by default; an example use is below, with the bold characters written by tab presses rather than by my keyboard directly:

    % scp foo.html printf.net:public_html/index.html

  • Colour matches in grep results (in green):

    export GREP_COLOR='01;32'
    alias grep='grep --color'
    
  • pushd: Few people seem to use directory stacks in their shell. After enabling auto_pushd as below, you can quickly popd back to the last directory you were in (and popd again for the directory before that, etc), or use dirs to see the stack of past directories that you can cd to using cd ~n, where n is the number given for that directory. To enable:

    setopt auto_pushd
    
  • The <() construct lets you avoid having to use temporary files as arguments to commands, like so:

    diff -y <(wc -l 1/*) <(wc -l 2/*)
    
  • zsh's cd has a useful three-argument syntax where the third argument is treated as a replacement for the portion of the current directory given in the second argument:

    ~/dir % ls
    foo1  foo2  foo3  foo4  foo5  foo6
    ~/dir % cd foo5
    ~/dir/foo5 % cd 5 6
    ~/dir/foo6 %
    

ssh:

  • By default, modern ssh hashes the known_hosts file so that someone who hacks access to your account doesn't have a list of where they might be able to go next. This is sensible, but breaks the hostname completion above, so I turn it off in ~/.ssh/config:

    HashKnownHosts no
    
  • New (4.0+) versions of OpenSSH have support for multiplexing several shells over a single ssh connection; this means that the second time you type ssh host, the first (already established) connection is used and told to spawn a new shell, making your new shell appear immediately instead of in a few seconds. This cuts login time for a new shell from 1.891s to 0.267s on my work machine. It also speeds up anything that uses a single ssh session per file such as bash/zsh remote filename completion (see above), or rsync/darcs/svn/etc over ssh. To enable, in ~/.ssh/config:

    ControlMaster auto
    ControlPath /tmp/%r@%h:%p
    

I have a few annoyances with ControlMaster — let me know if you know of a clean way to have the first connection for each host be created as a background process without a tty so that it can't easily be killed by accident.

emacs:

  • I use tramp to edit files remotely — this has the same host and filename completion as zsh, and is insanely useful for me; some of the machines I use at work are an ssh tunnel away (meaning high latency) and don't have emacs or vim installed (only vi, meaning no syntax highlighting). Setting up tramp is easy:

    (require 'tramp)
    C-x C-f /somehost:some/dir/and/file RET
    
  • I use gnus (see also my.gnus.org) for mail, news and RSS reading, and think it's the best mailer ever.

  • I use ERC as an IRC client.

My dotfiles are available online.