Brain Phrye

code cooking diy fiction personal photos politics reviews tools 


Git Commit Message Spell Check

[ Listen to article ]

Spell checking git commit messages turns out to be oddly hard.

The hook to do it in is commit-msg but there are a few problems. First is making global hooks and second is doing the checking.

One might argue that you can just do this in your editor, but I usually use the -m flag on git commit so no editor gets a whack at it. Since that trick won’t really work, what are the other options?

To make global hooks, you can just do git config --global core.hooksPath ~/.config/git/hooks but that will override all hooks. Any repo specific hooks won’t be run. Which is not what I want. So I made shim scripts like this for hook scripts I’d use in a local repo - this is for pre-commit:

1
2
3
4
5
6
#!/bin/sh

self=pre-commit
if [ -f "$GIT_DIR/hooks/$self" ]; then
  exec "$GIT_DIR/hooks/$self" "$@"
fi

For the commit-msg script it turns out you can’t run any interactive program. Luckily you can run aspell non-interactively, but this means there need to be some utility programs. This is the global commit-msg script I came up with:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/sh

if ! type aspell > /dev/null; then
  echo "Warning: aspell is not installed"
  exit
fi

words="$(grep -v '^#' "$1" \
         | aspell "--personal=$HOME/.config/git/.dict.en.pws" list)"
if [ -n "$words" ]; then
  cmd="git"
  msg="$1"
  vcsh_repo="$VCSH_REPO_NAME"
  if [ -z "$VCSH_REPO_NAME" ]; then
    vcsh_repo="$VCSH_DIRECTORY"
  fi
  if [ -n "$vcsh_repo" ]; then
    if [ "$vcsh_repo" = past ]; then
      exit
    fi
    cmd="vcsh $vcsh_repo"
    msg="$HOME/$1"
  fi
  echo "Error: The following words are misspelled"
  echo "$words" | sed 's/^/  /'
  echo "To add words: $cmd spell-add WORD"
  echo "To spell check commit message: $cmd spell-check"
  echo "To reuse the commit message: $cmd ci -F '$msg'"
  exit 1
fi

self=commit-msg
if [ -f "$GIT_DIR/hooks/$self" ]; then
  exec "$GIT_DIR/hooks/$self" "$@"
fi

Note that these aren’t bash scripts - for various reasons some systems I work on don’t have bash or have it in different places. So it’s just plain POSIX shell. And in spite of shellcheck’s concerns, every modern POSIX shell I’ve used knows $() and type.

This is mostly generic though the vcsh bits are specific to me. I have a past repo that I do automatic commits to. They have path and hostnames in them so no need for spellchecking there.

The two utility programs mentioned in it - git-spell-add and git-spell-check - are, respectively, as follows:

1
2
3
4
5
6
7
8
9
#!/bin/sh

if [ -z "$*" ]; then
  exit
fi

for word in "$@"; do
  echo "$word" >> "$HOME/.config/git/.dict.en.pws"
done
1
2
3
4
5
6
7
#!/bin/sh

file="$1"
if [ -z "$file" ]; then
  file="$(git rev-parse --git-dir)"/COMMIT_EDITMSG
fi
aspell "--personal=$HOME/.config/git/.dict.en.pws" check "$file"

So far it’s worked well. It’s caught a few typos and hasn’t been too intrusive. Depending just on an error message and not hanging to force me to do something is annoying. I’m going to need to get used to git ci sometimes failing. But it would be nice not to have typos locked in forever!