語義化版本

語義化版本 2.0.0
摘要
版本格式:主版本號.次版本號.修訂號,版本號遞增規(guī)則如下:
主版本號:當(dāng)你做了不兼容的 API 修改,
次版本號:當(dāng)你做了向下兼容的功能性新增,
修訂號:當(dāng)你做了向下兼容的問題修正。

先行版本號及版本編譯信息可以加到“主版本號.次版本號.修訂號”的后面,作為延伸。
簡介
在軟件管理的領(lǐng)域里存在著被稱作“依賴地獄”的死亡之谷,系統(tǒng)規(guī)模越大,加入的套件越多,你就越有可能在未來的某一天發(fā)現(xiàn)自己已深陷絕望之中。
在依賴高的系統(tǒng)中發(fā)布新版本套件可能很快會成為惡夢。如果依賴關(guān)系過高,可能面臨版本控制被鎖死的風(fēng)險(必須對每一個相依套件改版才能完成某次升級)。而如果依賴關(guān)系過于松散,又將無法避免版本的混亂(假設(shè)兼容于未來的多個版本已超出了合理數(shù)量)。當(dāng)你專案的進(jìn)展因為版本相依被鎖死或版本混亂變得不夠簡便和可靠,就意味著你正處于依賴地獄之中。
作為這個問題的解決方案之一,我提議用一組簡單的規(guī)則及條件來約束版本號的配置和增長。這些規(guī)則是根據(jù)(但不局限于)已經(jīng)被各種封閉、開放源碼軟件所廣泛使用的慣例所設(shè)計。為了讓這套理論運作,你必須先有定義好的公共 API 。這可以透過文件定義或代碼強(qiáng)制要求來實現(xiàn)。無論如何,這套 API 的清楚明了是十分重要的。一旦你定義了公共 API,你就可以透過修改相應(yīng)的版本號來向大家說明你的修改。考慮使用這樣的版本號格式:XYZ (主版本號.次版本號.修訂號)修復(fù)問題但不影響API 時,遞增修訂號;API 保持向下兼容的新增及修改時,遞增次版本號;進(jìn)行不向下兼容的修改時,遞增主版本號。
我稱這套系統(tǒng)為“語義化的版本控制”,在這套約定下,版本號及其更新方式包含了相鄰版本間的底層代碼和修改內(nèi)容的信息。
語義化版本控制規(guī)范(SemVer)
以下關(guān)鍵詞 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的敘述解讀。(譯注:為了保持語句順暢, 以下文件遇到的關(guān)鍵詞將依照整句語義進(jìn)行翻譯,在此先不進(jìn)行個別翻譯。)
使用語義化版本控制的軟件“必須 MUST ”定義公共 API。該 API 可以在代碼中被定義或出現(xiàn)于嚴(yán)謹(jǐn)?shù)奈募?nèi)。無論何種形式都應(yīng)該力求精確且完整。

標(biāo)準(zhǔn)的版本號“必須 MUST ”采用 XYZ 的格式,其中 X、Y 和 Z 為非負(fù)的整數(shù),且“禁止 MUST NOT”在數(shù)字前方補(bǔ)零。X 是主版本號、Y 是次版本號、而 Z 為修訂號。每個元素“必須 MUST ”以數(shù)值來遞增。例如:1.9.1 -> 1.10.0 -> 1.11.0。

標(biāo)記版本號的軟件發(fā)行后,“禁止 MUST NOT ”改變該版本軟件的內(nèi)容。任何修改都“必須 MUST ”以新版本發(fā)行。

主版本號為零(0.y.z)的軟件處于開發(fā)初始階段,一切都可能隨時被改變。這樣的公共 API 不應(yīng)該被視為穩(wěn)定版。

1.0.0 的版本號用于界定公共 API 的形成。這一版本之后所有的版本號更新都基于公共 API 及其修改內(nèi)容。

修訂號 Z(x.y.Z |
x > 0)“必須 MUST ”在只做了向下兼容的修正時才遞增。這里的修正指的是針對不正確結(jié)果而進(jìn)行的內(nèi)部修改。

次版本號 Y(x.Y.z |
x > 0)“必須 MUST ”在有向下兼容的新功能出現(xiàn)時遞增。在任何公共 API 的功能被標(biāo)記為棄用時也“必須 MUST ”遞增。也“可以 MAY ”在內(nèi)部程序有大量新功能或改進(jìn)被加入時遞增,其中“可以 MAY ”包括修訂級別的改變。每當(dāng)次版本號遞增時,修訂號“必須 MUST ”歸零。

