SemVer - 語意化版本規範

語意化版本管理 (SemVer) 是由 GitHub 共同創辦人 Tom Preston-Werner 所提出的一種版本號管理規範,提倡一種通用的軟體改版規則與建議,blah... blah...
 
寫(整理)這篇文章,其實也是因為我自己在 bump 版本號時,有時候是有一點不知道怎麼衡量,所以呢,就上網找找資料,或者偷偷看一下大神的 GitHub,看看人家是怎麼做的,在過程中得到了一些有趣的發現。這篇文章的內容主要來自 [1], [2] 兩篇文章(連結我附於文末),它們都不會很長,有興趣者可以自己讀一讀啦!關於 SemVer 更嚴謹的定義與說明請見官網,這裡僅作很簡短的介紹。

1. Semantic Versioning [1]

版本號是以 x.y.z 這種形式組成,依序是 Major、Minor 與 Patch 號,以版本號 3.2.6 為例:

326
Major
Minor
Patch

以下是簡單的原則:

  • 增加 Patch 號碼
    • 修正 simple bug,往上增加 1 個 patch number。
  • 增加 Minor 號碼
    • 加入新功能但向下相容,往上增加 1 個 minor number,patch 歸 0。
  • 增加 Major 號碼
    • 凡是不能向下相容的變更,都必須往上增加 1 個 Major number,minor 與 patch 歸 0。
(註:也可以加上 pre-release label,這個請大家自己參考官網說明)


# 假設你有個模組,版本號是 1.2.3

這裡提供一些簡單的情境與歸納 (也是我自己目前 bump 版本號的原則)。至於比較複雜的情況,我也沒經驗,那就遇到的時候再研究一下 XDDD...
  • 你修正了 bug,API 介面(輸入輸出) 都不變、也沒有功能上的變化,那就升到 1.2.4
  • 有個舊的 API,輸入簽署原先是 (x, y)、輸出是一個數字,現在加了一個 optional 的簽署成為 (x, y[, z])、輸出是同樣性質的數字,不會影響舊有的使用者,那就 patch 到 1.2.4
  • 你加了新的API,舊的API都不變,那就升到 1.3.0。
  • 假設有一支舊的 API 為 greet(name),你想要將名稱變更為 greeting(name),照理說此時應該要提升一個 Major 號碼,但是一切都還沒完備呀!此時你可以增加新的 greeting(name),但又將舊的 greet(name) 保留住,而只增加 Minor 版本號。但習慣上,會在 document 中將 greet(name) 標記為 Deprecated,以提醒使用者,下次的 Major 改版這支 API 將被刪除。文件中要同時鼓勵使用者採用新的 API。
  • 有一些 API 可能不是要更名,而是以後會刪除,要在 document 中註記 Deprecated。
(註:有什麼不妥之處,期盼大家的指正與建議~)

2. 版本號 1.0.0 之後視為穩定版正式發布

  • 0.x.x 的階段,通常不一定會採用 SemVer 規則來提升版本號
    • 其實我在看到文章 [1]的說法之前,就有發現這件事情。有偷偷看過像 tj 這些大神寫的 module,確實在 0.x.x 的階段,根本版本號都亂跳的阿 @@... 可能會有類似從 0.2.3 一下子跳到 0.6.0 這情況。這讓我在 bump 0.x.x 的版本號時,增加了不少信心.... XDDD (亂搞一通也不會心虛,你知道,這可是 0.x.x 版本啊~~ 哈哈哈)
  • 1.0.0 通常會被開發者視為穩定版的開始,此後要嚴格遵守 SemVer 規則改版。
  • 文章 [1] 中也指出,其實版本號真的是看作者爽的,也不一定會確實遵守 SemVer。另外,也沒有所謂 minor 跟 patch 奇數號就是非穩定版、偶數號就是穩定版的規則 (主要看 module 作者想怎麼定義,但作者要善盡說明的責任就是了)。而且不同領域,也可能有不同的版本號編排定義。

3. package.json 中出現的 ^ 與 ~

接下來要看的就是在 npm install --save (或 --save-dev) 時,在 package.json 中的相依性欄位("dependencies"),npm 會自動幫我們記錄現在專案底下安裝的模組其版本號。這樣其他人在拿到我們的專案時,只要重新執行 npm install 就可以把這些相依性模組重新安裝起來。
(註:關於 npm 指令,可參考 npm 常用命令指南)

以底下這個例子來說明,這裡你會看到相依模組有 busyman lodash 這兩個。那麼當我們看到 ^ 與 ~ 這兩個符號時,它們的意思是什麼呢?
{
  "name": "example",
  ...
  "dependencies": {
    "busyman": "~0.2.1",
    "lodash": "^4.15.0"
  },
  "devDependencies": {},
  ...
}
文章[2] npm 官網 Blog 的說明很簡短又很清楚,以上面的例子來說明如下:

Caret ( ^ )

  • "lodash": "^4.15.0"
  • 這告訴 npm,安裝時你想要 major 版本維持為 4,且版本大於或等於 4.15.0 的版本
  • 你會裝到 4.x.x,又不低於 4.15.0

Tilde ( ~ )

  • "busyman": "~0.2.1"
  • 告訴 npm,安裝時你想要 major + minor 版本維持為 0.2,且大於或等於 0.2.0 的版本
  • 你會裝到 0.2.x,又不低於 0.2.1

更複雜的寫法

  • OR ( || )
    • "lodash": "4.12.0 || ^4.15"
  • 詳細規則請參考 npm 官網 [3]
  • 如果不確定自己寫的規則是否如心中所預期,也可以使用 npm 的計算工具 [4],它會依照你的規則,幫你列出所有符合條件的版本號。如果對自己寫的規則不是很有把握,或許可以用該工具,double check 一下~

參考文獻

[1] Semver explained - why is there a caret (^) in my package.json?
[2] The npm Blog: Introducing the npm semantic version calculator

simen

An enthusiastic engineer with a passion for learning. After completing my academic journey, I worked as an engineer in Hsinchu Science Park. Later, I ventured into academia to teach at a university. However, I have now returned to the industry as an engineer, again.

Post a Comment (0)
Previous Post Next Post