语义化版本(SemVer)怎么理解?Maven 的 SNAPSHOT 和 RELEASE 有什么区别?
简化版
**语义化版本(Semantic Versioning,SemVer)是一套「用版本号表达变更含义」的约定,格式为 主版本.次版本.修订号(MAJOR.MINOR.PATCH,如 2.5.1):① 主版本(MAJOR)——有「不兼容的 API 变更」时 +1(升级可能破坏调用方,要小心);② 次版本(MINOR)——「向后兼容地新增功能」时 +1(加了新功能但老代码还能用);③ 修订号(PATCH)——「向后兼容的 bug 修复」时 +1(只修 bug、不加功能)。**核心思想:让使用者「看版本号就知道能不能放心升级」——PATCH/MINOR 升级安全(兼容)、MAJOR 升级要留意(可能不兼容)。Maven 的 SNAPSHOT vs RELEASE:① SNAPSHOT(快照版)——版本号带 -SNAPSHOT(如 1.0-SNAPSHOT),表示「开发中、不稳定、会变」的版本,同一个版本号可以反复覆盖发布(Maven 每次会拉最新的),用于开发协作阶段;② RELEASE(正式版)——不带 -SNAPSHOT(如 1.0),表示「稳定、固定、不可变」的版本,发布后不允许覆盖(同一版本号永远是同一份产物),保证依赖它的人拿到的始终一致。核心记忆:SemVer 主.次.修订(不兼容/新功能/修 bug)表达变更含义;SNAPSHOT 开发中可覆盖、RELEASE 正式版不可变。
详细版
SemVer:MAJOR.MINOR.PATCH:
| 位 | 何时 +1 | 含义 | 升级风险 |
|---|---|---|---|
| MAJOR 主版本 | 不兼容的 API 变更 | 破坏性变更 | 高(可能不兼容) |
| MINOR 次版本 | 向后兼容地新增功能 | 加新功能 | 低(兼容) |
| PATCH 修订号 | 向后兼容的 bug 修复 | 只修 bug | 低(兼容) |
2.5.1
│ │ └─ PATCH:修复了 bug(兼容,放心升)
│ └─── MINOR:加了新功能(兼容,放心升)
└───── MAJOR:不兼容变更(升级要小心,可能破坏调用)
规则:
高位 +1,低位归零:2.5.1 → 加功能 → 2.6.0(MINOR+1,PATCH 归零)
2.5.1 → 不兼容 → 3.0.0(MAJOR+1,其余归零)
预发布/构建元数据(扩展):
1.0.0-alpha、1.0.0-beta.1、1.0.0-rc.1(预发布,优先级低于正式)
1.0.0+build.123(构建元数据,不影响优先级)
SNAPSHOT vs RELEASE:
| 维度 | SNAPSHOT | RELEASE |
|---|---|---|
| 版本号 | 带 -SNAPSHOT(1.0-SNAPSHOT) | 不带(1.0) |
| 含义 | 开发中、不稳定、会变 | 稳定、固定 |
| 可覆盖 | 可以(反复发布同版本号) | 不可以(发布即固定) |
| Maven 行为 | 定期检查更新、拉最新 | 认为不变、缓存不再检查 |
| 用途 | 开发协作阶段 | 正式发布、生产依赖 |
⚠️ SNAPSHOT 的本质是「同一个版本号代表一个『会变的、开发中的』产物」——正因为它会变,Maven 才会对 SNAPSHOT 依赖『定期去仓库检查有没有新的』,而对 RELEASE 版本认为『永远不变,下过一次就永久缓存』。假设团队 A 开发的公共库
common:1.2-SNAPSHOT还在改,团队 B 依赖它——B 希望每天构建都能拿到 A 最新的改动,所以 A 反复deploy覆盖1.2-SNAPSHOT(私服其实用时间戳区分每次快照),B 的 Maven 会(按 updatePolicy,默认 daily)去私服拉最新的 SNAPSHOT。等 A 稳定了,发布common:1.2(RELEASE),从此1.2就固定不变,B 依赖1.2拿到的永远是同一份。生产环境绝不能依赖 SNAPSHOT——因为 SNAPSHOT 会变,今天构建和明天构建可能拿到不同的1.2-SNAPSHOT,导致「构建不可重现」(同样的代码,不同时间构建出不同结果)。
完整版教学
一、为什么需要语义化版本
先理解 SemVer 解决什么问题:
没有版本约定的混乱:
库作者随便打版本号(1.0 → 2.0 → 2.5...)
使用者不知道:
从 1.0 升到 2.0 会不会破坏我的代码?
这个新版本是加了功能还是只修了 bug?
→ 升级像开盲盒(不敢升,或升了出问题)
SemVer 的解决:用版本号"表达变更的含义"
MAJOR.MINOR.PATCH(主.次.修订)
→ 每位数字有明确含义,看版本号就知道变更类型
核心承诺:
PATCH 升级 → 只修 bug(兼容,放心升)
MINOR 升级 → 加了功能(兼容,放心升)
MAJOR 升级 → 不兼容变更(要小心,可能破坏)
带来的好处:
① 使用者能判断升级风险(看版本号)
② 可以安全地用版本范围(如"接受所有 1.x",因为 1.x 都兼容)
③ 生态协作有共同语言(大家都懂版本号含义)
所以 SemVer=用版本号表达变更含义,让使用者判断升级风险
SemVer 解决的问题:没有版本约定时——库作者随便打版本号、使用者不知道升级会不会破坏代码(升级像开盲盒)。SemVer 用版本号「表达变更的含义」:MAJOR.MINOR.PATCH(主.次.修订),每位有明确含义。核心承诺:PATCH 只修 bug(兼容)、MINOR 加功能(兼容)、MAJOR 不兼容变更(要小心)。好处:① 使用者能判断升级风险、② 能安全用版本范围(1.x 都兼容)、③ 生态协作有共同语言。理解「SemVer 解决:没约定时升级像开盲盒;用版本号表达变更含义(MAJOR.MINOR.PATCH);承诺 PATCH 修 bug、MINOR 加功能(都兼容)、MAJOR 不兼容;好处判断升级风险+安全用版本范围+共同语言」,就理解了为什么需要 SemVer。
二、MAJOR.MINOR.PATCH 三位的规则
理解三位数字的具体规则:
MAJOR.MINOR.PATCH 三位规则:
MAJOR(主版本):不兼容的 API 变更时 +1
- 删了/改了公开 API(调用方要改代码)
- 改了行为(同样调用结果不同)
→ 升级可能破坏调用方(要小心)
例:删除了一个 public 方法 → MAJOR+1
MINOR(次版本):向后兼容地新增功能时 +1
- 加了新的 public API(老 API 还在、还能用)
- 标记某 API 废弃(deprecated,但还没删)
→ 老代码不受影响(兼容)
例:加了一个新的 public 方法 → MINOR+1
PATCH(修订号):向后兼容的 bug 修复时 +1
- 只修 bug,不加功能、不改 API
→ 最安全的升级(兼容)
例:修了一个计算错误的 bug → PATCH+1
进位规则(高位变,低位归零):
2.5.1 修 bug → 2.5.2(PATCH+1)
2.5.1 加功能 → 2.6.0(MINOR+1,PATCH 归零)
2.5.1 不兼容 → 3.0.0(MAJOR+1,MINOR/PATCH 归零)
→ 高位一动,低位清零
0.x.y 特殊:
MAJOR=0(如 0.5.0)表示"初始开发、不稳定"
→ 此阶段任何版本都可能不兼容(不保证兼容规则)
→ 稳定了才发 1.0.0(正式承诺 SemVer 规则)
所以三位:MAJOR(不兼容)/MINOR(加功能)/PATCH(修 bug),高位变低位归零
MAJOR.MINOR.PATCH 三位规则:MAJOR(主版本)不兼容的 API 变更时 +1(删/改公开 API、改行为,升级可能破坏调用方);MINOR(次版本)向后兼容地新增功能时 +1(加新 public API、老 API 还在,兼容);PATCH(修订号)向后兼容的 bug 修复时 +1(只修 bug 不改 API,最安全)。进位规则:高位变、低位归零(2.5.1 修 bug→2.5.2、加功能→2.6.0、不兼容→3.0.0)。0.x.y 特殊:MAJOR=0 表示初始开发/不稳定(任何版本可能不兼容、稳定了才发 1.0.0)。理解「三位:MAJOR(不兼容 API 变更,可能破坏调用)/MINOR(向后兼容加功能)/PATCH(向后兼容修 bug);进位高位变低位归零(2.5.1→加功能→2.6.0→不兼容→3.0.0);0.x.y 初始开发不稳定」,就掌握了三位规则。
三、预发布版本与版本优先级
理解预发布版本和优先级比较:
预发布版本(pre-release):
在正式版之前的测试版本,加后缀(用 - 连接):
1.0.0-alpha(内测)
1.0.0-beta(公测)
1.0.0-rc.1(release candidate,候选发布)
→ 优先级低于正式版:1.0.0-alpha < 1.0.0
构建元数据(build metadata):
加 + 后缀(1.0.0+build.123)
→ 不影响优先级(只是标记构建信息)
版本优先级比较(谁"更新"):
① 先比 MAJOR.MINOR.PATCH(数值)
1.0.0 < 2.0.0,1.2.0 < 1.3.0
② 相同则有预发布的 < 没预发布的
1.0.0-alpha < 1.0.0(预发布比正式旧)
③ 预发布之间按标识符比
1.0.0-alpha < 1.0.0-beta < 1.0.0-rc.1
发布流程示例:
1.0.0-alpha → 1.0.0-beta → 1.0.0-rc.1 → 1.0.0(正式)
→ 逐步稳定,最后发正式版
为什么要预发布版:
让人提前试用、反馈,正式发布前发现问题
→ 但明确标记"还不稳定"(优先级低于正式)
所以预发布(alpha/beta/rc)优先级低于正式,构建元数据不影响优先级
预发布版本(pre-release):正式版之前的测试版本,加 - 后缀(1.0.0-alpha 内测、1.0.0-beta 公测、1.0.0-rc.1 候选发布),优先级低于正式版(1.0.0-alpha < 1.0.0)。构建元数据:加 + 后缀(1.0.0+build.123),不影响优先级。版本优先级比较:① 先比 MAJOR.MINOR.PATCH 数值、② 相同则有预发布的 < 没预发布的、③ 预发布之间按标识符比(alpha < beta < rc)。发布流程:alpha → beta → rc → 正式。理解「预发布(alpha 内测/beta 公测/rc 候选)优先级低于正式(1.0.0-alpha<1.0.0);构建元数据(+build)不影响优先级;比较先比数值、再有预发布<没预发布、预发布间 alpha<beta<rc;流程 alpha→beta→rc→正式」,就掌握了预发布和优先级。
四、SNAPSHOT vs RELEASE
理解 Maven 的 SNAPSHOT 和 RELEASE——高频考点:
SNAPSHOT(快照版):
版本号带 -SNAPSHOT(如 1.0-SNAPSHOT)
含义:开发中、不稳定、会变的版本
特点:
① 同一个版本号可以反复覆盖发布(deploy 多次)
→ 开发中频繁改、频繁发,不用每次改版本号
② Maven 会"定期检查更新"(拉最新的 SNAPSHOT)
→ 依赖 SNAPSHOT 的人能拿到最新改动
③ 私服用时间戳区分每次快照(1.0-20240101.120000-1)
用途:开发协作阶段(团队间共享开发中的库)
RELEASE(正式版):
版本号不带 -SNAPSHOT(如 1.0)
含义:稳定、固定、不可变的版本
特点:
① 发布后不允许覆盖(同版本号永远是同一份)
→ 保证依赖它的人拿到的始终一致
② Maven 认为它"永远不变",下过一次永久缓存
→ 不再去仓库检查(快,且可重现)
用途:正式发布、生产依赖
关键区别(一句话):
SNAPSHOT 会变(可覆盖、Maven 定期拉最新)
RELEASE 不变(不可覆盖、Maven 永久缓存)
Maven 的行为差异:
SNAPSHOT:按 updatePolicy(默认 daily)检查更新
mvn -U 强制立即更新
RELEASE:认为不变,本地有就不再检查
所以 SNAPSHOT(开发中可覆盖会变)、RELEASE(正式固定不可变)
SNAPSHOT(快照版):版本号带 -SNAPSHOT(1.0-SNAPSHOT),含义开发中/不稳定/会变;特点:① 同版本号可反复覆盖发布(开发中频繁改发)、② Maven 定期检查更新(拉最新 SNAPSHOT)、③ 私服用时间戳区分每次快照;用途开发协作阶段。RELEASE(正式版):不带 -SNAPSHOT(1.0),含义稳定/固定/不可变;特点:① 发布后不允许覆盖(同版本号永远同一份)、② Maven 认为永远不变、永久缓存(不再检查);用途正式发布、生产依赖。关键区别:SNAPSHOT 会变(可覆盖、定期拉最新)、RELEASE 不变(不可覆盖、永久缓存)。Maven 行为:SNAPSHOT 按 updatePolicy(默认 daily)检查、mvn -U 强制更新;RELEASE 认为不变本地有就不检查。理解「SNAPSHOT(带-SNAPSHOT,开发中会变,可反复覆盖,Maven 定期拉最新,时间戳区分)、RELEASE(不带,稳定不可变,不许覆盖,永久缓存);SNAPSHOT 会变、RELEASE 不变;mvn -U 强制更新 SNAPSHOT」,就掌握了 SNAPSHOT vs RELEASE。
五、为什么生产不能依赖 SNAPSHOT
理解生产环境为什么禁用 SNAPSHOT——重要实践:
为什么生产/发布不能依赖 SNAPSHOT:
核心问题:SNAPSHOT 会变 → 构建不可重现
假设你的应用依赖 common:1.2-SNAPSHOT
今天构建:拉到 common 的 A 版本
明天构建:common 又被改了,拉到 B 版本
→ 同样的应用代码,不同时间构建出不同结果
→ "构建不可重现"(无法保证线上跑的是哪份)
带来的风险:
① 线上出问题难排查(不知道用的哪版 SNAPSHOT)
② 回滚困难(同版本号内容已变)
③ 多人/多机构建结果不一致
正确做法:
① 开发阶段:用 SNAPSHOT(团队协作,拉最新)
② 发布/生产:必须用 RELEASE(固定版本,可重现)
→ 发版前把依赖的 SNAPSHOT 都换成 RELEASE
③ 你自己的应用发版:也从 SNAPSHOT 转 RELEASE
1.0-SNAPSHOT(开发)→ 1.0(发布)→ 1.1-SNAPSHOT(下轮开发)
Maven 的保护:
release 插件(maven-release-plugin)会检查:
有 SNAPSHOT 依赖时不允许发 release(强制先解决)
版本迭代节奏:
1.0-SNAPSHOT(开发 1.0)→ 发布 1.0
→ 1.1-SNAPSHOT(开发 1.1)→ 发布 1.1 → ...
→ 开发期 SNAPSHOT、发布转 RELEASE、下轮再 SNAPSHOT
所以生产禁用 SNAPSHOT(会变、构建不可重现),发版必须转 RELEASE
为什么生产不能依赖 SNAPSHOT:核心问题——SNAPSHOT 会变、构建不可重现(今天拉 A 版本、明天 common 被改拉 B 版本、同样代码不同时间构建出不同结果)。风险:① 线上出问题难排查、② 回滚困难、③ 多人多机结果不一致。正确做法:① 开发阶段用 SNAPSHOT(拉最新)、② 发布/生产必须用 RELEASE(固定可重现)、③ 应用发版从 SNAPSHOT 转 RELEASE。Maven 保护:maven-release-plugin 有 SNAPSHOT 依赖时不允许发 release。版本节奏:1.0-SNAPSHOT(开发)→ 1.0(发布)→ 1.1-SNAPSHOT(下轮)。理解「生产禁用 SNAPSHOT 因会变、构建不可重现(今天 A 明天 B);风险难排查+回滚难+不一致;做法开发用 SNAPSHOT、发布转 RELEASE;release 插件有 SNAPSHOT 依赖不许发;节奏 1.0-SNAPSHOT→1.0→1.1-SNAPSHOT」,就掌握了为什么生产禁用 SNAPSHOT。
六、实践与总结
总结 SemVer 和 SNAPSHOT/RELEASE 的实践:
SemVer 实践:
① 打版本号按含义:改 bug→PATCH、加功能→MINOR、不兼容→MAJOR
② 稳定后才发 1.0.0(0.x 是初始不稳定期)
③ 用预发布版试水(alpha/beta/rc)再发正式
④ 破坏性变更一定升 MAJOR(别在 MINOR/PATCH 偷偷改)
SNAPSHOT/RELEASE 实践:
① 开发中用 SNAPSHOT(团队协作、拉最新)
② 发布/生产用 RELEASE(固定、可重现)
③ 发版前把 SNAPSHOT 依赖都转成 RELEASE
④ 用 mvn -U 强制更新 SNAPSHOT(拉最新)
常见误区提醒:
✗ 生产依赖 SNAPSHOT(构建不可重现,大坑)
✗ 破坏性变更不升 MAJOR(违背 SemVer,坑使用者)
核心总结:
SemVer:MAJOR.MINOR.PATCH(不兼容/加功能/修 bug)表达变更含义
让使用者看版本号判断升级风险
SNAPSHOT:开发中、会变、可覆盖、Maven 定期拉最新
RELEASE:稳定、不变、不可覆盖、Maven 永久缓存
生产必须用 RELEASE(SNAPSHOT 会导致构建不可重现)
SemVer 实践:① 按含义打版本号(bug→PATCH、功能→MINOR、不兼容→MAJOR)、② 稳定后才发 1.0.0、③ 用预发布版试水、④ 破坏性变更一定升 MAJOR。SNAPSHOT/RELEASE 实践:① 开发用 SNAPSHOT、② 发布/生产用 RELEASE、③ 发版前把 SNAPSHOT 转 RELEASE、④ mvn -U 强制更新。误区:生产依赖 SNAPSHOT(构建不可重现)、破坏性变更不升 MAJOR。理解「SemVer 实践按含义打版本+稳定才 1.0+预发布试水+破坏升 MAJOR;SNAPSHOT/RELEASE 开发用 SNAPSHOT、发布用 RELEASE、发版前转;误区生产依赖 SNAPSHOT+破坏不升 MAJOR;SemVer 表达变更含义、SNAPSHOT 会变、RELEASE 不变、生产用 RELEASE」,就掌握了实践与总结。
记忆钩子:「语义化版本 SemVer=MAJOR.MINOR.PATCH(主.次.修订),用版本号表达变更含义:①MAJOR 不兼容 API 变更+1(升级可能破坏调用,要小心)②MINOR 向后兼容加功能+1(老代码还能用,放心升)③PATCH 向后兼容修 bug+1(最安全);进位高位变低位归零(2.5.1 加功能→2.6.0、不兼容→3.0.0),0.x 是初始不稳定期稳定才发 1.0.0;预发布 alpha/beta/rc 优先级低于正式;★Maven SNAPSHOT(带-SNAPSHOT,开发中、会变、可反复覆盖发布、Maven 定期拉最新、私服时间戳区分)vs RELEASE(不带、稳定、不可变、发布后不许覆盖、Maven 永久缓存);关键 SNAPSHOT 会变、RELEASE 不变;生产/发布必须用 RELEASE(SNAPSHOT 会变导致构建不可重现,今天 A 明天 B),mvn -U 强制更新 SNAPSHOT」。
七、常见误区与追问
- 误区:版本号就是随便递增的数字。 语义化版本(SemVer)的每一位都有明确含义:MAJOR.MINOR.PATCH——MAJOR 递增表示有不兼容的 API 变更(升级可能破坏调用方)、MINOR 递增表示向后兼容地新增了功能(老代码还能用)、PATCH 递增表示向后兼容的 bug 修复;使用者看版本号就能判断升级风险,而不是靠猜。
- 误区:加了新功能应该升 MAJOR。 加新功能(且不破坏老 API)应该升 MINOR,不是 MAJOR——MAJOR 只在「不兼容的破坏性变更」(删除/修改公开 API、改变行为,导致调用方要改代码)时才升;如果加个新方法就升 MAJOR,会让使用者误以为是破坏性变更、不敢升级;反过来,破坏性变更却只升 MINOR/PATCH 更糟(使用者以为兼容、放心升,结果代码坏了)。
- 误区:SNAPSHOT 和 RELEASE 只是命名习惯,没实质区别。 有实质区别:SNAPSHOT(带 -SNAPSHOT)是「开发中、会变」的版本,同一版本号可以反复覆盖发布,Maven 会定期去仓库检查更新、拉最新的;RELEASE(不带 -SNAPSHOT)是「稳定、不可变」的版本,发布后不允许覆盖,Maven 认为它永远不变、下过一次就永久缓存不再检查;这个区别直接影响构建的可重现性。
- 误区:生产环境依赖 SNAPSHOT 版本也没问题。 大问题——SNAPSHOT 会变(同一个 1.2-SNAPSHOT 今天和明天的内容可能不同),导致「构建不可重现」:同样的应用代码,不同时间/不同机器构建可能拉到不同的 SNAPSHOT 内容,出问题难排查、回滚困难;生产/发布必须依赖 RELEASE(固定版本),发版前要把所有 SNAPSHOT 依赖换成 RELEASE。
- 追问:SemVer 的 MAJOR、MINOR、PATCH 分别什么时候递增? MAJOR(主版本):发生「不兼容的 API 变更」时递增,比如删除或修改了公开 API、改变了已有行为,升级后调用方可能需要改代码;MINOR(次版本):「向后兼容地新增功能」时递增,比如加了新的公开 API 但老 API 还能用;PATCH(修订号):「向后兼容的 bug 修复」时递增,只修 bug、不加功能、不改 API;进位规则是高位递增、低位归零(如 2.5.1 加功能变 2.6.0、不兼容变 3.0.0);另外 MAJOR 为 0(0.x.y)表示初始开发期、不保证兼容规则,稳定后才发 1.0.0。
- 追问:Maven 的 SNAPSHOT 和 RELEASE 有什么区别? SNAPSHOT(版本号带 -SNAPSHOT,如 1.0-SNAPSHOT)表示开发中、不稳定、会变的版本:可以反复覆盖发布同一个版本号(私服内部用时间戳区分每次快照),Maven 会按 updatePolicy(默认每天)去仓库检查有没有新的 SNAPSHOT、拉最新的,用于开发协作阶段;RELEASE(不带 -SNAPSHOT,如 1.0)表示稳定、固定、不可变的版本:发布后不允许覆盖(同版本号永远是同一份产物),Maven 认为它永远不变、下过一次就永久缓存不再检查,用于正式发布和生产依赖;一句话:SNAPSHOT 会变(可覆盖、定期拉最新),RELEASE 不变(不可覆盖、永久缓存)。
- 追问:为什么发布正式版本前要把 SNAPSHOT 依赖都换成 RELEASE? 因为 SNAPSHOT 会变——如果你的正式版依赖某个 SNAPSHOT,那么这个 SNAPSHOT 之后被别人改了、覆盖发布了,你的「正式版」实际依赖的内容就变了,导致「同一个正式版号在不同时间构建/部署时行为不同」,违背了 RELEASE「固定不可变」的承诺、破坏构建可重现性;所以 maven-release-plugin 在发布 release 时会检查,如果还有 SNAPSHOT 依赖就拒绝发布,强制你先把依赖都换成确定的 RELEASE 版本,保证正式版是完全固定、可重现的。
八、加强记忆
语义化版本(SemVer)是「用版本号表达变更含义」的约定,格式 MAJOR.MINOR.PATCH(主.次.修订,如 2.5.1):① MAJOR(主版本)——不兼容的 API 变更时 +1(升级可能破坏调用方、要小心)、② MINOR(次版本)——向后兼容地新增功能时 +1(老代码还能用、放心升)、③ PATCH(修订号)——向后兼容的 bug 修复时 +1(最安全);进位「高位变、低位归零」(2.5.1 加功能→2.6.0、不兼容→3.0.0),0.x 是初始不稳定期、稳定才发 1.0.0;预发布 alpha/beta/rc 优先级低于正式。核心思想:让使用者看版本号就知道能不能放心升级。Maven 的 SNAPSHOT vs RELEASE:SNAPSHOT(带 -SNAPSHOT,如 1.0-SNAPSHOT)——开发中、会变、可反复覆盖发布、Maven 定期拉最新(私服用时间戳区分);RELEASE(不带,如 1.0)——稳定、不可变、发布后不许覆盖、Maven 永久缓存。关键:SNAPSHOT 会变、RELEASE 不变;生产/发布必须用 RELEASE(SNAPSHOT 会导致「构建不可重现」——同样代码不同时间构建出不同结果),mvn -U 强制更新 SNAPSHOT。一句话「SemVer=MAJOR.MINOR.PATCH(不兼容/加功能/修 bug)表达变更含义,让使用者判断升级风险,高位变低位归零;SNAPSHOT(开发中会变可覆盖、Maven 定期拉最新)、RELEASE(稳定不变不可覆盖、永久缓存);生产必须用 RELEASE,SNAPSHOT 会导致构建不可重现」。