问题在于 Git 命令在为钩子脚本创建的环境中与正常环境中的行为方式有所不同。
首先,挂钩脚本运行时将其当前工作目录设置为 Git 目录本身(即.git/
非裸存储库的目录)。其次,挂钩脚本使用 GIT_DIR 环境变量集运行并指向 Git 存储库(同样,.git/
非裸存储库的目录)。
通常,如果您尝试运行git reset --hard
来自.git/
目录,它将死亡并显示以下消息:
fatal: This operation must be run in a work tree
但是当设置 GIT_DIR 时,Git 命令假定当前目录是工作树。由于钩子运行时的当前目录是.git/
目录,你的git reset --hard
实际上是直接将您的工作树文件“签出”到.git/
而不是其父目录(即您现在在您的.git/
目录)。
希望您的存储库中的版本化内容都没有与以下内容一致的路径名Git 在 Git 存储库本身中使用的路径名 http://www.kernel.org/pub/software/scm/git/docs/gitrepository-layout.html。如果它们确实一致,那么你的git reset --hard
将覆盖存储库的一些内部结构,并且您可能希望从其他存储库重新克隆它。如果您确信版本化内容不会与 Git 的内部路径名冲突,那么您可以使用以下命令清理它:
# make a backup of your repository first!
(cd .git && GIT_DIR=$PWD git ls-files -cz | xargs -0 rm)
这只会删除当前跟踪的文件(它将留下已被删除但在损坏的钩子处于活动状态时推送的提示提交中曾经跟踪过的文件)。
一种解决方案是在调用 Git 命令之前将当前工作目录更改为正常工作树并取消设置 GIT_DIR 和 GIT_WORK_TREE。
⋮
test "${PWD%/.git}" != "$PWD" && cd ..
unset GIT_DIR GIT_WORK_TREE
# you can now safely use Git commands
⋮
另一个解决方案是显式重置 GIT_DIR,在那里设置 GIT_WORK_TREE 和 chdir。 Git 常见问题解答“为什么在“git Push”之后我看不到远程存储库中的更改?” https://git.wiki.kernel.org/index.php/GitFaq#Why_won.27t_I_see_changes_in_the_remote_repo_after_.22git_push.22.3F推荐一个更新后 script http://utsl.gen.nz/git/post-update就是这样做的。链接脚本也更安全,因为如果在进行硬重置之前索引或工作树脏了,它会进行隐藏。