Dustin Ingram


The Problem

When debugging a failing test using pytest, I often add a “focus mark” to tests which I’m currently working on, so that it’s easy to run them over and over without running all the tests in the suite. Usually, this looks like:


However, I also have the bad habit of often checking these marks in when I commit changes to a test.

The Solution

To prevent this, I created the following git pre-commit hook to be run before any commit is made:


if git rev-parse --verify HEAD >/dev/null 2>&1
    # Initial commit: diff against an empty tree object

NC='\033[0m' # No Color
difffiles=`git diff --cached --name-status | awk '$1 != "R" { print $2 }'`
while read -r filename
    diffstr=`grep -nr -e '^@pytest.mark.focus$' $filename`
    if [[ -n "$diffstr" ]] ; then
        printf "${RED}Focusmark:${NC} ${diffstr}\n"
done <<< "$difffiles"
exit $exitstatus

This script looks at all files currently staged to be committed and greps them for the offending string. If any match, it prints their filename and the matching line number (so that it’s easy to use iTerm’s semantic history feature on them and returns a non-zero exit code, which prevents the commit from being completed.

Using the hook:

Since I want this hook to be available in multiple repos, I’ve set this up as a global git hook as follows:

First, Create a directory to hold the global hooks:

mkdir -p ~/.git-templates/hooks

Next, put the above script in the hook template directory:

mv pre-commit ~/.git-templates/hooks

The commit hook must be executable:

chmod 755 ~/.git-templates/hooks/pre-commit

Next, globally configure git to use the created template directory:

git config --global init.templatedir '~/.git-templates'

Finally, we must re-init any git repo which should use this hook. This copies the template hooks into the local .git/hooks directory:

git init

If you want to update or replace a non-global hook, you’ll have to remove it and re-initialize, as git init won’t overwrite existing hooks.