anoneironaut anoneironaut - 2 months ago 14
Git Question

Is there a git hook which can prevent binary check-ins

Does anyone out there know of a good git hook that will check for binaries on commit and throw an error? I'm trying to prevent binaries from getting committed to my repository, but sometimes people make mistakes.

Thanks!

Answer

I don't know of an existing hook, but git already comes with a hook that checks for adding "non-ascii names", as a sample pre-commit hook. This will likely already be in your existing git repositories as .git/hooks/pre-commit.sample.

Using that hook as a template and considering the answers to "How to determine if Git handles a file as binary or as text?", you could do something like this (see "git's semi-secret empty tree" for where EMPTY_TREE comes from):

#! /bin/sh

stop_binaries=$(git config --get hooks.stop_binaries)

exec 1>&2

if [ "$stop_binaries" = true ]; then
    EMPTY_TREE=$(git hash-object -t tree /dev/null)
    # or: EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
    if git diff --cached --numstat $EMPTY_TREE | grep -e '^-' >/dev/null; then
        echo Error: commit would add binary files:
        git diff --cached --numstat $EMPTY_TREE | grep -e '^-' | cut -f3-
        exit 1
    fi
fi

This uses git diff --cached to see what would be committed, comparing it all against an initial empty tree. Note that it will reject commits with already-existing (but unchanged) binaries; to make it only reject new or changed binaries, add the against= logic from the non-ascii-names hook. To reject only new binaries add the --diff-filter=A argument too.

Fancy this up with additional error-message text if you like. You can reverse the test (instead of having to assert "stop binaries", make it default to stop and you have to set "allowbinaries" to add binary files), etc. And of course you can allow specific directories full of binary files, or whatever, as well, by doing additional filtering on the diff-index output.