feat: ✨ 基础模块
注册登录 用户管理 角色管理 部门管理 消息管理 接口管理 菜单管理 字典管理 缓存管理 请求日志 系统设置 版本信息 代码生成
182
docs/CONTRIBUTING.md
Normal file
@ -0,0 +1,182 @@
|
||||
# 约定式提交 1.0.0
|
||||
|
||||
## [](#概述)概述
|
||||
|
||||
约定式提交规范是一种基于提交信息的轻量级约定。 它提供了一组简单规则来创建清晰的提交历史; 这更有利于编写自动化工具。 通过在提交信息中描述功能、修复和破坏性变更, 使这种惯例与 [SemVer](http://semver.org/lang/zh-CN) 相互对应。
|
||||
|
||||
提交说明的结构如下所示:
|
||||
|
||||
* * *
|
||||
|
||||
原文:
|
||||
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
|
||||
|
||||
译文:
|
||||
|
||||
<类型>[可选 范围]: <描述>
|
||||
|
||||
[可选 正文]
|
||||
|
||||
[可选 脚注]
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
提交说明包含了下面的结构化元素,以向类库使用者表明其意图:
|
||||
|
||||
1. **fix:** _类型_ 为 `fix` 的提交表示在代码库中修复了一个 bug(这和语义化版本中的 [`PATCH`](https://semver.org/lang/zh-CN/#%E6%91%98%E8%A6%81) 相对应)。
|
||||
2. **feat:** _类型_ 为 `feat` 的提交表示在代码库中新增了一个功能(这和语义化版本中的 [`MINOR`](https://semver.org/lang/zh-CN/#%E6%91%98%E8%A6%81) 相对应)。
|
||||
3. **BREAKING CHANGE:** 在脚注中包含 `BREAKING CHANGE:` 或 <类型>(范围) 后面有一个 `!` 的提交,表示引入了破坏性 API 变更(这和语义化版本中的 [`MAJOR`](https://semver.org/lang/zh-CN/#%E6%91%98%E8%A6%81) 相对应)。 破坏性变更可以是任意 _类型_ 提交的一部分。
|
||||
4. 除 `fix:` 和 `feat:` 之外,也可以使用其它提交 _类型_ ,例如 [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional)(基于 [Angular 约定](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines))中推荐的 `build:`、`chore:`、 `ci:`、`docs:`、`style:`、`refactor:`、`perf:`、`test:`,等等。
|
||||
* build: 用于修改项目构建系统,例如修改依赖库、外部接口或者升级 Node 版本等;
|
||||
* chore: 用于对非业务性代码进行修改,例如修改构建流程或者工具配置等;
|
||||
* ci: 用于修改持续集成流程,例如修改 Travis、Jenkins 等工作流配置;
|
||||
* docs: 用于修改文档,例如修改 README 文件、API 文档等;
|
||||
* style: 用于修改代码的样式,例如调整缩进、空格、空行等;
|
||||
* refactor: 用于重构代码,例如修改代码结构、变量名、函数名等但不修改功能逻辑;
|
||||
* perf: 用于优化性能,例如提升代码的性能、减少内存占用等;
|
||||
* test: 用于修改测试用例,例如添加、删除、修改代码的测试用例等。
|
||||
5. 脚注中除了 `BREAKING CHANGE: <description>` ,其它条目应该采用类似 [git trailer format](https://git-scm.com/docs/git-interpret-trailers) 这样的惯例。
|
||||
|
||||
其它提交类型在约定式提交规范中并没有强制限制,并且在语义化版本中没有隐式影响(除非它们包含 BREAKING CHANGE)。 可以为提交类型添加一个围在圆括号内的范围,以为其提供额外的上下文信息。例如 `feat(parser): adds ability to parse arrays.`。
|
||||
|
||||
## [](#示例)示例
|
||||
|
||||
### [](#包含了描述并且脚注中有破坏性变更的提交说明)包含了描述并且脚注中有破坏性变更的提交说明
|
||||
|
||||
feat: allow provided config object to extend other configs
|
||||
|
||||
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
|
||||
|
||||
|
||||
### [](#包含了--字符以提醒注意破坏性变更的提交说明)包含了 `!` 字符以提醒注意破坏性变更的提交说明
|
||||
|
||||
feat!: send an email to the customer when a product is shipped
|
||||
|
||||
|
||||
### [](#包含了范围和破坏性变更--的提交說明)包含了范围和破坏性变更 `!` 的提交說明
|
||||
|
||||
feat(api)!: send an email to the customer when a product is shipped
|
||||
|
||||
|
||||
### [](#包含了--和-breaking-change-脚注的提交说明)包含了 `!` 和 BREAKING CHANGE 脚注的提交说明
|
||||
|
||||
chore!: drop support for Node 6
|
||||
|
||||
BREAKING CHANGE: use JavaScript features not available in Node 6.
|
||||
|
||||
|
||||
### [](#不包含正文的提交说明)不包含正文的提交说明
|
||||
|
||||
docs: correct spelling of CHANGELOG
|
||||
|
||||
|
||||
### [](#包含范围的提交说明)包含范围的提交说明
|
||||
|
||||
feat(lang): add polish language
|
||||
|
||||
|
||||
### [](#包含多行正文和多行脚注的提交说明)包含多行正文和多行脚注的提交说明
|
||||
|
||||
fix: prevent racing of requests
|
||||
|
||||
Introduce a request id and a reference to latest request. Dismiss
|
||||
incoming responses other than from latest request.
|
||||
|
||||
Remove timeouts which were used to mitigate the racing issue but are
|
||||
obsolete now.
|
||||
|
||||
Reviewed-by: Z
|
||||
Refs: #123
|
||||
|
||||
|
||||
## [](#约定式提交规范)约定式提交规范
|
||||
|
||||
本文中的关键词 “必须(MUST)”、“禁止(MUST NOT)”、“必要(REQUIRED)”、“应当(SHALL)”、“不应当(SHALL NOT)”、“应该(SHOULD)”、“不应该(SHOULD NOT)”、“推荐(RECOMMENDED)”、“可以(MAY)” 和 “可选(OPTIONAL)” ,其相关解释参考 [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) 。
|
||||
|
||||
1. 每个提交都**必须**使用类型字段前缀,它由一个名词构成,诸如 `feat` 或 `fix` , 其后接**可选的**范围字段,**可选的** `!`,以及**必要的**冒号(英文半角)和空格。
|
||||
2. 当一个提交为应用或类库实现了新功能时,**必须**使用 `feat` 类型。
|
||||
3. 当一个提交为应用修复了 bug 时,**必须**使用 `fix` 类型。
|
||||
4. 范围字段**可以**跟随在类型字段后面。范围**必须**是一个描述某部分代码的名词,并用圆括号包围,例如: `fix(parser):`
|
||||
5. 描述字段**必须**直接跟在 <类型>(范围) 前缀的冒号和空格之后。 描述指的是对代码变更的简短总结,例如: _fix: array parsing issue when multiple spaces were contained in string_ 。
|
||||
6. 在简短描述之后,**可以**编写较长的提交正文,为代码变更提供额外的上下文信息。正文**必须**起始于描述字段结束的一个空行后。
|
||||
7. 提交的正文内容自由编写,并**可以**使用空行分隔不同段落。
|
||||
8. 在正文结束的一个空行之后,**可以**编写一行或多行脚注。每行脚注都**必须**包含 一个令牌(token),后面紧跟 `:<space>` 或 `<space>#` 作为分隔符,后面再紧跟令牌的值(受 [git trailer convention](https://git-scm.com/docs/git-interpret-trailers) 启发)。
|
||||
9. 脚注的令牌**必须**使用 `-` 作为连字符,比如 `Acked-by` (这样有助于 区分脚注和多行正文)。有一种例外情况就是 `BREAKING CHANGE`,它**可以**被认为是一个令牌。
|
||||
10. 脚注的值**可以**包含空格和换行,值的解析过程**必须**直到下一个脚注的令牌/分隔符出现为止。
|
||||
11. 破坏性变更**必须**在提交信息中标记出来,要么在 <类型>(范围) 前缀中标记,要么作为脚注的一项。
|
||||
12. 包含在脚注中时,破坏性变更**必须**包含大写的文本 `BREAKING CHANGE`,后面紧跟着冒号、空格,然后是描述,例如: _BREAKING CHANGE: environment variables now take precedence over config files_ 。
|
||||
13. 包含在 <类型>(范围) 前缀时,破坏性变更**必须**通过把 `!` 直接放在 `:` 前面标记出来。 如果使用了 `!`,那么脚注中**可以**不写 `BREAKING CHANGE:`, 同时提交信息的描述中**应该**用来描述破坏性变更。
|
||||
14. 在提交说明中,**可以**使用 `feat` 和 `fix` 之外的类型,比如:_docs: updated ref docs._ 。
|
||||
15. 工具的实现必须**不区分**大小写地解析构成约定式提交的信息单元,只有 `BREAKING CHANGE` **必须**是大写的。
|
||||
16. BREAKING-CHANGE 作为脚注的令牌时**必须**是 BREAKING CHANGE 的同义词。
|
||||
|
||||
## [](#为什么使用约定式提交)为什么使用约定式提交
|
||||
|
||||
* 自动化生成 CHANGELOG。
|
||||
* 基于提交的类型,自动决定语义化的版本变更。
|
||||
* 向同事、公众与其他利益关系者传达变化的性质。
|
||||
* 触发构建和部署流程。
|
||||
* 让人们探索一个更加结构化的提交历史,以便降低对你的项目做出贡献的难度。
|
||||
|
||||
## [](#faq)FAQ
|
||||
|
||||
### [](#在初始开发阶段我该如何处理提交说明)在初始开发阶段我该如何处理提交说明?
|
||||
|
||||
我们建议你按照假设你已发布了产品那样来处理。因为通常总 _有人_ 使用你的软件,即便那是你软件开发的同事们。他们会希望知道诸如修复了什么、哪里不兼容等信息。
|
||||
|
||||
### [](#提交标题中的类型是大写还是小写)提交标题中的类型是大写还是小写?
|
||||
|
||||
大小写都可以,但最好是一致的。
|
||||
|
||||
### [](#如果提交符合多种类型我该如何操作)如果提交符合多种类型我该如何操作?
|
||||
|
||||
回退并尽可能创建多次提交。约定式提交的好处之一是能够促使我们做出更有组织的提交和 PR。
|
||||
|
||||
### [](#这不会阻碍快速开发和迭代吗)这不会阻碍快速开发和迭代吗?
|
||||
|
||||
它阻碍的是以杂乱无章的方式快速前进。它助你能在横跨多个项目以及和多个贡献者协作时长期地快速演进。
|
||||
|
||||
### [](#约定式提交会让开发者受限于提交的类型吗因为他们会想着已提供的类型)约定式提交会让开发者受限于提交的类型吗(因为他们会想着已提供的类型)?
|
||||
|
||||
约定式提交鼓励我们更多地使用某些类型的提交,比如 `fixes`。除此之外,约定式提交的灵活性也允许你的团队使用自己的类型,并随着时间的推移更改这些类型。
|
||||
|
||||
### [](#这和-semver-有什么关联呢)这和 SemVer 有什么关联呢?
|
||||
|
||||
`fix` 类型提交应当对应到 `PATCH` 版本。`feat` 类型提交应该对应到 `MINOR` 版本。带有 `BREAKING CHANGE` 的提交不管类型如何,都应该对应到 `MAJOR` 版本。
|
||||
|
||||
### [](#我对约定式提交做了形如-jameswomackconventional-commit-spec-的扩展该如何版本化管理这些扩展呢)我对约定式提交做了形如 `@jameswomack/conventional-commit-spec` 的扩展,该如何版本化管理这些扩展呢?
|
||||
|
||||
我们推荐使用 SemVer 来发布你对于这个规范的扩展(并鼓励你创建这些扩展!)
|
||||
|
||||
### [](#如果我不小心使用了错误的提交类型该怎么办呢)如果我不小心使用了错误的提交类型,该怎么办呢?
|
||||
|
||||
#### [](#当你使用了在规范中但错误的类型时例如将-feat-写成了-fix)当你使用了在规范中但错误的类型时,例如将 `feat` 写成了 `fix`
|
||||
|
||||
在合并或发布这个错误之前,我们建议使用 `git rebase -i` 来编辑提交历史。而在发布之后,根据你使用的工具和流程不同,会有不同的清理方案。
|
||||
|
||||
#### [](#当使用了-不在-规范中的类型时例如将-feat-写成了-feet)当使用了 _不在_ 规范中的类型时,例如将 `feat` 写成了 `feet`
|
||||
|
||||
在最坏的场景下,即便提交没有满足约定式提交的规范,也不会是世界末日。这只意味着这个提交会被基于规范的工具错过而已。
|
||||
|
||||
### [](#所有的贡献者都需要使用约定式提交规范吗)所有的贡献者都需要使用约定式提交规范吗?
|
||||
|
||||
并不!如果你使用基于 squash 的 Git 工作流,主管维护者可以在合并时清理提交信息——这不会对普通提交者产生额外的负担。 有种常见的工作流是让 git 系统自动从 pull request 中 squash 出提交,并向主管维护者提供一份表单,用以在合并时输入合适的 git 提交信息。
|
||||
|
||||
### [](#约定式提交规范中如何处理还原revert提交)约定式提交规范中如何处理还原(revert)提交?
|
||||
|
||||
还原提交(Reverting)会比较复杂:你还原的是多个提交吗?如果你还原了一个功能模块,下次发布的应该是补丁吗?
|
||||
|
||||
约定式提交不能明确的定义还原行为。所以我们把这个问题留给工具开发者, 基于 _类型_ 和 _脚注_ 的灵活性来开发他们自己的还原处理逻辑。
|
||||
|
||||
一种建议是使用 `revert` 类型,和一个指向被还原提交摘要的脚注:
|
||||
|
||||
revert: let us never again speak of the noodle incident
|
||||
|
||||
Refs: 676104e, a215868
|
226
docs/SEMVER.md
Normal file
@ -0,0 +1,226 @@
|
||||
语义化版本 2.0.0
|
||||
===
|
||||
|
||||
摘要
|
||||
---
|
||||
|
||||
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
|
||||
|
||||
1. 主版本号:当你做了不兼容的 API 修改,
|
||||
2. 次版本号:当你做了向下兼容的功能性新增,
|
||||
3. 修订号:当你做了向下兼容的问题修正。
|
||||
|
||||
先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
|
||||
|
||||
简介
|
||||
---
|
||||
|
||||
在软件管理的领域里存在着被称作“依赖地狱”的死亡之谷,系统规模越大,加入的包越多,你就越有可能在未来的某一天发现自己已深陷绝望之中。
|
||||
|
||||
在依赖高的系统中发布新版本包可能很快会成为噩梦。如果依赖关系过高,可能面临版本控制被锁死的风险(必须对每一个依赖包改版才能完成某次升级)。而如果依赖关系过于松散,又将无法避免版本的混乱(假设兼容于未来的多个版本已超出了合理数量)。当你项目的进展因为版本依赖被锁死或版本混乱变得不够简便和可靠,就意味着你正处于依赖地狱之中。
|
||||
|
||||
作为这个问题的解决方案之一,我提议用一组简单的规则及条件来约束版本号的配置和增长。这些规则是根据(但不局限于)已经被各种封闭、开放源码软件所广泛使用的惯例所设计。为了让这套理论运作,你必须先有定义好的公共 API。这可能包括文档或代码的强制要求。无论如何,这套 API 的清楚明了是十分重要的。一旦你定义了公共 API,你就可以透过修改相应的版本号来向大家说明你的修改。考虑使用这样的版本号格式:X.Y.Z(主版本号.次版本号.修订号)修复问题但不影响 API 时,递增修订号;API 保持向下兼容的新增及修改时,递增次版本号;进行不向下兼容的修改时,递增主版本号。
|
||||
|
||||
我称这套系统为“语义化的版本控制”,在这套约定下,版本号及其更新方式包含了相邻版本间的底层代码和修改内容的信息。
|
||||
|
||||
语义化版本控制规范(SemVer)
|
||||
---
|
||||
|
||||
以下关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的叙述解读。
|
||||
|
||||
1. 使用语义化版本控制的软件必须(MUST)定义公共 API。该 API 可以在代码中被定义或出现于严谨的文档内。无论何种形式都应该力求精确且完整。
|
||||
|
||||
2. 标准的版本号必须(MUST)采用 X.Y.Z 的格式,其中 X、Y 和 Z 为非负的整数,且禁止(MUST NOT)在数字前方补零。X 是主版本号、Y 是次版本号、而 Z 为修订号。每个元素必须(MUST)以数值来递增。例如:1.9.1 -> 1.10.0 -> 1.11.0。
|
||||
|
||||
3. 标记版本号的软件发行后,禁止(MUST NOT)改变该版本软件的内容。任何修改都必须(MUST)以新版本发行。
|
||||
|
||||
4. 主版本号为零(0.y.z)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。
|
||||
|
||||
5. 1.0.0 的版本号用于界定公共 API 的形成。这一版本之后所有的版本号更新都基于公共 API 及其修改内容。
|
||||
|
||||
6. 修订号 Z(x.y.Z `|` x > 0)必须(MUST)在只做了向下兼容的修正时才递增。这里的修正指的是针对不正确结果而进行的内部修改。
|
||||
|
||||
7. 次版本号 Y(x.Y.z `|` x > 0)必须(MUST)在有向下兼容的新功能出现时递增。在任何公共 API 的功能被标记为弃用时也必须(MUST)递增。也可以(MAY)在内部程序有大量新功能或改进被加入时递增,其中可以(MAY)包括修订级别的改变。每当次版本号递增时,修订号必须(MUST)归零。
|
||||
|
||||
8. 主版本号 X(X.y.z `|` X > 0)必须(MUST)在有任何不兼容的修改被加入公共 API 时递增。其中可以(MAY)包括次版本号及修订级别的改变。每当主版本号递增时,次版本号和修订号必须(MUST)归零。
|
||||
|
||||
9. 先行版本号可以(MAY)被标注在修订版之后,先加上一个连接号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。数字型的标识符禁止(MUST NOT)在前方补零。先行版的优先级低于相关联的标准版本。被标上先行版本号则表示这个版本并非稳定而且可能无法满足预期的兼容性需求。范例:1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。
|
||||
|
||||
10. 版本编译信息可以(MAY)被标注在修订版或先行版本号之后,先加上一个加号再加上一连串以句点分隔的标识符来修饰。标识符必须(MUST)由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成,且禁止(MUST NOT)留白。当判断版本的优先层级时,版本编译信息可(SHOULD)被忽略。因此当两个版本只有在版本编译信息有差别时,属于相同的优先层级。范例:1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。
|
||||
|
||||
11. 版本的优先层级指的是不同版本在排序时如何比较。
|
||||
|
||||
1. 判断优先层级时,必须(MUST)把版本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较(版本编译信息不在这份比较的列表中)。
|
||||
|
||||
2. 由左到右依序比较每个标识符,第一个差异值用来决定优先层级:主版本号、次版本号及修订号以数值比较。
|
||||
|
||||
例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。
|
||||
|
||||
3. 当主版本号、次版本号及修订号都相同时,改以优先层级比较低的先行版本号决定。
|
||||
|
||||
例如:1.0.0-alpha < 1.0.0。
|
||||
|
||||
4. 有相同主版本号、次版本号及修订号的两个先行版本号,其优先层级必须(MUST)透过由左到右的每个被句点分隔的标识符来比较,直到找到一个差异值后决定:
|
||||
|
||||
1. 只有数字的标识符以数值高低比较。
|
||||
|
||||
2. 有字母或连接号时则逐字以 ASCII 的排序来比较。
|
||||
|
||||
3. 数字的标识符比非数字的标识符优先层级低。
|
||||
|
||||
4. 若开头的标识符都相同时,栏位比较多的先行版本号优先层级比较高。
|
||||
|
||||
例如:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0。
|
||||
|
||||
合法语义化版本的巴科斯范式语法
|
||||
--------------------------------------------------
|
||||
```
|
||||
<valid semver> ::= <version core>
|
||||
| <version core> "-" <pre-release>
|
||||
| <version core> "+" <build>
|
||||
| <version core> "-" <pre-release> "+" <build>
|
||||
|
||||
<version core> ::= <major> "." <minor> "." <patch>
|
||||
|
||||
<major> ::= <numeric identifier>
|
||||
|
||||
<minor> ::= <numeric identifier>
|
||||
|
||||
<patch> ::= <numeric identifier>
|
||||
|
||||
<pre-release> ::= <dot-separated pre-release identifiers>
|
||||
|
||||
<dot-separated pre-release identifiers> ::= <pre-release identifier>
|
||||
| <pre-release identifier> "." <dot-separated pre-release identifiers>
|
||||
|
||||
<build> ::= <dot-separated build identifiers>
|
||||
|
||||
<dot-separated build identifiers> ::= <build identifier>
|
||||
| <build identifier> "." <dot-separated build identifiers>
|
||||
|
||||
<pre-release identifier> ::= <alphanumeric identifier>
|
||||
| <numeric identifier>
|
||||
|
||||
<build identifier> ::= <alphanumeric identifier>
|
||||
| <digits>
|
||||
|
||||
<alphanumeric identifier> ::= <non-digit>
|
||||
| <non-digit> <identifier characters>
|
||||
| <identifier characters> <non-digit>
|
||||
| <identifier characters> <non-digit> <identifier characters>
|
||||
|
||||
<numeric identifier> ::= "0"
|
||||
| <positive digit>
|
||||
| <positive digit> <digits>
|
||||
|
||||
<identifier characters> ::= <identifier character>
|
||||
| <identifier character> <identifier characters>
|
||||
|
||||
<identifier character> ::= <digit>
|
||||
| <non-digit>
|
||||
|
||||
<non-digit> ::= <letter>
|
||||
| "-"
|
||||
|
||||
<digits> ::= <digit>
|
||||
| <digit> <digits>
|
||||
|
||||
<digit> ::= "0"
|
||||
| <positive digit>
|
||||
|
||||
<positive digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
|
||||
<letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
|
||||
| "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
|
||||
| "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d"
|
||||
| "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n"
|
||||
| "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
|
||||
| "y" | "z"
|
||||
```
|
||||
|
||||
为什么要使用语义化的版本控制?
|
||||
---
|
||||
|
||||
这并不是一个新的或者革命性的想法。实际上,你可能已经在做一些近似的事情了。问题在于只是“近似”还不够。如果没有某个正式的规范可循,版本号对于依赖的管理并无实质意义。将上述的想法命名并给予清楚的定义,让你对软件使用者传达意向变得容易。一旦这些意向变得清楚,弹性(但又不会太弹性)的依赖规范就能达成。
|
||||
|
||||
举个简单的例子就可以展示语义化的版本控制如何让依赖地狱成为过去。假设有个名为“救火车”的函数库,它需要另一个名为“梯子”并已经有使用语义化版本控制的包。当救火车创建时,梯子的版本号为 3.1.0。因为救火车使用了一些版本 3.1.0 所新增的功能,你可以放心地指定依赖于梯子的版本号大于等于 3.1.0 但小于 4.0.0。这样,当梯子版本 3.1.1 和 3.2.0 发布时,你可以将直接它们纳入你的包管理系统,因为它们能与原有依赖的软件兼容。
|
||||
|
||||
作为一位负责任的开发者,你理当确保每次包升级的运作与版本号的表述一致。现实世界是复杂的,我们除了提高警觉外能做的不多。你所能做的就是让语义化的版本控制为你提供一个健全的方式来发行以及升级包,而无需推出新的依赖包,节省你的时间及烦恼。
|
||||
|
||||
如果你对此认同,希望立即开始使用语义化版本控制,你只需声明你的函数库正在使用它并遵循这些规则就可以了。请在你的 README 文件中保留此页链接,让别人也知道这些规则并从中受益。
|
||||
|
||||
FAQ
|
||||
---
|
||||
|
||||
### 在 0.y.z 初始开发阶段,我该如何进行版本控制?
|
||||
|
||||
最简单的做法是以 0.1.0 作为你的初始化开发版本,并在后续的每次发行时递增次版本号。
|
||||
|
||||
### 如何判断发布 1.0.0 版本的时机?
|
||||
|
||||
当你的软件被用于正式环境,它应该已经达到了 1.0.0 版。如果你已经有个稳定的 API 被使用者依赖,也会是 1.0.0 版。如果你很担心向下兼容的问题,也应该算是 1.0.0 版了。
|
||||
|
||||
### 这不会阻碍快速开发和迭代吗?
|
||||
|
||||
主版本号为零的时候就是为了做快速开发。如果你每天都在改变 API,那么你应该仍在主版本号为零的阶段(0.y.z),或是正在下个主版本的独立开发分支中。
|
||||
|
||||
### 对于公共 API,若即使是最小但不向下兼容的改变都需要产生新的主版本号,岂不是很快就达到 42.0.0 版?
|
||||
|
||||
这是开发的责任感和前瞻性的问题。不兼容的改变不应该轻易被加入到有许多依赖代码的软件中。升级所付出的代价可能是巨大的。要递增主版本号来发行不兼容的改版,意味着你必须为这些改变所带来的影响深思熟虑,并且评估所涉及的成本及效益比。
|
||||
|
||||
### 为整个公共 API 写文档太费事了!
|
||||
|
||||
为供他人使用的软件编写适当的文档,是你作为一名专业开发者应尽的职责。保持项目高效的一个非常重要的部分是掌控软件的复杂度,如果没有人知道如何使用你的软件或不知道哪些函数的调用是可靠的,要掌控复杂度会是困难的。长远来看,使用语义化版本控制以及对于公共 API 有良好规范的坚持,可以让每个人及每件事都运行顺畅。
|
||||
|
||||
### 万一不小心把一个不兼容的改版当成了次版本号发行了该怎么办?
|
||||
|
||||
一旦发现自己破坏了语义化版本控制的规范,就要修正这个问题,并发行一个新的次版本号来更正这个问题并且恢复向下兼容。即使是这种情况,也不能去修改已发行的版本。可以的话,将有问题的版本号记录到文档中,告诉使用者问题所在,让他们能够意识到这是有问题的版本。
|
||||
|
||||
### 如果我更新了自己的依赖但没有改变公共 API 该怎么办?
|
||||
|
||||
由于没有影响到公共 API,这可以被认定是兼容的。若某个软件和你的包有共同依赖,则它会有自己的依赖规范,作者也会告知可能的冲突。要判断改版是属于修订等级或是次版等级,是依据你更新的依赖关系是为了修复问题或是加入新功能。对于后者,我经常会预期伴随着更多的代码,这显然会是一个次版本号级别的递增。
|
||||
|
||||
### 如果我变更了公共 API 但无意中未遵循版本号的改动怎么办呢?(意即在修订等级的发布中,误将重大且不兼容的改变加到代码之中)
|
||||
|
||||
自行做最佳的判断。如果你有庞大的使用者群在依照公共 API 的意图而变更行为后会大受影响,那么最好做一次主版本的发布,即使严格来说这个修复仅是修订等级的发布。记住, 语义化的版本控制就是透过版本号的改变来传达意义。若这些改变对你的使用者是重要的,那就透过版本号来向他们说明。
|
||||
|
||||
### 我该如何处理即将弃用的功能?
|
||||
|
||||
弃用现存的功能是软件开发中的家常便饭,也通常是向前发展所必须的。当你弃用部分公共 API 时,你应该做两件事:(1)更新你的文档让使用者知道这个改变,(2)在适当的时机将弃用的功能透过新的次版本号发布。在新的主版本完全移除弃用功能前,至少要有一个次版本包含这个弃用信息,这样使用者才能平顺地转移到新版 API。
|
||||
|
||||
### 语义化版本对于版本的字符串长度是否有限制呢?
|
||||
|
||||
没有,请自行做适当的判断。举例来说,长到 255 个字符的版本已过度夸张。再者,特定的系统对于字符串长度可能会有他们自己的限制。
|
||||
|
||||
### “v1.2.3” 是一个语义化版本号吗?
|
||||
|
||||
“v1.2.3” 并不是一个语义化的版本号。但是,在语义化版本号之前增加前缀 “v” 是用来表示版本号的常用做法。在版本控制系统中,将 “version” 缩写为 “v” 是很常见的。比如:`git tag v1.2.3 -m "Release version 1.2.3"` 中,“v1.2.3” 表示标签名称,而 “1.2.3” 是语义化版本号。
|
||||
|
||||
### 是否有推荐的正则表达式用以检查语义化版本号的正确性?
|
||||
|
||||
有两个推荐的正则表达式。第一个用于支持按组名称提取的语言(PCRE[Perl 兼容正则表达式,比如 Perl、PHP 和 R]、Python 和 Go)。
|
||||
|
||||
参见:<https://regex101.com/r/Ly7O1x/3/>
|
||||
|
||||
```
|
||||
^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
|
||||
```
|
||||
|
||||
第二个用于支持按编号提取的语言(与第一个对应的提取项按顺序分别为:major、minor、patch、prerelease、buildmetadata)。主要包括 ECMA Script(JavaScript)、PCRE(Perl 兼容正则表达式,比如 Perl、PHP 和 R)、Python 和 Go。
|
||||
参见:<https://regex101.com/r/vkijKf/1/>
|
||||
|
||||
```
|
||||
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
|
||||
```
|
||||
|
||||
关于
|
||||
---
|
||||
|
||||
语义化版本控制的规范是由 Gravatars 创办者兼 GitHub 共同创办者 [Tom Preston-Werner](http://tom.preston-werner.com) 所建立。
|
||||
|
||||
如果您有任何建议,请到 [GitHub 上提出您的问题](https://github.com/semver/semver/issues)。
|
||||
|
||||
许可证
|
||||
---
|
||||
|
||||
[知识共享 署名 3.0 (CC BY 3.0)](http://creativecommons.org/licenses/by/3.0/)
|
BIN
docs/logo/drone.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
docs/logo/drone_red.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
docs/logo/gitea.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
docs/logo/grafana.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
docs/screenshot/2023-10-26_172812.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
docs/screenshot/2023-10-26_172955.png
Normal file
After Width: | Height: | Size: 207 KiB |
BIN
docs/screenshot/2023-10-26_174707.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
docs/screenshot/2023-10-26_174949.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
docs/screenshot/2023-10-26_175308.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/screenshot/2023-10-26_175352.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
docs/screenshot/2023-10-26_175407.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
docs/screenshot/2023-10-26_175419.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
docs/screenshot/2023-10-26_175430.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
docs/screenshot/2023-10-26_175441.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
docs/screenshot/2023-10-26_175447.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
docs/screenshot/2023-10-26_175501.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
docs/screenshot/2023-10-26_175922.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
docs/screenshot/thumb/2023-10-26_172812.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
docs/screenshot/thumb/2023-10-26_172955.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
docs/screenshot/thumb/2023-10-26_174707.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
docs/screenshot/thumb/2023-10-26_174949.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175308.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175352.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175407.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175419.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175430.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175441.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175447.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175501.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
docs/screenshot/thumb/2023-10-26_175922.png
Normal file
After Width: | Height: | Size: 28 KiB |