An interactive, iterative ‘git blame’ mode for Emacs « mosu's tips & news from the Matroska world
An interactive, iterative ‘git blame’ mode for Emacs
Friday 23 October 2009 @ 4:10 pm

I’m an active user of Magit for all my Git needs within Emacs. One thing I’ve always found missing was nice support for ‘git blame’ — and by ‘nice’ I mean some more comfort than the simple display of its output.

When I’m hunting bugs one thing I often need is not only the information who modified a certain line but also who modified the line before that. Also what I’d like is having both the source code (including syntax highlighting, of course) and the blame information shown side-by-side with quick access to the log message for particular commits.

That’s what ‘mo-git-blame’ tries to solve. It is a standalone mode that can be used with any of the various Git version control modes. Here are a couple of its features:

  • Shows the output of ‘git blame’ and the file content side-by-side with syntax highlighting for the content
  • Show the log messages for the current revision or the revision in the current line
  • Show the diff (via ‘git show’) for the current revision or the revision in the current line
  • Show the file content for the revision in the current line
  • Call ‘git blame’ for the same file for the revision in the current line

Here’s what it looks like:

Screenshot of Emacs with mo-git-blame-mode

Screenshot of Emacs with mo-git-blame-mode

You can download the sources from my Git repository or directly with

  1. git clone git://github.com/mbunkus/mo-git-blame.git

Installation and usage instructions are included both in the file itself and its README, but here’s the short version:

  1. (add-to-list 'load-path "~/.emacs.d/mo-git-blame")
  2. (autoload 'mo-git-blame-file "mo-git-blame" nil t)
  3. (autoload 'mo-git-blame-current "mo-git-blame" nil t)
Tags: , ,

Comments (16) - Posted in Programming by  



 16 responses to “An interactive, iterative ‘git blame’ mode for Emacs”

  •   Alexey Voinov wrote:

    Great job. Uploaded this to github (http://github.com/voins/mo-git-blame). There will be patches. :)

  •   shjk wrote:

    How does this differ from vc-annotate (which does support git in recent emacs versions)?

  •   Philip Weaver wrote:

    So then… could this be integrated into Magit?

    •   mosu wrote:

      As magit doesn’t have a full-blown file manager (meaning it only shows modified files) such an integration would be limited to the files it actually lists as modified. That isn’t hard to do; basically a function that checks whether or not point is at a file and use that file’s name for mo-git-blame. I’ll try to write that up next week.

      Or did you have something else in mind?

  •   phil wrote:

    To be honest, I doubt it. It doesn’t quite fit. I’d be happy to stick a recommendation for it in the manual though.

    •   mosu wrote:

      That’s what I thought as well and why I didn’t try to integrate it before — even with such a simple method as I outlined in the comment above.

  •   nico wrote:

    This looks great.

    But is it possible that it does not cope with hard symlinks? Because of several reasons we have to link to our git repo this way (chroot). Then when I try mo-git-blame-current the following error is shown:

    fatal: Not a valid object name d7912b8:../../../../../home/nick/src/modules/Affiliate/Actions/CRUD.pm

    But Magit itself shows no problems.

  •   Dave Abrahams wrote:

    Not workin’ for me on MacOSX with Emacs 23.2; it hangs emacs waiting for the git blame command to finish, and if I kill the git command Emacs remains hung so I have to kill it too. Interestingly, the git command it hangs on works just fine from the command-line!

  •   DaveAbrahams wrote:

    The MacOSX problems are fixed, but frankly I’m a little perplexed as to how to use this. I ran it, and I wanted to find out who (and which commit) was responsible for a given line of source, but I didn’t see a way to do that. What am I missing?

    •   mosu wrote:

      First, visit the file you want to blame. Then execute `mo-git-blame-current’. This works best if you have only one window shown.

      MGB will split that window into two: the left one will show the output of “git blame –interactive”, the right one will contain the file content at the revision you’re blaming for. Initially this is the same revision your HEAD is at, but you can re-blame for other revisions by pressing some of the keys listed in the help for `mo-git-blame-current’ (or the mode’s key map).

      Whenever you scroll either of the two windows the other will be scrolled by the same amount.

      Is this enough to get you started?

      •   DaveAbrahams wrote:

        Well, it’s still not working for me. The latest problem is, when I visit the file and invoke mo-git-blame-current, I get this:

        fatal: ‘../../../../../../../Users/dave/src/llvm/tools/clang/lib/Sema/SemaExpr.cpp’ is outside repository.

        Oh, weird. There’s a directory symlink in the path to the file **above the repository directory** and that confuses mo-git-blame. If I open it by its canonical name, it works. Maybe you could make mo-git-blame more resilient to this

  •   DaveAbrahams wrote:

    One further thing: I have diff-mode-read-only set, and once I hit `RET’ in the buffer with the revision numbers, I can’t do it again until I kill the diff buffer.

  •   DaveAbrahams wrote:

    Hmm, scrolling in the mo-git-blame buffer seems to be indiscriminately scrolling whatever buffer happens to be in the other window. Should I start posting issues at https://github.com/mbunkus/mo-git-blame/issues ?