Git钩子中`cd 路径&& git 命令`失效原因及临时方案解析
问题背景
我尝试在pre-commit钩子中格式化提交的源代码,但仅希望在特定仓库中执行该钩子。通过检查仓库远程地址是否包含特定子串来判断当前是否在目标仓库,这部分正常工作。但目标仓库包含子模块,因此在子模块中提交时,需要检查父仓库的远程地址,最初实现代码如下:
test=$(cd ../../; git remote -vv | grep 'my_special_repo') echo $test if [[ $test == *"my_special_repo"* ]]; then echo "This is a my_special_repo child submodule" echo "Commit should be formatted" else exit 0 fi
这段代码无法正常工作,echo $test输出为空。但添加echo $PWD后的代码却能正常运行:
test=$(cd ../../; echo $PWD; git remote -vv | grep 'my_special_repo') echo $test if [[ $test == *"my_special_repo"* ]]; then echo "This is a my_special_repo child submodule" echo "Commit should be formatted" else exit 0 fi
现提出两个问题:
- 为何第一种写法无法工作?
- 为何临时方案能生效?
注:使用的Git版本为2.41.0.windows.1
问题解答
1. 第一种写法失效的原因
在Windows环境的Git钩子中,cd ../../的路径切换操作可能未同步完成就执行了后续的git remote命令。Git for Windows默认的shell环境(如Git Bash/MinGW)在钩子执行时,路径切换的速度可能跟不上命令执行的节奏,导致git仍在原有的子模块目录下运行,自然无法捕获父仓库的远程地址,grep结果为空。
另外,子模块的嵌套深度不一定固定为../../,如果提交时的工作目录不是子模块根目录,或者子模块本身还有嵌套,cd ../../会跳到错误的目录。此时git remote -vv在非Git仓库目录执行会报错,但错误输出未被捕获,最终导致test变量为空。
2. 添加echo $PWD后生效的原因
添加echo $PWD相当于在cd之后增加了一个同步的输出操作,给shell环境足够的时间完成路径切换,确保后续的git remote命令是在切换后的父仓库目录中执行。
同时,echo $PWD输出的路径能间接验证目录切换是否正确,避免了因路径错误导致git命令执行失败的情况。本质上是这个额外的命令让shell执行流程出现短暂停顿,保证了cd操作的完成,使得git命令能在正确的仓库目录下运行,从而捕获到父仓库的远程地址。
内容的提问来源于stack exchange,提问作者GiatManos

