自定义目录结构下Docker环境中GrumPHP pre-commit钩子未生效
异常根因
- 路径映射错位导致待检查文件列表为空
Git提交触发的pre-commit钩子运行在项目根目录(即.git所在层级),拉取到的暂存区文件路径都是以app/为前缀的仓库根目录相对路径(例如app/src/Controller/Test.php)。但钩子调用容器内的GrumPHP时,GrumPHP的默认工作目录就是app目录本身,相当于它需要匹配的文件路径变成了app/app/src/Controller/Test.php——这个路径在容器内完全不存在。
GrumPHP的任务执行逻辑是:如果从diff中提取到的待检查文件列表为空,会直接返回成功,不会抛出“找不到目标文件”的异常,因此出现了“提交时显示校验通过,但实际未执行任何检查”的现象。 - 容器环境变量传递失效
钩子脚本中通过export设置的GRUMPHP_GIT_WORKING_DIR仅在宿主shell中生效,docker exec命令默认不会将宿主环境变量传入容器进程,容器内的GrumPHP根本接收不到这个路径配置。同时grumphp.yml中配置的GRUMPHP_GIT_WORKING_DIR: "../"、GRUMPHP_GIT_REPOSITORY_DIR: "../.git/"这类相对路径,基准是容器内GrumPHP进程的启动目录,极易因为容器工作目录不一致出现路径错位。 - 手动运行与钩子流程的执行逻辑差异
手动在容器内运行vendor/bin/grumphp run时,GrumPHP会默认扫描当前工作目录下所有符合规则的文件,完全不依赖Git传递的暂存文件路径,因此可以正常检出代码问题。但pre-commit流程调用的是git:pre-commit子命令,核心逻辑是仅检查diff中匹配到的暂存文件,一旦路径错位没有匹配到有效文件,就会直接通过校验。
修复方案
- 调整钩子的diff路径适配逻辑
拉取到暂存区diff后,移除diff中所有文件路径的app/前缀,让路径适配GrumPHP在容器内的app工作目录,修改后的钩子diff处理片段如下:DIFF=$(git -c diff.mnemonicprefix=false -c diff.noprefix=false --no-pager diff -r -p -m -M --full-index --no-color --staged | cat) # 移除diff文件路径中的app/前缀,匹配app目录下的相对路径 DIFF=$(echo "$DIFF" | sed -E 's|^(diff --git [ab]/)app/|\1|g') - 固定容器内的运行工作目录
修改grumphp.yml中的EXEC_GRUMPHP_COMMAND,通过docker exec的-w参数强制指定容器内的运行目录,避免依赖容器默认WORKDIR出现路径偏差,示例配置:git_hook_variables: EXEC_GRUMPHP_COMMAND: docker exec -w /容器内app目录的绝对路径 php-fpm - 清理无效配置
- 删除钩子脚本中无效的
export GRUMPHP_GIT_WORKING_DIR=...代码,这些变量不会传入容器,仅会造成逻辑误导 - 移除
grumphp.yml的environment.variables下所有依赖相对路径的配置,GrumPHP会自动基于当前工作目录定位.git目录和配置文件,无需手动指定路径。
- 删除钩子脚本中无效的
- 重新生成钩子
修改完配置后,删除原有的.git/hooks/pre-commit文件,重新在容器内运行vendor/bin/grumphp git:init生成新的钩子,再按照上述逻辑调整diff路径替换规则即可。
内容的提问来源于stack exchange,提问作者Bogdan Dubyk
相关产品推荐
相关产品推荐