主版本號 X(X.y.z |
X > 0)“必須 MUST ”在有任何不兼容的修改被加入公共 API 時遞增。其中“可以 MAY ”包括次版本號及修訂級別的改變。每當(dāng)主版本號遞增時,次版本號和修訂號“必須 MUST ”歸零。

先行版本號“可以 MAY ”被標(biāo)注在修訂版之后,先加上一個連接號再加上一連串以句點分隔的標(biāo)識符號來修飾。標(biāo)識符號“必須 MUST ”由 ASCII 碼的英數(shù)字和連接號 [0-9A-Za-z-] 組成,且“禁止 MUST NOT ”留白。數(shù)字型的標(biāo)識符號“禁止 MUST NOT ”在前方補(bǔ)零。先行版的優(yōu)先級低于相關(guān)聯(lián)的標(biāo)準(zhǔn)版本。被標(biāo)上先行版本號則表示這個版本并非穩(wěn)定而且可能無法達(dá)到兼容的需求。范例:1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。

版本編譯信息“可以 MAY ”被標(biāo)注在修訂版或先行版本號之后,先加上一個加號再加上一連串以句點分隔的標(biāo)識符號來修飾。標(biāo)識符號“必須 MUST ”由 ASCII 的英數(shù)字和連接號 [0-9A-Za-z-] 組成,且“禁止 MUST NOT ”留白。當(dāng)判斷版本的優(yōu)先層級時,版本編譯信息“可 SHOULD ”被忽略。因此當(dāng)兩個版本只有在版本編譯信息有差別時,屬于相同的優(yōu)先層級。范例:1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。

版本的優(yōu)先層級指的是不同版本在排序時如何比較。判斷優(yōu)先層級時,“必須 MUST ”把版本依序拆分為主版本號、次版本號、修訂號及先行版本號后進(jìn)行比較(版本編譯信息不在這份比較的列表中)。由左到右依序比較每個標(biāo)識符號,第一個差異值用來決定優(yōu)先層級:主版本號、次版本號及修訂號以數(shù)值比較,例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。當(dāng)主版本號、次版本號及修訂號都相同時,改以優(yōu)先層級比較低的先行版本號決定。例如:1.0.0-alpha < 1.0.0。有相同主版本號、次版本號及修訂號的兩個先行版本號,其優(yōu)先層級“必須 MUST ”透過由左到右的每個被句點分隔的標(biāo)識符號來比較,直到找到一個差異值后決定:只有數(shù)字的標(biāo)識符號以數(shù)值高低比較,有字母或連接號時則逐字以 ASCII 的排序來比較。數(shù)字的標(biāo)識符號比非數(shù)字的標(biāo)識符號優(yōu)先層級低。若開頭的標(biāo)識符號都相同時,欄位比較多的先行版本號優(yōu)先層級比較高。范例: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。

