应加在composer.json的scripts段中,定义为独立脚本(如"check-branch"),通过composer run check-branch显式调用;不可放入post-install-cmd等自动钩子,避免执行时机错位;需用git rev-parse --abbrev-ref HEAD读取分支并校验,失败时exit 1确保退出码透出。

Composer 分支检查脚本加在哪?
加在 composer.json 的 scripts 段里,不是全局钩子,也不是 Git 钩子——它只在本地执行 composer install 或 composer update 时触发,且默认不自动运行,必须显式调用。
常见错误是把它写进 post-install-cmd 里就以为“每次装包都自动校验”,其实那只是运行完安装后才执行,此时分支可能早被切走了;更稳妥的方式是单独定义一个脚本名(比如 check-branch),需要时手动跑:composer run check-branch。
-
"scripts": { "check-branch": "php -r "if (getenv('GIT_BRANCH') !== 'main') { exit(1); }""—— 这种写法依赖环境变量,CI 中可用,但本地没设就永远过不去 - 推荐用
git rev-parse --abbrev-ref HEAD直接读当前分支:"check-branch": "sh -c 'test $(git rev-parse --abbrev-ref HEAD) = "main" || { echo \"ERROR: not on main branch\"; exit 1; }'" - Windows 用户注意:
sh -c在 Windows 默认不可用,得改用 PowerShell 或加platform-check判断,否则 CI 通过、本地失败
怎么把代码合规校验塞进 Composer 脚本?
不能直接把 phpstan、psalm 或 phpcs 命令硬塞进 scripts 就完事——它们的退出码语义和 Composer 脚本的“失败即中断”逻辑要对齐,否则校验失败了脚本却返回 0,整个流程就漏检了。
关键点在于:所有校验命令必须真实返回非零退出码,且不能被 shell 包裹层吞掉。例如下面这种写法是错的:
"lint": "phpcs src/ || echo 'lint failed'"
因为 || 后面的 echo 执行成功,整个命令最终返回 0。
- 正确写法是去掉逻辑短路,让失败路径也能透出退出码:
"lint": "phpcs src/ || exit 1" - 多个工具串联建议用
&&,而非分号:"ci-check": "phpcs src/ && phpstan analyse src/ && psalm --no-cache",这样任一失败都会终止后续 - 如果用的是 PHPCS + 自定义规则,确保
phpcs.xml里severity设为 5(error 级别),否则 warning 不会触发非零退出码
为什么本地跑通了,CI 却总报分支检查失败?
CI 环境(如 GitHub Actions、GitLab CI)默认做的是 shallow clone,且多数不 checkout 出完整分支引用——git rev-parse --abbrev-ref HEAD 在某些 runner 上返回 HEAD 而不是 main 或 develop,导致脚本误判。
这不是脚本写错了,是 Git 克隆方式和 CI 配置耦合太紧。
- GitHub Actions:加
fetch-depth: 0并显式 checkout 分支:uses: actions/checkout@v4+ref: ${{ github.head_ref || github.ref }} - GitLab CI:设
clone_flags: --no-single-branch --depth 0,或直接用CI_COMMIT_TAG/CI_COMMIT_BRANCH环境变量替代 git 命令 - 不要依赖
git symbolic-ref --short HEAD,它在 detached HEAD 下直接报错,而 CI 构建常处于该状态
脚本里混用 PHP 和 shell,哪些地方容易崩?
最常翻车的是引号嵌套、空格路径、特殊字符未转义,尤其是当项目路径含空格或中文时,php -r 里的双引号和 shell 层的引号打架,直接语法错误。
- 避免在
php -r中拼接路径或变量,改用外部传参:"check-env": "php check-branch.php --branch=main" - 所有涉及文件路径的操作,统一用
realpath或dirname __DIR__在 PHP 侧解析,别靠 shell 的$(pwd) -
composer.json中脚本值是 JSON 字符串,反斜杠必须双写:"php -r "echo 'hello';"",单写"php -r "echo 'hello';""会解析失败
分支检查和代码合规不是加个脚本就万事大吉的事,真正卡住人的往往是环境差异、退出码隐匿、以及跨平台 shell 行为不一致——这些细节不提前压平,CI 流水线早晚在凌晨三点给你发告警。


















