長知識 語義化版本控制

2022-01-09 22:03:08 字數 4208 閱讀 2394

版本格式:主版本號.次版本號.修訂號,版本號遞增規則如下:

主版本號:當你做了不相容的 api 修改,

次版本號:當你做了向下相容的功能性新增,

修訂號:當你做了向下相容的問題修正。

先行版本號及版本編譯元資料可以加到「主版本號.次版本號.修訂號」的後面,作為延伸。

在軟體管理的領域裡存在著被稱作「依賴地獄」的死亡之谷,系統規模越大,加入的包越多,你就越有可能在未來的某一天發現自己已深陷絕望之中。

在依賴高的系統中發布新版本包可能很快會成為噩夢。如果依賴關係過高,可能面臨版本控制被鎖死的風險(必須對每乙個依賴包改版才能完成某次公升級)。而如果依賴關係過於鬆散,又將無法避免版本的混亂(假設相容於未來的多個版本已超出了合理數量)。當你專案的進展因為版本依賴被鎖死或版本混亂變得不夠簡便和可靠,就意味著你正處於依賴地獄之中。

作為這個問題的解決方案之一,我提議用一組簡單的規則及條件來約束版本號的配置和增長。這些規則是根據(但不侷限於)已經被各種封閉、開放原始碼軟體所廣泛使用的慣例所設計。為了讓這套理論運作,你必須先有定義好的公共 api 。這可以透過檔案定義或**強制要求來實現。無論如何,這套 api 的清楚明了是十分重要的。一旦你定義了公共 api,你就可以透過修改相應的版本號來向大家說明你的修改。考慮使用這樣的版本號格式:x.y.z (主版本號.次版本號.修訂號)修復問題但不影響api 時,遞增修訂號;api 保持向下相容的新增及修改時,遞增次版本號;進行不向下相容的修改時,遞增主版本號。

我稱這套系統為「語義化的版本控制」,在這套約定下,版本號及其更新方式包含了相鄰版本間的底層**和修改內容的資訊。

使用語義化版本控制的軟體必須(must)定義公共 api。該 api 可以在**中被定義或出現於嚴謹的檔案內。無論何種形式都應該力求精確且完整。

標準的版本號必須(must)採用 x.y.z 的格式,其中 x、y 和 z 為非負的整數,且禁止(must not)在數字前方補零。x 是主版本號、y 是次版本號、而 z 為修訂號。每個元素必須(must)以數值來遞增。例如:1.9.1 -> 1.10.0 -> 1.11.0。

標記版本號的軟體發行後,禁止(must not)改變該版本軟體的內容。任何修改都必須(must)以新版本發行。

主版本號為零(0.y.z)的軟體處於開發初始階段,一切都可能隨時被改變。這樣的公共 api 不應該被視為穩定版。

1.0.0 的版本號用於界定公共 api 的形成。這一版本之後所有的版本號更新都基於公共 api 及其修改內容。

修訂號 z(x.y.z | x > 0)必須(must)在只做了向下相容的修正時才遞增。這裡的修正指的是針對不正確結果而進行的內部修改。

次版本號 y(x.y.z | x > 0)必須(must)在有向下相容的新功能出現時遞增。在任何公共 api 的功能被標記為棄用時也必須(must)遞增。也可以(may)在內部程式有大量新功能或改進被加入時遞增,其中可以(may)包括修訂級別的改變。每當次版本號遞增時,修訂號必須(must)歸零。

主版本號 x(x.y.z | x > 0)必須(must)在有任何不相容的修改被加入公共 api 時遞增。其中可以(may)包括次版本號及修訂級別的改變。每當主版本號遞增時,次版本號和修訂號必須(must)歸零。

