branch-alias 是为 dev- 开头的开发分支(如 dev-main)提供稳定版本号映射(如 "1.0.x-dev"),使其他项目能用语义化版本约束(如 "^1.0")安全依赖;它必须定义在被依赖库的 composer.json 的 extra.branch-alias 中,且仅对 VCS 包生效。

Composer 的 branch-alias 不是给项目“起别名”用的,而是为开发中的不稳定分支(比如 dev-main 或 dev-develop)提供一个稳定的版本号映射,让其他项目能用语义化版本(如 ^2.0)安全地依赖它。直接在 composer.json 里写 "alias": "2.0.x-dev" 是无效的——这个字段只在 repositories 的包定义或 VCS 包的 composer.json 中起作用,且仅对 dev- 开头的分支生效。
什么是 branch-alias?它解决什么问题
当你在开发一个尚未发布稳定版的库(比如还在 main 分支迭代),别人想 require 它时,只能写 "myvendor/mylib": "dev-main"。但 dev-main 不满足 ^1.0 这类约束,也无法参与版本稳定性解析。branch-alias 就是告诉 Composer:“请把 dev-main 当作 1.0.x-dev 来看待”,这样下游项目就能用 "myvendor/mylib": "^1.0" 安装并自动跟踪该开发分支。
- 只对
dev-开头的分支有效(如dev-main、dev-next) - 必须写在被依赖的库自己的
composer.json中(不是使用者的) - 值必须是
X.Y.z-dev格式,不能是1.0.0或stable - 它不改变当前分支名,也不影响
git checkout
如何正确配置 branch-alias(以 main 分支为例)
进入你要发布的库的根目录,编辑其 composer.json:
{
"name": "myvendor/mylib",
"version": "1.0.0",
"autoload": { "psr-4": { "MyVendor\\MyLib\\": "src/" } },
"extra": {
"branch-alias": {
"dev-main": "1.0.x-dev"
}
}
}
注意几点:
-
extra.branch-alias是顶层extra键下的对象,不是require或config的子项 - 键名必须是完整分支名,带
dev-前缀(即使 Git 分支叫main,这里也写"dev-main") - 值必须以
x-dev结尾,中间用点分隔(1.0.x-dev合法,1.0-dev或1.x-dev不合法) - 如果同时维护多个开发分支(如
dev-next对应 2.0),可写多个键值对
常见错误和验证方式
配置完别名后,很多人发现下游项目仍无法用 ^1.0 拉到 dev-main,原因通常是:
- 没提交并 push 到远程仓库(Composer 从 packagist 或你配置的 VCS 仓库读取元数据)
- packagist 没同步最新
composer.json(手动点击 “Update” 或等 webhook 触发) - 本地测试时用了
pathrepository,而path类型不支持branch-alias解析 - 运行
composer show myvendor/mylib查看实际识别的版本:如果显示dev-main 1.0.x-dev,说明 alias 生效;如果只显示dev-main,说明配置未被读取或格式错误
临时验证可在下游项目中加一个 repositories 指向本地路径(仅限调试):
{
"repositories": [
{
"type": "path",
"url": "../mylib"
}
],
"require": {
"myvendor/mylib": "dev-main as 1.0.x-dev"
}
}
注意:as 是 require 时的临时 alias,仅用于 path/VCS 类型,和 extra.branch-alias 无关,也不能替代它。
为什么 dev-develop 映射成 2.0.x-dev 很容易出错
当主干升级到 2.0 开发周期,很多人会把 dev-develop 的 alias 改成 "2.0.x-dev",却忘了同步更新 dev-main 的映射(比如还留着 "1.0.x-dev")。结果导致:
- 新用户
composer require myvendor/mylib:^2.0拉到的是dev-develop,符合预期 - 老用户
composer update时,如果锁定了"myvendor/mylib": "^1.0",Composer 可能悄悄切换到dev-main(如果它还存在且有1.0.x-devalias),而不是报错或保持原版本 - 更隐蔽的是:如果你删了
dev-main分支,但 packagist 缓存里还有旧 metadata,Composer 仍可能尝试安装已不存在的分支
真正可控的做法是:每个开发分支对应唯一语义化前缀,且一旦废弃分支,就从 extra.branch-alias 中移除对应条目,并确保远程仓库不再推送该分支的更新。










