dev-master是浮动引用,不指向固定代码点,每次composer update都拉取远程分支当前HEAD的最新提交,导致CI构建不可重现、本地能跑但线上崩;真正可控的写法只有锁定具体commit(如dev-main#7f8c4d9a2e1b3c4d5e6f7a8b9c0d1e2f3a4b5c6d)或映射伪版本(如dev-main as 999.999.999),且严禁在生产环境或CI中使用dev-分支。

dev-master 是浮动引用,不是版本
它不指向任何固定代码点,而是每次 composer update 都会拉取远程分支当前 HEAD 的最新提交。哪怕只隔两小时,两次 install 可能装上完全不同的 commit —— 类名改了、方法删了、PHP 版本要求升了,这些都不会在安装时报错,只等第一次运行才崩。
这不是 bug,是设计使然:dev-master 本质是 git clone && git checkout origin/master 的快捷写法,没有锁定机制。
- 本地能跑 ≠ CI 能跑,因为 CI 拉的是“此刻”的 master,你本地拉的是“两小时前”的
-
composer.lock里记录的 reference 只在composer install时生效;composer update会无视 lock,重新 fetch 最新 dev-master - 即使你 fork 了包并自己维护,只要还用
dev-master,就逃不开这个浮动问题
为什么加了 -s dev 还会出问题
加 --stability=dev(或简写 -s dev)只是让 Composer 允许解析 dev- 开头的约束,但它不解决浮动问题,也不保证可重现。
常见误判场景:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 命令行加了
-s dev,但composer.json里仍保留"prefer-stable": true→ Composer 会 fallback 到最近 stable tag(比如 v2.3.0),而不是你想要的 dev-main - 私有仓库没在
repositories中声明vcs类型源 → Composer 根本查不到该包,报Could not find package,和 stability 无关 - 远程分支已从
master改为main,但你还硬写dev-master→ Git 不存在该分支,直接失败,不是 stability 设置的问题
真正可控的写法只有两种
要么锁定到具体 commit,要么映射为语义化伪版本。其他写法都属于临时应付,迟早出事。
-
"vendor/package": "dev-main#7f8c4d9a2e1b3c4d5e6f7a8b9c0d1e2f3a4b5c6d":必须用完整 40 位 SHA1,短哈希(如abc1234)在 CI 环境大概率解析失败 -
"vendor/package": "dev-main as 999.999.999":仅用于 require 场景,让依赖解析器优先选这个分支;不能用于生产,且不提供任何兼容性保障 - 别用
dev-master或dev-main单独出现——它们永远不该出现在生产环境的composer.json或 CI 脚本中
CI 和生产环境必须禁用 dev 分支
composer install --no-dev --optimize-autoloader 不是可选项,是强制项。漏掉 --no-dev 会导致开发专用包(如 debugbar、phpunit)被装进线上环境,轻则性能暴跌,重则暴露敏感路径。
更关键的是:--no-dev 会跳过所有 require-dev 里的包,但不会跳过 require 里写的 dev-main —— 它只管包类型,不管版本稳定性。
- 所以真正要防的,是把
dev-引用写进require字段 - 如果必须用开发版,就在
require-dev里写,并确保 CI 脚本明确区分dev和prod安装流程 -
composer.lock必须提交,且只允许composer install读取;composer update应限制在开发机执行,严禁在 CI 中自动触发

