先行版本號可以(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。

版本編譯元資料可以(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。

版本的優先層級指的是不同版本在排序時如何比較。判斷優先層級時,必須(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 檔案中保留此頁鏈結,讓別人也知道這些規則並從中受益。

最簡單的做法是以 0.1.0 作為你的初始化開發版本,並在後續的每次發行時遞增次版本號。

當你的軟體被用於正式環境,它應該已經達到了 1.0.0 版。如果你已經有個穩定的 api 被使用者依賴,也會是 1.0.0 版。如果你很擔心向下相容的問題,也應該算是 1.0.0 版了。

主版本號為零的時候就是為了做快速開發。如果你每天都在改變 api,那麼你應該仍在主版本號為零的階段(0.y.z),或是正在下個主版本的獨立開發分支中。

這是開發的責任感和前瞻性的問題。不相容的改變不應該輕易被加入到有許多依賴**的軟體中。公升級所付出的代價可能是巨大的。要遞增主版本號來發行不相容的改版,意味著你必須為這些改變所帶來的影響深思熟慮,並且評估所涉及的成本及效益比。

為供他人使用的軟體編寫適當的檔案,是你作為一名專業開發者應盡的職責。保持專案高效乙個非常重要的部份是掌控軟體的複雜度,如果沒有人知道如何使用你的軟體或不知道哪些函式的呼叫是可靠的,要掌控複雜度會是困難的。長遠來看,使用語義化版本控制以及對於公共 api 有良好規範的堅持,可以讓每個人及每件事都執行順暢。

一旦發現自己破壞了語義化版本控制的規範,就要修正這個問題,並發行乙個新的次版本號來更正這個問題並且恢復向下相容。即使是這種情況,也不能去修改已發行的版本。可以的話,將有問題的版本號記錄到檔案中,告訴使用者問題所在,讓他們能夠意識到這是有問題的版本。

由於沒有影響到公共 api,這可以被認定是相容的。若某個軟體和你的包有共同依賴,則它會有自己的依賴規範,作者也會告知可能的衝突。要判斷改版是屬於修訂等級或是次版等級,是依據你更新的依賴關係是為了修復問題或是加入新功能。對於後者,我經常會預期伴隨著更多的**,這顯然會是乙個次版本號級別的遞增。

棄用現存的功能是軟體開發中的家常便飯,也通常是向前發展所必須的。當你棄用部份公共 api 時,你應該做兩件事:(1)更新你的檔案讓使用者知道這個改變,(2)在適當的時機將棄用的功能透過新的次版本號發布。在新的主版本完全移除棄用功能前,至少要有乙個次版本包含這個棄用資訊,這樣使用者才能平順地轉移到新版 api。

沒有,請自行做適當的判斷。舉例來說,長到 255 個字元的版本已過度誇張。再者,特定的系統對於字串長度可能會有他們自己的限制。

語義化版本號

本文根據 語義化版本 2.0.0 一文稍作修改。版本格式 主版本號.次版本號.修訂版本號 版本號遞增規則 主版本號 做了不相容的api修改 次版本號 做了向下相容的功能性新增 修訂號 做了向下相容的問題修正。先行版本號及版本編譯元資料可以加到 主版本號.次版本號.修訂號 的後面,作為延伸。用一組簡單...

版本管理基礎 語義化版本 2 0 0解讀

提到語義化版本,你可能不是很熟悉,但是這幾乎是每個開發者都接觸的非常多的一種版本管理方式,當你所使用的軟體的版本以比如gitlab 12.10.5的方式進行版本的介紹的時候,這就是一種典型的語義化版本方式。這篇文章以中文版的語義化版本說明為基礎進行使用解釋。相較於定義,建議先記住這樣乙個示例更容易理...

語義化版本 版本號管理

不論是遊戲或者應用軟體開發,一般進行版本的管理都是重要的一步,所以本文摘錄了 語義化版本 2.0.0 的內容,希望大家能認真了解一下版本號的管理方式 版本格式 主版本號.次版本號.修訂號 major.minor.patch 版本號遞增規則如下 主版本號 major 當你做了不相容的 api 修改,次...