branch-alias 是给开发分支(如 dev-main)映射虚拟稳定版本号(如 2.0.x-dev)的机制,解决其无法被语义化版本约束(如 ^2.0)引用的问题;需在被依赖包的 composer.json 的 extra.branch-alias 中配置,仅对 dev- 开头分支生效,且别名值必须含 -dev 后缀。

什么是 branch-alias,它解决什么问题?
当你在 composer.json 中 require 一个开发分支(比如 "dev-main" 或 "dev-feature/x"),Composer 默认把它当作无版本号的“不稳定”包处理,无法被其他包通过语义化版本约束(如 ^2.0)引用。而 branch-alias 的作用,就是给开发分支「贴上一个虚拟的稳定版本号」,让依赖方能用常规版本约束拉取它。
如何在包的 composer.json 中配置 branch-alias?
只在**被依赖的包**(即你正在开发的库)的 composer.json 中设置,不是在项目根目录里配。它必须放在 extra 段下,且键名固定为 branch-alias:
{
"name": "myvendor/mylib",
"extra": {
"branch-alias": {
"dev-main": "2.0.x-dev"
}
}
}
注意:"2.0.x-dev" 是虚拟版本号,不是真实 tag;x 是占位符,表示该分支会持续演进;Composer 会把 dev-main 当作 2.0.x-dev 来解析和匹配。
- 如果你主干是
dev-master,就写"dev-master": "1.5.x-dev" - 如果想让
dev-next对应3.0.x-dev,就加一行"dev-next": "3.0.x-dev" -
branch-alias只影响该包自身被 require 的方式,不影响它依赖的其他包
依赖方怎么写 require 才能命中别名?
依赖方不用改任何配置,只要在自己的 composer.json 中按虚拟版本号写即可:
{
"require": {
"myvendor/mylib": "^2.0"
}
}
Composer 会自动识别 ^2.0 匹配到 myvendor/mylib 的 dev-main 分支(因为它的 branch-alias 声明了 "dev-main": "2.0.x-dev")。但要注意:
- 必须用
-dev后缀的别名(如2.0.x-dev),不能写成2.0.x,否则不生效 - 如果同时存在真实 tag
v2.0.0,Composer 优先选 tag,除非显式指定"myvendor/mylib": "dev-main" - 运行
composer update myvendor/mylib时,要确保源仓库可访问且分支存在
常见错误与兼容性陷阱
最常踩的坑是以为 branch-alias 能让任意分支“伪装”成任意版本——其实它只对 dev- 开头的分支有效,且必须存在于被 require 的包中。以下情况不会触发别名:
- 你在项目里直接 require
"myvendor/mylib": "dev-feature/login",但该包没为dev-feature/login配branch-alias - 别名值写成
"2.0.x"(缺-dev),Composer 完全忽略该条目 - 使用
path仓库类型时,branch-alias不生效,因为 Composer 绕过了版本解析逻辑 - PHP 7.4+ 和 Composer 2.0+ 支持完整功能;Composer 1.x 对
branch-alias解析更严格,建议升级
别名不是魔法,它只是 Composer 版本解析器的一层映射规则。一旦分支删除或别名变更,所有依赖它的 ^x.y 表达式就会失效——这点容易被忽略,尤其在 CI/CD 流水线中临时切分支测试时。










