sbt-release 版本号管理完全指南:把发版工作全部交给 version.sbt
2026/9/12 5:29:46 网站建设 项目流程

sbt-release 版本号管理完全指南:把发版工作全部交给 version.sbt

【免费下载链接】dubThe modern link attribution platform. Loved by world-class marketing teams like Framer, Perplexity, Superhuman, Twilio, Buffer and more.项目地址: https://gitcode.com/GitHub_Trending/du/dub

做 Scala 项目发版,最容易翻车的就是版本号管理。sbt-release 用根目录下一个 version.sbt 文件和一条 sbt release 命令解决这个问题:升版本、打标签、发布、推送,全部交给流水线自动完成。

昨晚的翻车:一个 -SNAPSHOT 引发的事故

先讲个真实感很强的场景。

周三晚上十一点,你手动发布一个 Scala 服务:把 build.sbt 里的2.3.1-SNAPSHOT改成2.3.1,commit,打标签v2.3.1,执行发布。第二天早上同事炸了——下游项目拉到的正式依赖里混进了带-SNAPSHOT后缀的包,而且仓库里的标签是v2.3.0,少了个数字。排查半天发现:发布完你忘了把版本号改回下一个开发版,标签还打错了一位。

手改版本号、手打标签、手动发布,三步里错一步就是事故。这就是 sbt-release 想替你干掉的事。

五分钟跑起来:加一行插件,sbt release 就能发

project/plugins.sbt里加这一行(取最新版本号):

addSbtPlugin("com.github.sbt" % "sbt-release" % "1.4.2")

终端里敲sbt release。接下来是交互问答:先问"发哪个版本"(默认就是去掉-SNAPSHOT的当前版本),再问"下一个开发版叫什么"(默认加一后补-SNAPSHOT),一路回车即可。

跑完你会在项目根目录多出一个 version.sbt——它就是全文的主角,下面细说。

发布时的版本流转:version.sbt 被流水线写了两次

sbt-release 的默认发布流程(releaseProcess)一共十几个步骤,但和版本号直接相关的核心动作,是两次写入 version.sbt

阶段动作说明
1checkSnapshotDependencies检查是否混入 SNAPSHOT 依赖
2inquireVersions交互确认发布版与下一个开发版,给智能默认值
3clean + runTest清理并跑全部测试,失败即中止
4setReleaseVersion第一次写入:version.sbt 变成2.3.1
5commitReleaseVersion提交这次改动
6tagRelease打标签v2.3.1
7publishArtifacts发布制品到仓库
8setNextVersion第二次写入:version.sbt 变成2.3.2-SNAPSHOT
9commitNextVersion再次提交
10pushChanges推送提交与标签到远程

注意发布动作卡在两次写入中间:第一次写入让制品拿到正式版本号,第二次把代码送回开发状态。"发版 → 打标签 → 进入下一轮开发"的循环,一次流水线自动跑完,你不用碰任何一行版本号。

为什么 version.sbt 是独立文件:三个设计细节

它从不改你的构建定义。sbt 的构建定义本身就是 Scala 代码,在 build.sbt 中间手改数字既不直观也容易出错。sbt-release 的做法是:版本号单独放进 version.sbt,写到哪里由设置项releaseVersionFile决定,默认就是项目根目录(源码中该逻辑定义在 ReleasePlugin.scala),想换位置改一下配置即可。

默认是构建级写法。version.sbt 的内容通常就一行:

ThisBuild / version := "2.3.1"

ThisBuild / version意味着整个多模块项目共享一个版本号——对绝大多数仓库来说这正是正确答案。

想按模块单独管?一个开关的事。releaseUseGlobalVersion设为false,写入的就会是项目级的version := "2.3.1",各模块可以各走各的版本。

还有个容易被忽略的好处:version.sbt 就是普通 sbt 配置文件,你用文本编辑器直接改,sbt 立刻生效。临时要改个版本号又不想走完整发布流程时,这是最快的路。

六种版本升级策略对照表:该加一哪一位怎么选

下一个开发版本加一哪一位,不用你自己想。sbt-release 从 0.8 版本起内置了六种 Bump 策略(源码见 Version.scala):

策略行为示例什么时候用
Major主版本号 +11.2.3 → 2.0.0破坏性 API 变更
Minor次版本号 +11.2.3 → 1.3.0加新功能且向后兼容
Bugfix修订号 +11.2.3 → 1.2.4纯修复
Nano第四位 +11.2.3.4 → 1.2.3.5版本号超过三段的方案
Next(默认)智能判断该加一哪一位1.0.0-RC1 → 1.0.0-RC2通用默认:0.17 → 0.18,3.22.3.4.91 → 3.22.3.4.92
NextStable同 Next,但去掉预发布限定符1.0.0-RC1 → 1.0.0RC 收尾、正式转正

默认策略 Next 足够聪明,它会自动判断"哪个数字该加一"。想换策略时,在 build.sbt 里写一行releaseVersionBump := sbtrelease.Version.Bump.Major即可,其余不动。

无人值守发布与自定义版本规则

CI 里没人盯着怎么发

三个参数按需取用:

  • sbt "release with-defaults":所有交互取默认值,最适合 CI/CD 流水线;
  • sbt "release skip-tests":跳过测试,适合凌晨两点的救火版本;
  • 命令行直接钉死版本,连问答都省了:
sbt "release release-version 1.0.99 next-version 1.2.0-SNAPSHOT"

这条命令的含义:本次发 1.0.99,下一个开发版是 1.2.0-SNAPSHOT,其余流程照跑。脚本化发布时非常好用。

对默认推导不满意?两个设置键随便覆写

releaseVersion负责"当前开发版 → 正式发布版"的推导,releaseNextVersion负责"发布版 → 下一个开发版"。它们都是普通的 sbt 设置键,你可以用自己的函数整体替换默认逻辑。"主版本逢十进一"、"按发布日期命名"这类特殊规则,覆写一下就能落地,不用 fork 插件。

避坑清单:sbt 发布流程四个高频坑

  • 多模块被 ThisBuild 全库带飞:你只想升一个子模块的版本,结果所有模块版本号一起变了。想要各模块独立版本,记得releaseUseGlobalVersion := false并单独管理。
  • -SNAPSHOT 混进正式发布checkSnapshotDependencies查的是依赖里有没有 SNAPSHOT,管不了你自己的版本号。交互时把默认值看仔细,或直接用命令行参数钉死版本。
  • git 标签打错tagRelease默认按v前缀格式打标签(v2.3.1)。手动补标签时格式对不上,后续版本校验会报错,排查半天才发现是前缀少写了。
  • 发布前忘记提交:默认流程在两次写 version.sbt 后都会自动 commit;如果你自定义了流程跳过了提交步骤,标签会指在一个 version.sbt 还是旧号数的提交上,之后想复现这个版本就无从查起了。

今晚开始,回车就好

sbt-release 做的事情其实就一句话:把版本号从"散落在构建定义里的字符串"变成"独立、可读、可自动写入的文件",再配一条默认就够用的发布流水线。版本号管理交给它,你只负责回答"发不发"。

去你自己的项目里加一行插件,敲一下sbt release,下一个版本就交给流水线吧。


  • 官方文档:docs/official.md
  • AI功能源码:plugins/ai/

【免费下载链接】dubThe modern link attribution platform. Loved by world-class marketing teams like Framer, Perplexity, Superhuman, Twilio, Buffer and more.项目地址: https://gitcode.com/GitHub_Trending/du/dub

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询