<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>SemVer - 标签 - 菠菜眾長</title><link>https://lruihao.cn/tags/semver/</link><description>SemVer - 标签 - 菠菜眾長</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><managingEditor>1024@lruihao.cn (Lruihao)</managingEditor><webMaster>1024@lruihao.cn (Lruihao)</webMaster><lastBuildDate>Sat, 13 Aug 2022 13:32:03 +0800</lastBuildDate><atom:link href="https://lruihao.cn/tags/semver/" rel="self" type="application/rss+xml"/><item><title>语义版本控制（SemVer）</title><link>https://lruihao.cn/posts/semver/</link><pubDate>Sat, 13 Aug 2022 13:32:03 +0800</pubDate><author>Lruihao</author><guid>https://lruihao.cn/posts/semver/</guid><description><![CDATA[<div class="featured-image">
        <img src="/images/featured-image.png" referrerpolicy="no-referrer">
      </div><div class="details admonition tip open">
    <div class="details-summary admonition-title">
      <i class="icon fa-solid fa-lightbulb fa-fw" aria-hidden="true"></i>摘要<i class="details-icon fa-solid fa-angle-right fa-fw" aria-hidden="true"></i>
    </div>
    <div class="details-content">
      <div class="admonition-content"><p>版本格式：<code>MAJOR.MINOR.PATCH</code>，版本号递增规则如下：</p>
<ol>
<li><code>MAJOR</code>: <strong>主版本号</strong>，当你做了不兼容的 API 修改</li>
<li><code>MINOR</code>: <strong>次版本号</strong>，当你做了向下兼容的功能性新增</li>
<li><code>PATCH</code>: <strong>修订号</strong>，当你做了向下兼容的问题修正</li>
</ol>
<p>先行版本号及版本编译信息可以加到 <code>MAJOR.MINOR.PATCH</code> 的后面，作为延伸。</p>
</div>
    </div>
  </div>
<h2 id="格式">格式</h2>
<p>基本的语法格式如下，更多请参考 <a href="https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions"target="_blank" rel="external nofollow noopener noreferrer">Backus–Naur Form Grammar for Valid SemVer Versions<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></p>
<div class="highlight" id="id-1"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">&lt;valid semver&gt; ::= &lt;version core&gt;
</span></span><span class="line"><span class="cl">                 | &lt;version core&gt; &#34;-&#34; &lt;pre-release&gt;
</span></span><span class="line"><span class="cl">                 | &lt;version core&gt; &#34;+&#34; &lt;build&gt;
</span></span><span class="line"><span class="cl">                 | &lt;version core&gt; &#34;-&#34; &lt;pre-release&gt; &#34;+&#34; &lt;build&gt;</span></span></code></pre></td></tr></table>
</div>
</div><p>范例：</p>
<p></p>
<table>
<thead>
<tr>
<th>代码状态</th>
<th>等级</th>
<th>规则</th>
<th>版本样例</th>
</tr>
</thead>
<tbody>
<tr>
<td>首次发布</td>
<td>新品发布</td>
<td>以 1.0.0 开始</td>
<td>1.0.0</td>
</tr>
<tr>
<td>bug 修复，向后兼容</td>
<td>补丁版本发布</td>
<td>变更第三位数字</td>
<td>1.0.1</td>
</tr>
<tr>
<td>新功能，向后兼容</td>
<td>次版本发布</td>
<td>变更第二位数字，并且第三位数字重置为 0</td>
<td>1.1.0</td>
</tr>
<tr>
<td>重大变更，不向后兼容</td>
<td>主版本发布</td>
<td>变更第一位数字，并且第二位，第三位数字重置为 0</td>
<td>2.0.0</td>
</tr>
</tbody>
</table>
<div class="details admonition question open">
    <div class="details-summary admonition-title">
      <i class="icon fa-solid fa-question-circle fa-fw" aria-hidden="true"></i>“v1.2.3” 是一个语义化版本号吗？<i class="details-icon fa-solid fa-angle-right fa-fw" aria-hidden="true"></i>
    </div>
    <div class="details-content">
      <div class="admonition-content">“v1.2.3” 并不是的一个语义化的版本号。<br>
