在pre-commit中调用Git diff时出现“fatal: unable to read [SHA1]”错误

0 投票
2 回答
799 浏览
提问于 2025-04-18 13:51

我在Windows系统上工作,想在一个代码库的预提交脚本(用Python写的)中运行一个git diff命令。我的Python调用看起来是这样的:

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())

每当我在“D:/git/current_uic/src/gtc”这个代码库中进行提交时,就会出现以下情况:

fatal: unable to read 6ff96bd371691b9e93520e133ebc4d84c74cd0f6

请注意,这是“D:/git/current_uic/src/gtc”代码库的一个预提交钩子,而“D:/git/current_uic/src/gtc/resource”是“D:/git/current_uic/src/gtc”的一个子模块。另外,如果我打开Git bash并运行以下命令:

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

或者如果我直接从Git bash运行这个脚本,我就能得到我想要的结果,无论当前工作目录是什么。

有没有人知道这里发生了什么?

2 个回答

0

我遇到了完全一样的问题,不过我是用的 gitpython。我这样解决的:

repo = git.Repo()
for submodule in repo.submodules:
    back_index = os.getenv('GIT_INDEX_FILE')
    os.environ['GIT_INDEX_FILE'] = submodule.module().index.path
    commit = submodule.module().head.commit
    print([item.a_path for item in commit.diff(None)])
    os.environ['GIT_INDEX_FILE'] = back_index
3

问题:

在运行一个钩子(hook)时,Git会设置一些环境变量,这些变量可以在钩子脚本中使用。问题是,Git自己也会用到这些环境变量,而Git设置和使用这些变量的正常方式似乎会被钩子触发时设置的值覆盖。在这个特定的情况下,环境变量 GIT_INDEX_FILE 被设置成了与调用钩子的仓库对应的索引文件的路径(D:/git/current_uic/src/.git/modules/gtc/index),这导致了(错误的)索引和(正确的)变更树之间的不匹配。

解决办法:

在钩子脚本中,在进行任何Git操作之前,将环境变量 GIT_INDEX_FILE 设置为正确的值。在这种情况下,你可以这样做:

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

更多信息:

关于这些Git环境变量以及哪些钩子会设置它们的更多信息,可以在 这里 找到。

撰写回答