【转】语义化版本 2.0.0

转自:语义化版本 2.0.0 | Semantic Versioning

语义化版本 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. 版本的优先层级指的是不同版本在排序时如何比较。判断优先层级时,必须(MUST)把版本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较(版本编译信息不在这份比较的列表中)。由左到右依序比较每个标识符,第一个差异值用来决定优先层级:主版本号、次版本号及修订号以数值比较,例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。当主版本号、次版本号及修订号都相同时,改以优先层级比较低的先行版本号决定。例如:1.0.0-alpha < 1.0.0。有相同主版本号、次版本号及修订号的两个先行版本号,其优先层级必须(MUST)透过由左到右的每个被句点分隔的标识符来比较,直到找到一个差异值后决定:只有数字的标识符以数值高低比较,有字母或连接号时则逐字以 ASCII 的排序来比较。数字的标识符比非数字的标识符优先层级低。若开头的标识符都相同时,栏位比较多的先行版本号优先层级比较高。范例: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。

为什么要使用语义化的版本控制?

这并不是一个新的或者革命性的想法。实际上,你可能已经在做一些近似的事情了。问题在于只是“近似”还不够。如果没有某个正式的规范可循,版本号对于依赖的管理并无实质意义。将上述的想法命名并给予清楚的定义,让你对软件使用者传达意向变得容易。一旦这些意向变得清楚,弹性(但又不会太弹性)的依赖规范就能达成。

举个简单的例子就可以展示语义化的版本控制如何让依赖地狱成为过去。假设有个名为“救火车”的函数库,它需要另一个名为“梯子”并已经有使用语义化版本控制的包。当救火车创建时,梯子的版本号为 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 个字元的版本已过度夸张。再者,特定的系统对于字串长度可能会有他们自己的限制。

关于

语义化版本控制的规范是由 Gravatars 创办者兼 GitHub 共同创办者 Tom Preston-Werner 所建立。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435710.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

心情随笔

不好意思&#xff0c;在这里又要让大家听我的牢骚了&#xff0c;但是我实在是没有地方可以发泄&#xff0c;所以只好对不起大家了&#xff0c;在近两个月的找工作历程中心智成熟了很多&#xff0c;同时言语也少了很多&#xff0c;知道没有用的话是白费口舌所以很少发表自己的意…

wince编译问题

一般来说&#xff0c;在VS2008中修改注册表文件&#xff0c;不需要从新编译内核&#xff0c;只需要copy files to release directory和make run-time image即可。但发现不好用&#xff0c;暂时不知道为什么。 看了看BSP目录下的文件&#xff0c;手动修改了X:\WINCE600\PLATFOR…

【转】Ubuntu:永久修改MAC地址

转自&#xff1a;Ubuntu&#xff1a;永久修改MAC地址 - YeeYang - BlogJava 前面发了一篇文章&#xff1a;Ubuntu&#xff1a;修改网卡的MAC地址&#xff0c;最后提到了重启后MAC地址会还原的问题&#xff0c;本文将介绍如何永久修改MAC地址&#xff08;当然不能重装系统&#…

陌生的是人心,是人性,是社会,是世道

偶然中得到这样一本书&#xff0c;它是一本都市小说&#xff0c;写自己的经历&#xff0c;不是很乏味的经历&#xff1b;它是一本职场小说&#xff0c;有着对每个人的、不同侧重点的、外表及心理刻画&#xff0c;披露了鲜为人知的职场黑幕&#xff1b;它又是一本悬疑小说&#…

【转】PF_INET 和 AF_INET 的区别

转自&#xff1a;PF_INET 和 AF_INET 的区别 - 52php - 博客园 在写网络程序的时候&#xff0c;建立TCP socket&#xff1a; 1 sock socket(PF_INET, SOCK_STREAM, 0); 然后再绑定本地地址或连接远程地址时需要初始化sockaddr_in结构&#xff0c;其中指定address family时一…

可以让你少奋斗10年的工作经验

第一&#xff1a;不要认为停留在心灵的舒适区域内是可以原谅的。     每个人都有一个舒适区域&#xff0c;在这个区域内是很自我的&#xff0c;不愿意被打扰&#xff0c;不愿意被push&#xff0c;不愿意和陌生的面孔交谈&#xff0c;不愿意被人指责&#xff0c;不愿意按照规…

【转】PF_RING学习笔记

转自&#xff1a;Qt迭代器&#xff08;Java类型和STL类型&#xff09;详解 1、PF_RING简介 PF_RING是Luca研究出来的基于Linux内核级的高效数据包捕获技术。简单来说PF_RING 是一个高速数据包捕获库,通过它可以实现将通用 PC 计算机变成一个有效且便宜的网络测量工具箱,进行数…

WinCE系统的编译过程详解

在WinCE系统中&#xff0c;当我们完成了相关的开发和系统定制工作以后&#xff0c;会编译WinCE系统&#xff0c;最后生成NK.bin和NK.nb0。下面介绍一下WinCE系统的编译过程&#xff0c;大致分为4个阶段&#xff1a;编译阶段(Compile phase)&#xff0c;系统产生阶段(Sysgen pha…