但是，在语义化版本号之前增加前缀 “v” 是用来表示版本号的常用做法。<br>
在版本控制系统中，将 “version” 缩写为 “v” 是很常见的。<br>
比如：<code>git tag v1.2.3 -m &quot;Release version 1.2.3&quot;</code> 中，标签是 “v1.2.3”，语义化版本号是 “1.2.3”。</div>
    </div>
  </div>
<h2 id="规范">规范</h2>
<p>以下关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 <a href="https://www.rfc-editor.org/rfc/rfc2119"target="_blank" rel="external nofollow noopener noreferrer">RFC 2119<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a> 的叙述解读。</p>
<details>
  <summary>语义化版本控制规范（SemVer）</summary>
  <ol>
<li>
<p>使用语义化版本控制的软件必须（MUST）定义公共 API。该 API 可以在代码中被定义或出现于严谨的文档内。无论何种形式都应该力求精确且完整。</p>
</li>
<li>
<p>标准的版本号必须（MUST）采用 X.Y.Z 的格式，其中 X、Y 和 Z 为非负的整数，且禁止（MUST NOT）在数字前方补零。X 是主版本号、Y 是次版本号、而 Z 为修订号。每个元素必须（MUST）以数值来递增。例如：1.9.1 -&gt; 1.10.0 -&gt; 1.11.0。</p>
</li>
<li>
<p>标记版本号的软件发行后，禁止（MUST NOT）改变该版本软件的内容。任何修改都必须（MUST）以新版本发行。</p>
</li>
<li>
<p>主版本号为零（0.y.z）的软件处于开发初始阶段，一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。</p>
</li>
<li>
<p>1.0.0 的版本号用于界定公共 API 的形成。这一版本之后所有的版本号更新都基于公共 API 及其修改内容。</p>
</li>
<li>
<p>修订号 Z（x.y.Z | x &gt; 0）必须（MUST）在只做了向下兼容的修正时才递增。这里的修正指的是针对不正确结果而进行的内部修改。</p>
</li>
<li>
<p>次版本号 Y（x.Y.z | x &gt; 0）必须（MUST）在有向下兼容的新功能出现时递增。在任何公共 API 的功能被标记为弃用（deprecated）时也必须（MUST）递增。也可以（MAY）在内部程序有大量新功能或改进被加入时递增，其中可以（MAY）包括修订级别的改变。每当次版本号递增时，修订号必须（MUST）归零。</p>
</li>
<li>
<p>主版本号 X（X.y.z | X &gt; 0）必须（MUST）在有任何不兼容的修改被加入公共 API 时递增。其中可以（MAY）包括次版本号及修订级别的改变。每当主版本号递增时，次版本号和修订号必须（MUST）归零。</p>
</li>
<li>
<p>先行版本号可以（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。</p>
</li>
<li>
<p>版本编译信息可以（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。</p>
</li>
<li>
<p>版本的优先层级指的是不同版本在排序时如何比较。</p>
<ol>
<li>
<p>判断优先层级时，必须（MUST）把版本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较（版本编译信息不在这份比较的列表中）。</p>
</li>
<li>
<p>由左到右依序比较每个标识符，第一个差异值用来决定优先层级：主版本号、次版本号及修订号以数值比较。</p>
<p>例如：1.0.0 &lt; 2.0.0 &lt; 2.1.0 &lt; 2.1.1。</p>
</li>
<li>
<p>当主版本号、次版本号及修订号都相同时，改以优先层级比较低的先行版本号决定。</p>
<p>例如：1.0.0-alpha &lt; 1.0.0。</p>
</li>
<li>
<p>有相同主版本号、次版本号及修订号的两个先行版本号，其优先层级必须（MUST）透过由左到右的每个被句点分隔的标识符来比较，直到找到一个差异值后决定：</p>
<ol>
<li>只有数字的标识符以数值高低比较。</li>
<li>有字母或连接号时则逐字以 ASCII 的排序来比较。</li>
<li>数字的标识符比非数字的标识符优先层级低。</li>
<li>若开头的标识符都相同时，栏位比较多的先行版本号优先层级比较高。</li>
</ol>
<p>例如：1.0.0-alpha &lt; 1.0.0-alpha.1 &lt; 1.0.0-alpha.beta &lt; 1.0.0-beta &lt; 1.0.0-beta.2 &lt; 1.0.0-beta.11 &lt; 1.0.0-rc.1 &lt; 1.0.0</p>
</li>
</ol>
</li>
</ol>

