20210416

Customizing Emacs for Git Commit Messages

 Customizing Emacs for Git Commit Messages

I do a lot of commits to the FreeBSD project and elsewhere. It would be nice if I could setup emacs in a custom way for each commit message that I'm editing.

Fortunately, GNU Emacs provides a nice way to do just that. While I likely could do some of these things with git commit hooks, I find this to be a little nicer.

First up, we need to do something when we pull up the commit message to edit. By convention, git uses the file COMMIT_EDITMSG, though the exact location of this file depends on where the git tree you have checked out is. Emacs has a hook that's run when emacs starts editing a file called 'find-file-hook'. So:
(add-hook 'find-file-hook 'imp-git-hook)

will do the job nicely. Next up, we need to define this function to do something useful when run (indeed, failure to define it will result in an error when visiting all files).

(defun imp-git-hook ()
  (when (string= (file-name-base buffer-file-name) "COMMIT_EDITMSG")
    (freebsd-git-setup))) 

buffer-file-name is a local variable that has the full path name to the buffer, if any. file-name-base is like basename(1) in that it returns the name of the file without the extension, rather than its whole path.

But what is 'freebsd-git-setup'? It's a little function I wrote to set the fill column to 72 (I usually have it at 80, but that produces commit messages that are just a bit wide when git adds leading spaces) and adds a sponsorship tag to my commits:

(defun freebsd-git-setup ()
 (save-excursion
  (setq fill-column 72)
  (if (re-search-forward "^Sponsored by:" nil t)
    t
   if (re-search-forward "^\n#" nil t)
    (replace-match "\nSponsored by:\t\tNetflix\n\n#")))))

But it only adds the sponsorship tag if one isn't there yet.

This is a proof-of-concept function. No doubt it will have to evolve over time. The project adds 'Differential Revision' tags as the last tag in a commit message because differential requires (required?) that. And it wouldn't be good to add this for non-FreeBSD commits, so I'll have to find a way to filter for that... But I thought this would be useful, if nothing else than to my future self as a roadmap for how to do things like this.


2 comments:

  1. Anonymous12:59 PM

    Nice. As someone who often screws up commit messages, I appreciate scripting out my forgetfulness.

    If you don't want to run a hook each time a file is found, you could set the GIT_EDTIOR environment variable. Here is a lightly tested example:

    GIT_EDITOR="emacs -nw -q --eval \"(custom-set-variables '(fill-column 72))\"" git commit

    ReplyDelete
  2. Or maybe better for your case is to only add the hook when defining GIT_COMMIT.

    Untested:

    GIT_EDITOR="emacs -nw --eval \"(add-hook 'find-file-hook 'imp-git-hook)\""

    ReplyDelete