為什么要使用語義化的版本控制?
這并不是一個新的或者革命性的想法。實際上,你可能已經(jīng)在做一些近似的事情了。問題在于只是“近似”還不夠。如果沒有某個正式的規(guī)范可循,版本號對于依賴的管理并無實質(zhì)意義。將上述的想法命名并給予清楚的定義,讓你對軟件使用者傳達(dá)意向變得容易。一旦這些意向變得清楚,彈性(但又不會太彈性)的依賴規(guī)范就能達(dá)成。
舉個簡單的例子就可以展示語義化的版本控制如何讓依賴地獄成為過去。假設(shè)有個名為“救火車”的函式庫,它需要另一個名為“梯子”并已經(jīng)有使用語義化版本控制的套件。當(dāng)救火車創(chuàng)建時,梯子的版本號為 3.1.0。因為救火車使用了一些版本 3.1.0 所新增的功能, 你可以放心地指定相依于梯子的版本號大等于 3.1.0 但小于 4.0.0。這樣,當(dāng)梯子版本 3.1.1 和 3.2.0 發(fā)布時,你可以將直接它們納入你的套件管理系統(tǒng),因為它們能與原有相依的軟件兼容。
作為一位負(fù)責(zé)任的開發(fā)者,你理當(dāng)確保每次套件升級的運作與版本號的表述一致。現(xiàn)實世界是復(fù)雜的,我們除了提高警覺外能做的不多。你所能做的就是讓語義化的版本控制為你提供一個健全的方式來發(fā)行以及升級套件,而無需推出新的相依套件,節(jié)省你的時間及煩惱。
如果你對此認(rèn)同,希望立即開始使用語義化版本控制,你只需聲明你的函式庫正在使用它并遵循這些規(guī)則就可以了。請在你的 README 文件中保留此頁連結(jié),讓別人也知道這些規(guī)則并從中受益。
FAQ
在 0.y.z 初始開發(fā)階段,我該如何進(jìn)行版本控制?
最簡單的做法是以 0.1.0 作為你的初始化開發(fā)版本,并在后續(xù)的每次發(fā)行時遞增次版本號。
如何判斷發(fā)布 1.0.0 版本的時機(jī)?
當(dāng)你的軟件被用于正式環(huán)境,它應(yīng)該已經(jīng)達(dá)到了 1.0.0 版。如果你已經(jīng)有個穩(wěn)定的 API 被使用者依賴,也會是 1.0.0 版。如果你很擔(dān)心向下兼容的問題,也應(yīng)該算是 1.0.0 版了。
這不會阻礙快速開發(fā)和迭代嗎?
主版本號為零的時候就是為了做快速開發(fā)。如果你每天都在改變 API,那么你應(yīng)該仍在主版本號為零的階段(0.y.z),或是正在下個主版本的獨立開發(fā)分支中。
對于公共 API,若即使是最小但不向下兼容的改變都需要產(chǎn)生新的主版本號,豈不是很快就達(dá)到 42.0.0 版?
這是開發(fā)的責(zé)任感和前瞻性的問題。不兼容的改變不應(yīng)該輕易被加入到有許多依賴代碼的軟件中。升級所付出的代價可能是巨大的。要遞增主版本號來發(fā)行不兼容的改版,意味著你必須為這些改變所帶來的影響深思熟慮,并且評估所涉及的成本及效益比。
為整個公共 API 寫文件太費事了!
為供他人使用的軟件編寫適當(dāng)?shù)奈募悄阕鳛橐幻麑I(yè)開發(fā)者應(yīng)盡的職責(zé)。保持專案高效一個非常重要的部份是掌控軟件的復(fù)雜度,如果沒有人知道如何使用你的軟件或不知道哪些函數(shù)的調(diào)用是可靠的,要掌控復(fù)雜度會是困難的。長遠(yuǎn)來看,使用語義化版本控制以及對于公共 API 有良好規(guī)范的堅持,可以讓每個人及每件事都運行順暢。
萬一不小心把一個不兼容的改版當(dāng)成了次版本號發(fā)行了該怎么辦?
一旦發(fā)現(xiàn)自己破壞了語義化版本控制的規(guī)范,就要修正這個問題,并發(fā)行一個新的次版本號來更正這個問題并且恢復(fù)向下兼容。即使是這種情況,也不能去修改已發(fā)行的版本。可以的話,將有問題的版本號記錄到文件中,告訴使用者問題所在,讓他們能夠意識到這是有問題的版本。
如果我更新了自己的依賴但沒有改變公共 API 該怎么辦?
由于沒有影響到公共 API,這可以被認(rèn)定是兼容的。若某個軟件和你的套件有共同依賴,則它會有自己的依賴規(guī)范,作者也會告知可能的沖突。要判斷改版是屬于修訂等級或是次版等級,是依據(jù)你更新的依賴關(guān)系是為了修復(fù)問題或是加入新功能。對于后者,我經(jīng)常會預(yù)期伴隨著更多的代碼,這顯然會是一個次版本號級別的遞增。
如果我變更了公共 API 但無意中未遵循版本號的改動怎么辦呢?(意即在修訂等級的發(fā)布中,誤將重大且不兼容的改變加到代碼之中)
自行做最佳的判斷。如果你有龐大的使用者群在依照公共 API 的意圖而變更行為后會大受影響,那么最好做一次主版本的發(fā)布,即使嚴(yán)格來說這個修復(fù)僅是修訂等級的發(fā)布。記住, 語義化的版本控制就是透過版本號的改變來傳達(dá)意義。若這些改變對你的使用者是重要的,那就透過版本號來向他們說明。
我該如何處理即將棄用的功能?
棄用現(xiàn)存的功能是軟件開發(fā)中的家常便飯,也通常是向前發(fā)展所必須的。當(dāng)你棄用部份公共 API 時,你應(yīng)該做兩件事:(1)更新你的文件讓使用者知道這個改變,(2)在適當(dāng)?shù)臅r機(jī)將棄用的功能透過新的次版本號發(fā)布。在新的主版本完全移除棄用功能前,至少要有一個次版本包含這個棄用信息,這樣使用者才能平順地轉(zhuǎn)移到新版 API。
語義化版本對于版本的字串長度是否有限制呢?
沒有,請自行做適當(dāng)?shù)呐袛唷Ee例來說,長到 255 個字元的版本已過度夸張。再者,特定的系統(tǒng)對于字串長度可能會有他們自己的限制。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內(nèi)容