HOWTO See what’s changed in the file you’re editing in Emacs

Warning: Geek threshold exceeded. If you don’t know what Emacs is, this post will mean nothing to you.

I use Emacs as my primary editor these days, and I tend to have lots of buffers open at once. Every so often, I’ll go to close Emacs or just close some buffers, only to be alerted “Buffer XYZ modified; kill anyway? (y or n).

What? I opened that buffer 3 days ago. I don’t know if I should save those changes… what changed? Now, my copy of XEmacs has ediff, a very nice interactive diff tool. You can diff two buffers, two files, three files, buffers against revisions (if the file is under source code control), etc. What you can’t do is diff a buffer against the underlying file on the file system.

Now, I could save the buffer in question to a temporary location, and then ediff that against the original. But where’s the elegance in that? I wanted a better solution, so I asked Google.

I found the answer (well, most of it) in a 1996 post to comp.emacs by Larry Rosenberg. He offered a function for doing a quick diff of the current buffer against the underlying file system version. I bound this C-c d in emacs. I then expanded it just a bit. I often use context-diffs (diff -c), so I wanted the option, but for long lists of diffs, sometimes it’s just too much. So, I made it an option of the command. Invoked normally, it shows a plain diff. When prefixed with C-u (using my binding, this becomes C-u C-c d), it runs a context diff.

Just to be clear – Larry did all the real work back in 1996. But considering my understanding of elisp is only slightly better than my understanding of Sandskrit, I’m pleased with my modification.

Here’s the function definition, along with the keybinding, from my emacs init file:

(defun diff-buffer-against-file (context)
    "diff the current [edited] buffer and the file of the same name"
    (interactive "P")
    (let (  ($file buffer-file-name)
            ($tempFile "/tmp/emacs.diff")
            ($tempBuffer "emacs.diff"))
        (delete-other-windows)
        (push-mark (point) t)
        (generate-new-buffer $tempFile)
        (copy-to-buffer $tempBuffer (point-min) (point-max))
        (set-buffer $tempBuffer)
        (write-file $tempFile)
        (shell-command (concat (if context "diff -c " "diff ") $file " " $tempFile))
        (kill-buffer $tempFile)
        (pop-mark)
    )
)

(global-set-key "\C-cd" 'diff-buffer-against-file)

Both comments and pings are currently closed.

One Response to “HOWTO See what’s changed in the file you’re editing in Emacs”

  1. John Watson Says:

    Looks like emacs has diff-buffer-with-file now (was this before or after your post? I dont’ know). But I was itching for an ediff command personally (I like the pretty colors):

    (defun ediff-buffer-against-file (file)
    “diff the current [edited] buffer and the file of the same name”
    (interactive
    (list (ediff-read-file-name
    “File to compare:” default-directory buffer-file-name)))
    (let ((buf-buf-name (buffer-name))
    (file-buf-name (create-file-buffer file)))
    (with-current-buffer file-buf-name
    (insert-file-contents file t nil nil t))
    (ediff-buffers buf-buf-name file-buf-name)))