最轻量可靠的方式是在 .git/hooks/pre-commit 中执行 composer validate –no-interaction;需加 #!/bin/sh、cd 至项目根目录、仅当 composer.json 变更时运行,并在失败时 exit 1。

pre-commit 里怎么调用 composer validate
直接在 Git Hooks 的 .git/hooks/pre-commit 脚本里执行 composer validate --no-interaction 是最轻量、最可靠的方式。它不依赖额外工具链,也不需要解析 json 结构——composer validate 本身就能检查语法、schema 兼容性、require 包名格式、版本约束合法性等。
注意:必须加 --no-interaction,否则遇到警告(比如 license 字段缺失)会卡住等待输入,导致 commit 中断。
- 脚本开头加
#!/bin/sh,确保 POSIX 兼容 - 建议先
cd $(git rev-parse --show-toplevel)切到项目根目录,避免路径错位 - 检查
composer.json是否被修改:git diff --cached --quiet -- composer.json 2>/dev/NULL || { ... },只在它有变更时才跑验证 - 返回非 0 码时直接
exit 1,Git 会中止 commit
为什么不用 jq 或 php -l 手动校验?
jq 只能验 JSON 语法,过不了 schema 层面的检查(比如 type: "project" 写成 "library" 不报错);php -l composer.json 更危险——PHP 解析器会把 JSON 当 PHP 代码读,一旦字段含 @、$ 或注释,立刻报错或静默失败。
composer validate 是唯一覆盖全部维度的官方手段:JSON 语法 + Composer Schema + 语义合理性(如 autoload 路径是否存在)。
- 不推荐用
composer install --dry-run替代,它耗时长、依赖网络、还会触发插件逻辑 - CI 中可复用同一命令,但 pre-commit 场景下务必加
--no-ansi避免控制字符干扰
windows 下 pre-commit 脚本怎么写才不翻车?
Git for Windows 默认用 MSYS2 环境跑 shell 脚本,但 composer 常是 Windows 原生 .bat 或 .exe。直接调用可能因 PATH 或换行符崩掉。
稳妥做法:改用 git config core.hooksPath .githooks,把 hooks 放进项目内统一管理,并用 PowerShell 脚本替代 shell:
if (git diff --cached --quiet -- composer.json) { exit 0 } $ErrorActionPreference = "Stop" try { composer validate --no-interaction --no-ansi | Out-Null } catch { Write-Error "composer.json 格式或内容错误" exit 1 }
- PowerShell 脚本保存为
.githooks/pre-commit,需git config core.hooksPath .githooks - 避免用
cmd.exe批处理——它对命令链和错误码处理太脆弱 - Mac/linux 用户若用 Homebrew 安装的 Composer,确认
which composer返回路径在 hook 脚本的 PATH 中
验证通过但 CI 还是失败?查这三点
本地 composer validate 过了,CI 却报错,大概率不是格式问题,而是环境/配置差异。
-
composer.json里用了platform配置(如"php": "8.2"),但 CI 的 Composer 版本太老,不认识该字段 → 升级 CI 的composer到 2.5+ - 本地开了
COMPOSER_ALLOW_SUPERUSER=1,而 CI 没开,导致某些插件初始化失败 → 不要在 validate 阶段依赖插件 - CI 使用
composer install时加了--no-dev,但composer.json的require-dev里有非法包名 →validate默认检查全部字段,无需额外参数
真正容易被忽略的是:validate 不检查 lock 文件一致性。如果 composer.json 改了但没跑 composer update,lock 文件会滞后——这不会让 validate 报错,但会让 CI 的 install 失败。这事得靠另一个 hook(比如 pre-push)补上 composer update --dry-run。