Search code examples
pythongitgithooks

Git diff call in pre-commit throws "fatal: unable to read [SHA1]"


I am working in windows and attempting to run a git diff command in the pre-commit script (Python) of a repository. My Python call looks like this:

repo_dir = 'D:/git/current_uic/src/gtc/resource'
cmd = ['diff', '--name-only']
print(Popen(['git', '--git-dir={}'.format(repo_dir + '/.git'), 
             '--work-tree={}'.format(repo_dir)] + cmd,
            stdin=PIPE, stdout=PIPE).communicate())

Whenever I go to commit in the "D:/git/current_uic/src/gtc" repo, I get the following:

fatal: unable to read 6ff96bd371691b9e93520e133ebc4d84c74cd0f6

Note that this is a pre-commit hook for the 'D:/git/current_uic/src/gtc' repository and that 'D:/git/current_uic/src/gtc/resource' is a submodule of 'D:/git/current_uic/src/gtc'. Also note that if I pop open Git bash and run the following:

git --git-dir=D:/git/current_uic/src/gtc/resource/.git 
    --work-tree=D:/git/current_uic/src/gtc/resource diff --name-only

or if I just run the script straight from Git bash I get exactly what I want, regardless of working directory.

Any ideas as to what is going on here?


Solution

  • The Problem:

    Upon running a hook, Git sets some environment variables that are accessible by the hook script. The problem is that Git itself uses these environment variables, and the normal way in which Git sets/uses them seems to be overridden by the values set when the hook gets fired off. In this particular instance, the environment variable GIT_INDEX_FILE has been set to the path to the index file corresponding to the repository which had called the hook (D:/git/current_uic/src/.git/modules/gtc/index), causing a mismatch between the (incorrect) index and the (correct) change tree.

    The Fix:

    In the hook script, set the environment variable GIT_INDEX_FILE to the correct value before making any git calls. In this case, you could do the following:

    set GIT_INDEX_FILE=D:/git/current_uic/src/.git/modules/gtc/modules/resource/index
    git --git-dir=D:/git/current_uic/src/gtc/resource/.git 
        --work-tree=D:/git/current_uic/src/gtc/resource diff --name-only
    

    Additional Info

    More information about these Git environment variables and which hooks set them can be found here.