使用HtmlParser解析HTML

如果要对HTML进行解析,提取HTML的数据或者修改HTML数据,HtmlParser是一个不错的选择.使用HtmlParser可以解析本地和网络上的HTML数据:Parser parser newParser( newWinista.Text.HtmlParser.Http.HttpProtocol(newUri("uriString")));Parser parser newParser( newWi…

【转】VScode快捷键(超无敌详细版)

转自&#xff1a;VScode快捷键(超无敌详细版)_但行好事&#xff0c;莫问前程-CSDN博客 通用快捷键&#xff1a; 快捷键作用CtrlShiftP,F1展示全局命令面板CtrlP快速打开最近打开的文件CtrlShiftN打开新的编辑窗口CtrlShiftW关闭编辑器 基础编辑快捷键&#xff1a; 快捷键作用…

WinCE中得Catalog Items前的标记图标的意义总结

先看下来自微软对Platform Builder里的图标解释&#xff0c;在以后的CE里&#xff0c;也类似。 The Catalog window and the OSDesignView tab contain a number of icons used to represent object types. The icons make it possible for you to differentiate between Catal…

JavaScript 图片上传预览效果

图片上传预览是一种在图片上传之前对图片进行本地预览的技术。 使用户选择图片后能立即查看图片&#xff0c;而不需上传服务器&#xff0c;提高用户体验。 但随着浏览器安全性的提高&#xff0c;要实现图片上传预览也越来越困难。 不过群众的智慧是无限的&#xff0c;网上已经有…

【转】GigE Vision简介

转自&#xff1a;GigE Vision简介_计算机视觉小菜鸟的专栏-CSDN博客_gige vision GigE Vision是由AIA制定的通信协议&#xff0c;用来实现在机器视觉领域利用千兆以太网接口进行图像的高速传输。该标准是基于UDP协议&#xff0c;与普通网络数据包不同之处在于应用层协议&#…

如果C++程序要调用已经被编译后的C函数,该怎么办?

C语言支持函数重载&#xff0c;C 语言不支持函数重载。函数被C编译后在库中的名字 与C 语言的不同。假设某个C函数的声明如下&#xff1a; void foo(int x, int y); 该函数被C编译器编译后在库中的名字为_foo&#xff0c;而C编译器则会产生像_foo_int_int之类的名字用来支持函数…

在Sql Server 2005使用公用表表达式CTE简化复杂的查询语句

公用表表达式CTE是Sql Server 2005引入的一种新的表表达式。CTE在许多方面都类似于派生表。逻辑上CTE是一个临时结果集&#xff0c;它仅仅存在于它发生的语句中。您可以在SELECT、INSERT、DELETE、UPDATE或CTEATE VIEW语句中建立一个CTE。 CTE的优点 与派生表不同&#xff0c;C…

【转】搞机:window10安装Linux子系统(WSL)及迁移到非系统盘

转自&#xff1a;搞机&#xff1a;window10安装Linux子系统&#xff08;WSL&#xff09;及迁移到非系统盘_泛泛之素-CSDN博客_wsl移动到非系统盘 痛点&#xff1a; 在电脑上想要使用linux又想使用windows系统只能安装双系统&#xff0c;因为虚拟机的性能差且使用麻烦&#xf…

关键字static、const、volatile的作用

关键字static的作用是什么&#xff1f; 这个简单的问题很少有人能回答完全。在C语言中&#xff0c;关键字static有三个明显的作用&#xff1a; 1、在函数体&#xff0c;一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 2、 在模块内&#xff08;但在函数体外&…

IE8中解决Cell华表插件不显示方法!

最近一不小心更新了IE&#xff0c;从IE7一跃变成了IE8用户&#xff0c;但网上目前对IE8的评价不是很好&#xff0c;有很多东西不兼容&#xff0c;尤其是在IE7下开发的系统不兼容的地方还是存在的。就Cell来说也是一样的&#xff0c;调试好久&#xff0c;虽然没找到原回&#xf…

【转】CMake Error: The current CMakeCache.txt directory CMakeCache.txt is different than the directory

转自&#xff1a;CMake Error: The current CMakeCache.txt directory is different..._万俟淋曦的进击手记-CSDN博客 零、问题描述 开始学ROS时&#xff0c;需要编译别人的功能包&#xff0c;常常把别人的工作空间拿过来使用&#xff0c;但编译时会出现各种错误&#xff0c;如…

WinCE 5.0 WIFI 无线网卡的配置和建立连接(转)

From&#xff1a;http://blog.csdn.net/xajhuang/archive/2008/12/02/3419512.aspx 在 Windows CE 下自带有无线网卡的配置和连接程序&#xff0c;可是我的系统剪裁掉了资源管理器和任务栏&#xff0c;导致自带的无线网卡配置程序不能再使用了&#xff0c;只好自力更生。 我的…