dev-master不能当版本用,它只是浮动指针,每次composer update可能拉取新提交,force push后旧hash失效;真正锁定需用dev-branch#40位小写完整commit hash。

dev-master 不能当版本用,它只是浮动指针
写 "vendor/pkg": "dev-master" 看似装了 master 分支,实际只是告诉 Composer 去拉当时 HEAD 的提交;下次 composer update 可能拉到新 commit,force push 后旧 hash 在 composer.lock 里直接失效。这不是锁定,是裸奔。
常见错误现象:composer install 在 CI 上失败,报 Could not find package 或卡在 source.reference 不匹配;本地能跑、线上崩;两次构建结果不一致。
- 远端分支被删、重命名或 force push,
composer install就会失败 -
composer.lock里source.reference显示"main"或"HEAD",说明根本没锁住 commit - 分支名大小写敏感:写成
dev-Main、dev-main/fix(多斜杠)都会报Could not find a matching version
真正锁定 commit 只有一种写法:dev-branch#full-hash
必须用 dev-main#abc1234567890abcdef1234567890abcdef123456 这种格式——# 是唯一被 Composer VCS 驱动识别的 commit 锚点。@ 会被当成分支名解析,短哈希(如 abc123)可能不唯一,40 位完整小写哈希才可靠。
使用场景:临时验证 PR、紧急 hotfix、尚未打 tag 的开发中。
- 分支名必须和远端完全一致:
dev-Main ≠ dev-main,dev-feature/login要 URL 编码为dev-feature%2Flogin - 私有仓库必须提前在
composer.json的repositories里声明"type": "vcs"和带.git后缀的 URL - 命令行安装需显式放宽稳定性:
composer require vendor/pkg:dev-main#abc123... --stability=dev或composer require vendor/pkg:dev-main#abc123...@dev
验证是否真锁住了,不能只看 composer.lock
composer.lock 的 source.reference 只记录当时解析出的哈希,防不住远程 force push 覆盖。必须检查已安装包的真实 Git HEAD。
运行:cd vendor/vendor/pkg && git rev-parse HEAD,输出必须和 composer.lock 里对应字段完全一致。
- CI 中可加校验脚本:
composer show -s vendor/pkg | grep -q "abc1234567890$" - 执行
composer update vendor/pkg前,建议先删掉vendor/vendor/pkg和composer.lock中对应段落,避免缓存干扰 -
composer update --dry-run可提前看哪些包的 commit hash 会变,尤其注意间接依赖是否也用了dev-xxx但没加#hash
别永久设 minimum-stability: dev
"minimum-stability": "dev" 会让所有依赖都可能降级到任意 dev- 版本,失控风险极高。单包放宽更安全:composer require vendor/pkg:dev-main@dev(@dev 只对该包生效)。
容易踩的坑:以为改了 composer.json 就算锁定,却没运行 composer update vendor/pkg 更新 lock 文件;或者删了 composer.lock 再 install,导致整个依赖树重算,连带升级一堆间接依赖。
复杂点在于:分支名变更、私有源配置缺失、commit hash 大小写/长度不符、URL 编码遗漏——任一环节出错,Composer 都不会给出友好提示,只会报“找不到包”。











