Git钩子本身不检测Composer依赖,需脚本实现:pre-commit检查composer.json修改是否配套vendor安装,pre-push用composer install --dry-run校验lock与json一致性,并确保路径、版本、权限统一。

Git 钩子本身不能直接“检测” Composer 依赖,它只能在特定时机执行命令;真正的检测逻辑必须由你写的脚本完成,且必须明确区分 pre-commit(检查本地修改)和 pre-push(检查待推送代码)两种场景——选错钩子类型,检测就完全失效。
pre-commit 钩子里检查 composer.json 变更是否配套更新了 vendor
这个钩子适合拦截「改了 composer.json 却没运行 composer install」的提交。关键不是比对哈希,而是检查 vendor/ 目录下是否有对应包的安装记录:
- 用
git diff --cached --name-only | grep "composer.json"判断本次提交是否含composer.json修改 - 若有,再运行
composer show --no-ansi | cut -d' ' -f1 | sort获取当前已安装包列表,并与composer.json中require和require-dev的键做简单比对(注意:不校验版本号,只看包名是否存在) - 如果发现
composer.json里有"monolog/monolog": "^2.0",但composer show输出里没有monolog/monolog,就拒绝提交 - 注意跳过
vendor/是否被 gitignore 掉的问题——钩子只关心实际安装状态,不依赖 git 状态
pre-push 钩子里验证 composer.lock 是否与 composer.json 一致
这是防「本地改了 composer.json 但忘了 composer update 或 composer install,导致 composer.lock 没更新就推上去了」。核心是让 Composer 自己校验:
- 运行
composer validate --no-check-publish --no-check-version确保composer.json格式合法 - 再运行
composer install --dry-run --no-progress 2>/dev/null,如果返回非零码,说明composer.lock和composer.json不匹配(比如删了composer.json里的一个包,但没删lock里的对应条目) - 不要用
git diff比对两个文件——lock文件内容顺序可能因环境不同而变,不可靠 - 务必加
--no-progress,否则输出含 ANSI 控制符,可能干扰钩子判断
钩子脚本里调用 Composer 必须指定完整路径或确保环境一致
CI 和开发者本地的 PATH、PHP 版本、Composer 版本往往不同,钩子在 git push 时可能根本找不到 composer 命令,或者调到旧版导致校验行为不一致:
- 推荐用
./composer.phar(放在项目根目录)并写死路径,比如php ./composer.phar install --dry-run - 如果用全局
composer,先加检查:command -v composer >/dev/null 2>&1 || { echo "composer not found"; exit 1; } - 避免在钩子里用
sudo或切换用户——Git 钩子以当前 shell 用户身份运行,权限问题会静默失败 - Mac 上注意 SIP 可能阻止某些 PHP 扩展加载,导致
composer报错但不退出,需加set -e让脚本在任意命令失败时中止
真正难的是让所有协作者的钩子都启用且版本同步——.git/hooks/ 不进 Git,得靠 husky 或自建 scripts/setup-hooks.sh 来分发,否则一半人没跑检测,等于没设。


















