gitgithooksgit-post-receive

Why doesn't `git -C` work from Python in a post receive hook?


Try this:

mkdir /tmp/one
cd /tmp/one
git init
echo -e "#!/usr/bin/env python3\nimport os\nos.system('git -C /tmp/one show')" > /tmp/one/.git/hooks/post-receive
chmod +x /tmp/one/.git/hooks/post-receive
touch test.txt
git add test.txt
git commit -m 'Initial commit'
cd /tmp/
git clone one two
cd two
git checkout -b test
echo "Why doesn't this work?" >> test.txt
git add test.txt
git commit -m "testing"
git push -u origin test

And observe the very confusing message:

remote: fatal: Not a git repository: '.'

What?

Seriously, what the actual heck? Why is this completely broken? I can go to a literal folder that is not a git repository (cd / && git -C /tmp/one/show) and it works fine. Why doesn't this command work?

It also doesn't work if I do os.chdir('/tmp/one'). I cannot make the post-receive hook actually figure out what the heck is going on. It's more than happy to run some other commands, like git merge, but it will not understand git show, git status, or more importantly for me, git -C /tmp/one checkout master. I've also tried with just a bare

#!/bin/sh
git -C /tmp/one status

And it gives me the same error mesage - not a git repostiory: '.'

Any clue what in the world is going on here?


Solution

  • The issue here is that commands run from a Git hook are run with various environment variables set. The one that's hitting you is $GIT_DIR, but there could be others (e.g., $GIT_WORK_TREE, $GIT_INDEX_FILE, and so on).

    They're set correctly for dealing with the repository you're in at the time the hook runs. But you don't want this hook to deal with this repository. You want this hook to chdir somewhere else and deal with some other repository. At that point, you should clean out the unwanted environment variables, or override them with correct settings for that repository.

    In short, add:

    unset GIT_DIR
    

    (for sh/bash/etc), or in Python:

    del os.environ['GIT_DIR']
    

    (note that the Python version only works when it's actually set), or use the env argument when using subprocess, etc.