composer.json 的 version 字段不应手动填写,它仅作为 Composer 的特殊信号位:若填写则强制视为无 VCS 的本地包,忽略 Git tag、拒绝 Packagist 同步,且下游 require 可能匹配失败或报错;真实版本唯一来源是 Git tag(如 v3.2.1),Packagist 自动解析为语义化版本并支持 ^3.2 等约束;开发中分支名(如 dev-main)由 Git 自动推导,无需干预;若硬写 "version": "1.0.0" 又打 v2.0.0 tag,Composer 仍坚持使用 1.0.0 字面值;CI 中用 sed 替换 version 是高危操作,会导致 Git diff 与 tag 元信息脱节、锁文件不可复现;仅当完全脱离 VCS、不发布到 Packagist/私仓、所有依赖均通过 repositories.type = path 引入时,才可勉强填写,且值必须为合法语义化版本(如 "1.2.3"),禁用 "v1.2.3" 或占位符;推荐改用 "minimum-stability": "dev" + "prefer-stable": false,并显式 require "vendor/name": "dev-main";打 tag 才是真正生效的发布动作,务必删掉或清空 composer

composer.json 里的 version 字段不该手动写
它不是“项目版本号填写处”,而是 Composer 的一个特殊信号位:一旦你写了,Composer 就默认这是个无 VCS 的本地包,直接忽略 Git tag、拒绝 Packagist 同步、下游 require 可能匹配失败甚至报 Could not find package。
- 真实版本来源只有 Git tag(如
v3.2.1),Packagist 自动解析vX.Y.Z为X.Y.Z,支持^3.2、~3.2.0等全部语义化约束 - 开发中分支名(如
dev-main)也由 Git 自动推导,无需干预 - 如果你硬写了
"version": "1.0.0",又打了v2.0.0tag,Composer 仍坚持用 1.0.0——它不校验一致性,只认你写的字面值 - CI 流程里用
sed -i替换version是高危操作:Git diff 和 tag 元信息脱节,导致锁文件不可复现
什么时候可以(勉强)写 version 字段
仅限完全脱离 Git / SVN 的离线场景,且所有依赖方都用 "type": "path" 引入——比如内网共享目录部署、ZIP 包分发、无远程仓库的嵌入式项目。
- 必须同时满足:不托管在任何 VCS、不发布到 Packagist 或私有仓库、所有 require 都走
repositories.type = path - 即便如此,也建议改用
"minimum-stability": "dev"+"prefer-stable": false,再通过"myorg/myapp": "dev-main"显式引用分支,更可控 - 若真要写,值必须是合法语义化版本(如
"1.2.3"),不能是"1.2"或"v1.2.3";也不能带占位符如"@package_version@"(那只是某些构建脚本的 hack,Composer 不识别)
打 tag 才是真正生效的版本发布动作
版本号不是写出来的,是推出来的。Packagist 不看 composer.json,只抓远程 tag;下游用户装的也不是你本地文件,而是 tag 快照。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 打 tag 前先删掉
composer.json里的version字段(或确认为空) - 命令必须带
v前缀:git tag -a v2.1.3 -m "release",然后git push origin v2.1.3(漏v或用--tags推全量都可能触发非预期 tag) - Packagist 上已注册包需开启 auto-update;未注册则要手动 trigger sync,否则新 tag 不可见
- 验证是否成功:运行
composer show vendor/name,看输出的 version 是否为2.1.3,而非dev-main或其他 dev 分支名
下游怎么正确 require 你的版本
版本约束写法决定装什么,不是你“写了 version”就万事大吉。很多问题其实出在 require 方没写对,而不是你发版错了。
-
"vendor/name": "2.1.3"→ 精确锁定,不升级 -
"vendor/name": "^2.1.3"→ 允许>=2.1.3 ,安全兼容更新 -
"vendor/name": "~2.1.3"→ 仅允许补丁升级,即>=2.1.3 - 如果装出来是
dev-main,先检查是否忘了git push origin v2.1.3;再检查下游有没有配"minimum-stability": "dev";最后跑composer why-not vendor/name:2.1.3看冲突根源
最常被忽略的一点:tag 名必须严格符合语义化版本格式,v2.1、v2.1.0-rc1 都合法,但 2.1.0(缺 v)、v2_1_0(下划线)、V2.1.0(大写)都会让 Packagist 解析失败。

















