pre-commit 钩子应执行 composer install --no-dev 和 composer validate --strict --no-check-publish,并自动 git add composer.lock;pre-push 钩子需校验 composer.lock 是否有未暂存修改;所有命令须在项目根目录运行,优先使用本地 composer.phar。

提交前自动运行 composer install 防止 lock 文件不一致
Git 提交时若 composer.lock 未随 composer.json 更新,协作中极易引发依赖版本漂移。直接在 pre-commit 钩子中执行 composer install --no-dev 是最轻量的兜底手段。
但要注意:该命令会修改 composer.lock 和 vendor/,而 Git 默认只暂存已跟踪文件——如果 vendor/ 未被忽略(不该如此),钩子会失败;如果 composer.lock 变更未被暂存,提交照样能过,起不到拦截作用。
- 务必确保
.gitignore中包含vendor/,且composer.lock已被 Git 跟踪(git add composer.lock) - 钩子脚本里加一句
git add composer.lock 2>/dev/null,避免因无变更报错 - CI 环境通常禁用
composer install的交互提示,本地钩子建议加--no-interaction参数
pre-commit 中校验 composer validate 是否通过
composer validate 能快速发现 composer.json 格式错误、必填字段缺失或版本约束语法错误,比如把 "^1.2" 写成 "^1,2" 这种低级问题。
它不联网、不读仓库、毫秒级完成,适合高频调用。但默认行为是允许带 autoload 错误的 JSON 通过(比如 PSR-4 映射路径不存在),需显式加 --strict 才真正严格。
- 推荐命令:
composer validate --strict --no-check-publish -
--no-check-publish省掉对 Packagist 的连通性检查,避免网络抖动导致钩子卡住或误报 - 若项目使用自定义 Composer 插件,某些插件可能干扰
validate输出,此时应先确认插件是否稳定再启用钩子
用 pre-push 拦截未提交的 composer.lock 变更
开发者常忘记 git add composer.lock,导致 composer.json 和 lock 不同步。仅靠 pre-commit 不够——因为 composer install 可能生成新 lock,但用户没暂存就直接 push,远程构建就会失败。
pre-push 钩子更适合做这层最终校验:它能看到工作区、暂存区、HEAD 三者状态差异,能精准判断 composer.lock 是否有未提交变更。
- 检查逻辑可简化为:
git status --porcelain composer.lock | grep -q '^ M'(表示已修改但未暂存) - 若命中,输出明确提示如
Error: composer.lock has unstaged changes. Run 'composer update' or 'git add composer.lock' first. - 注意 Windows 下 Git Bash 的
grep行为略有不同,建议用findstr或统一用sh -c 'git status...包一层增强兼容性
钩子脚本如何避免重复执行或污染全局环境
Composer 命令依赖当前目录下的 composer.json,而 Git 钩子默认在 Git 目录(.git/)内执行,不是项目根目录。直接写 composer validate 会报错 No composer.json found。
另一个常见问题是:全局安装的 Composer 版本和项目要求不一致(比如项目需 Composer 2.5+,但全局是 2.2),导致钩子行为与 CI 不一致。
- 所有钩子命令前加
cd "$(git rev-parse --show-toplevel)"切回项目根目录 - 优先用项目局部的 Composer:检查是否存在
./composer.phar,存在则用php ./composer.phar validate;否则 fallback 到系统composer - 不要在钩子里执行
composer update——它会改写lock并可能升级次要版本,属于人工决策行为,自动化应只做检查不改状态
composer.lock 变更状态的三种情形(未修改 / 已修改未暂存 / 已暂存未提交)对应的不同拦截点。选错钩子类型或漏判一种状态,检查就形同虚设。