</details>
<h2 id="版本阶段">版本阶段</h2>
<ul>
<li><code>Base</code>: 设计阶段，只有相应的设计没有具体的功能实现</li>
<li><code>Alpha</code>: 软件的初级版本，基本功能已经实现，但存在较多的 bug</li>
<li><code>Bate</code>: 相对于 Alpha 已经有了很大的进步，消除了严重的 BUG，但还存在一些潜在的 BUG，还需要不断测试</li>
<li><code>RC</code>: 该版本已经相当成熟了，基本上不存在导致错误的 Bug，与即将发行的正式版本相差无几</li>
<li><code>RELEASE</code>: 最终发布版本，没有太大的问题</li>
</ul>
<p>最终发布版本（<code>RELEASE</code>）之前的所有版本，都称为先行版本（<code>pre-release</code>）。</p>
<h2 id="faqhttpssemverorglangzh-cnfaq"><a href="https://semver.org/lang/zh-CN/#faq"target="_blank" rel="external nofollow noopener noreferrer">FAQ<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></h2>
<h2 id="其他相关">其他相关</h2>
<h3 id="npm-semver">npm SemVer</h3>
<p>通常我们发布一个包到 npm 仓库时，我们的做法是先修改 <code>package.json</code> 为某个版本，然后执行 <code>npm publish</code> 命令。手动修改版本号的做法建立在你对 SemVer 规范特别熟悉的基础之上，否则可能会造成版本混乱。npm 和 yarn 两个包管理都提供了 SemVer 规范的版本控制命令：</p>
<ul>
<li><a href="https://docs.npmjs.com/cli/v8/commands/npm-version"target="_blank" rel="external nofollow noopener noreferrer">npm-version<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></li>
<li><a href="https://classic.yarnpkg.com/en/docs/cli/version"target="_blank" rel="external nofollow noopener noreferrer">yarn version<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></li>
</ul>
<p>npm 发包基础命令：</p>
<div class="highlight" id="id-2"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. 创建一个新的包</span>
</span></span><span class="line"><span class="cl">npm init
</span></span><span class="line"><span class="cl"><span class="c1"># 2. 查看是否官方源</span>
</span></span><span class="line"><span class="cl">npm config get registry
</span></span><span class="line"><span class="cl"><span class="c1"># 3. 登录</span>
</span></span><span class="line"><span class="cl">npm login
</span></span><span class="line"><span class="cl"><span class="c1"># 4. 发布</span>
</span></span><span class="line"><span class="cl">npm publish
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 版本变化 major.minor.patch</span>
</span></span><span class="line"><span class="cl">npm version patch <span class="c1"># 升级补丁版本</span>
</span></span><span class="line"><span class="cl">npm version minor <span class="c1"># 升级小版号</span>
</span></span><span class="line"><span class="cl">npm version major <span class="c1"># 升级大版号</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下架 [-force]</span>
</span></span><span class="line"><span class="cl">npm unpublish</span></span></code></pre></td></tr></table>
</div>
</div><p>全局设置版本号前缀</p>
<div class="highlight" id="id-3"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># https://docs.npmjs.com/cli/v8/using-npm/config#tag-version-prefix</span>
</span></span><span class="line"><span class="cl">npm config <span class="nb">set</span> tag-version-prefix <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 全局设置版本更新 commit 提交信息</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://docs.npmjs.com/cli/v8/using-npm/config#message</span>
</span></span><span class="line"><span class="cl">npm config <span class="nb">set</span> message <span class="s2">&#34;Chore(release): %s&#34;</span></span></span></code></pre></td></tr></table>
</div>
</div><p>或者设置项目的 <code>.npmrc</code> 或者 <code>.yarnrc</code></p>
<div class="highlight" id="id-4"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># .npmrc</span>
</span></span><span class="line"><span class="cl">tag-version-prefix<span class="o">=</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">message</span><span class="o">=</span><span class="s2">&#34;Chore(release): %s&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># .yarnrc</span>
</span></span><span class="line"><span class="cl">version-tag-prefix <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">version-git-message <span class="s2">&#34;Chore(release): %s&#34;</span></span></span></code></pre></td></tr></table>
</div>
</div><p>package.json 版本控制规则使用了一些些符号：</p>
<ul>
<li><code>^</code></li>
<li><code>~</code></li>
<li><code>&gt;</code></li>
<li><code>&gt;=</code></li>
<li><code>&lt;</code></li>
<li><code>&lt;=</code></li>
<li><code>=</code></li>
<li><code>-</code></li>
<li><code>||</code></li>
</ul>
<p>这些规则的详情如下：</p>
<ul>
<li><code>^</code>: 只会执行不更改最左边非零数字的更新。 如果写入的是 <code>^0.13.0</code>，则当运行 <code>npm update</code> 时，可以更新到 <code>0.13.1</code>、<code>0.13.2</code> 等，但不能更新到 <code>0.14.0</code> 或更高版本。 如果写入的是 <code>^1.13.0</code>，则当运行 <code>npm update</code> 时，可以更新到 <code>1.13.1</code>、<code>1.14.0</code> 等，但不能更新到 <code>2.0.0</code> 或更高版本。</li>
<li><code>~</code>: 如果写入的是 <code>〜0.13.0</code>，则当运行 <code>npm update</code> 时，会更新到补丁版本：即 <code>0.13.1</code> 可以，但 <code>0.14.0</code> 不可以。</li>
<li><code>&gt;</code>: 接受高于指定版本的任何版本。</li>
<li><code>&gt;=</code>: 接受等于或高于指定版本的任何版本。</li>
<li><code>&lt;=</code>: 接受等于或低于指定版本的任何版本。</li>
<li><code>&lt;</code>: 接受低于指定版本的任何版本。</li>
<li><code>=</code>: 接受确切的版本。</li>
<li><code>-</code>: 接受一定范围的版本。例如：<code>2.1.0 - 2.6.2</code>。</li>
<li><code>||</code>: 组合集合。例如 <code>&lt; 2.1 || &gt; 2.6</code>。</li>
</ul>
<p>可以合并其中的一些符号，例如 <code>1.0.0 || &gt;=1.1.0 &lt;1.2.0</code>，即使用 1.0.0 或从 1.1.0 开始但低于 1.2.0 的版本。</p>
<p>还有其他的规则：</p>
<ul>
<li>无符号：仅接受指定的特定版本（例如 <code>1.2.1</code>）。</li>
<li><code>latest</code>: 使用可用的最新版本。</li>
</ul>
<h3 id="版本保留">版本保留</h3>
<ol>
<li>对于大型软件，每个版本都有使用价值时，应保留所有历史版本</li>
<li>对于始终以最新版本为准的软件，则可保留至少最近的 10 个次版本</li>
</ol>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://semver.org/"target="_blank" rel="external nofollow noopener noreferrer">Semantic Versioning 2.0.0<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></li>
<li><a href="http://nodejs.cn/learn/semantic-versioning-using-npm"target="_blank" rel="external nofollow noopener noreferrer">使用 npm 的语义版本控制<i class="fa-solid fa-external-link-alt fa-fw fa-xs ms-1 text-secondary" aria-hidden="true"></i></a></li>
</ul>]]></description></item></channel></rss>