2018-06-04 Collaborating with non-Git-users - Git hook

In the first part, I showed how I can make Git add information about the commit in every file I want it to in such a way that it is updated every time I Git-archive the project. The second part was devoted to integrating this workflow in Emacs and mu4e. Today I finish with showing my Git hook protecting me from accidentally messing up.

One issue with this setup is that I can accidentally commit the values (like the commit hash etc.) I got from one of the other authors instead of the placeholder. Using Magit’s magit-discard on a region is easy, but forgetting to do it is even easier. So, git hooks to the rescue – this is perfectly suited to a Git pre-commit hook:

#!/bin/bash

git diff --name-only --cached | while read -r filename; do
    if ! grep -q "\$Format:" <(head -n3 "$filename")
    then
	echo File "$filename" contains the commit data, please revert to the placeholders!
	exit 1
    fi
done

Notice that I used a few tricks here:

Notice also that the above is not very robust: if the filenames contain spaces, things might break down. (Use IFS= read in that case.) In my case, this is not a concern, so I didn’t bother.

The only remaining thing to do is to ensure that I won’t accidentally commit things from other people as myself. I know two methods of doing this: one is an extremely dirty hack, and the other one relies on a not-so-well-documented feature of Git. Go figure.

The dirty hack is to set the user name in the per-repository Git configuration to empty strings. This makes it impossible to commit anything (even if you use git commit --author), since Git complains about empty ident name (for <email@example.com>) not allowed. The trick is to set the environment variables GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL (for some very strange reason, they override even the local Git settings). Now, if you don’t specify your author data, the commit will fail, but if you do, everything will be fine.

The more elegant way is to use a client-side Git hook. In this case, the pre-commit hook is again our best bet. The problem is, it does not get any parameters. Happily for us, it has an undocumented feature: it has access to some environment variables, one of them being GIT_AUTHOR_EMAIL. (I learned about it here; it is actually described in the docs, but that seems not to imply that the pre-commit hook is going to get it.) So, we can use this pre-commit hook:

#!/bin/bash

if ! grep "@allowed.domain$" <(echo $GIT_AUTHOR_EMAIL)
then
    echo Please correctly set the commit author!
    exit 1
fi

(Of course, I merged both the above scripts to one pre-commit script.)

Problem solved!

CategoryEnglish, CategoryBlog, CategoryGit