git jump with Emacs
Git version 1.7.8, which is shortly to be released at this writing,
contains a handy new program
git jump. The idea is that you
can say things like
git jump diff to have your
$EDITOR go directly to
the lines within your files that contain unstaged changes.
The central idea of
git jump is that it relies on Vim’s notion of
“quickfix” files. Conventional usage of quickfix files is to run a
compiler on your code, saving its error messages into a file; then you
vim -q error-file, and Vim helps you step through the list of
errors and fix them. In particular, you needn’t manually open the right
files and then jump to the location flagged by the compiler.
git jump merely generates a file with a list of relevant code
locations, in a fairly standard format for compiler error messages, then
$EDITOR -q on that file. Building on the existing quickfix
mechanism in this way is a pretty good design, I think.
Emacs has a feature broadly equivalent to Vim quickfix files, but the other
way round. Where Vim expects you to run the compiler outside the editor,
saving its error messages to a file, Emacs encourages you to run the compiler
inside the editor. The error messages are saved directly into an Emacs
compile-mode buffer, whence you can step through them in much
the same way as with quickfix locations in Vim.
git jump with Emacs, then, is just a matter of finding a way to get
compile-mode to treat the relevant quickfix file as compiler output.
Fortunately, that’s not too hard. First we’ll need a new Emacs function
that treats a named file as if it were compiler output; and then we’ll need
to make sure that
$EDITOR -q invokes that function appropriately.
Start by adding this Emacs function to your
~/.emacs (or equivalent):
(defun quickfix-open (files) (setq-default compilation-directory default-directory) (compilation-start (concat "cat " (mapconcat #'shell-quote-argument files " "))))
That defines a function
quickfix-open which takes a list of filenames, and
starts a compilation with a command that just runs
cat on those filenames.
The script is just slightly more tricky. I’m going to assume that you use
emacsclient (which lets you open files in a running Emacs
process). The script will therefore run
emacsclient directly by default,
but if it receives the
-q option, it will use
emacsclient -e expression
to evaluate a suitable Lisp expression in the running Emacs. Since we
quickfix-open, we’ll just need to invoke it on the relevant
There’s one additional wrinkle: when I was testing this, I found that by the
cat, the temporary quickfix file created by
git jump had already been deleted. So instead of passing the quickfix
file to Emacs directly, we’ll save the data into a separate file, and then
pass that. For simplicity, I’m just going to store the quickfix data in
~/.quickfix; that means you can’t quickfix two separate
git jump lists
simultaneously, but that doesn’t seem like a problem in practice.
So, a very simple implementation of this script might look like this:
#! /bin/sh if [ $1 != -q ]; then exec emacsclient "$@" else shift qf=$HOME/.quickfix cat "$@" > "$qf" exec emacsclient -e "(quickfix-open '(\"$qf\"))" fi
Save that as, for example,
~/bin/e, and change your shell configuration to
EDITOR=$HOME/bin/e, and now you should be able to use
git jump at
will. Share and enjoy!