語(yǔ)義化版本 2.0.0

  1. ??????? (ar)

  2. català (ca)

  3. ?esky (cs)

  4. deutsch (de)

  5. english (en)

  6. espa?ol (es)

  7. ????? (fa)

  8. fran?ais (fr)

  9. ????? (he)

  10. ?????? (hin)

  11. hrvatski (hr)

  12. magyar (hu)

  13. indonesia (id)

  14. italiano (it)

  15. 日本語(yǔ) (ja)

  16. ??????? (ka)

  17. ??? (ko)

  18. polski (pl)

  19. português brasileiro (pt-BR)

  20. pyccкий (ru)

  21. slovensky (sk)

  22. sloven??ina (sl)

  23. svenska (sv)

  24. Türk?e (tr)

  25. 簡(jiǎn)體中文 (zh-CN)

  26. 繁體中文 (zh-TW)

  27. 2.0.0

語(yǔ)義化版本 2.0.0

摘要

版本格式:主版本號(hào).次版本號(hào).修訂號(hào),版本號(hào)遞增規(guī)則如下:

  1. 主版本號(hào):當(dāng)你做了不兼容的 API 修改,
  2. 次版本號(hào):當(dāng)你做了向下兼容的功能性新增,
  3. 修訂號(hào):當(dāng)你做了向下兼容的問(wèn)題修正。

先行版本號(hào)及版本編譯元數(shù)據(jù)可以加到“主版本號(hào).次版本號(hào).修訂號(hào)”的后面,作為延伸。

簡(jiǎn)介

在軟件管理的領(lǐng)域里存在著被稱(chēng)作“依賴(lài)地獄”的死亡之谷,系統(tǒng)規(guī)模越大,加入的包越多,你就越有可能在未來(lái)的某一天發(fā)現(xiàn)自己已深陷絕望之中。

在依賴(lài)高的系統(tǒng)中發(fā)布新版本包可能很快會(huì)成為噩夢(mèng)。如果依賴(lài)關(guān)系過(guò)高,可能面臨版本控制被鎖死的風(fēng)險(xiǎn)(必須對(duì)每一個(gè)依賴(lài)包改版才能完成某次升級(jí))。而如果依賴(lài)關(guān)系過(guò)于松散,又將無(wú)法避免版本的混亂(假設(shè)兼容于未來(lái)的多個(gè)版本已超出了合理數(shù)量)。當(dāng)你專(zhuān)案的進(jìn)展因?yàn)榘姹疽蕾?lài)被鎖死或版本混亂變得不夠簡(jiǎn)便和可靠,就意味著你正處于依賴(lài)地獄之中。

作為這個(gè)問(wèn)題的解決方案之一,我提議用一組簡(jiǎn)單的規(guī)則及條件來(lái)約束版本號(hào)的配置和增長(zhǎng)。這些規(guī)則是根據(jù)(但不局限于)已經(jīng)被各種封閉、開(kāi)放源碼軟件所廣泛使用的慣例所設(shè)計(jì)。為了讓這套理論運(yùn)作,你必須先有定義好的公共 API 。這可以透過(guò)文件定義或代碼強(qiáng)制要求來(lái)實(shí)現(xiàn)。無(wú)論如何,這套 API 的清楚明了是十分重要的。一旦你定義了公共 API,你就可以透過(guò)修改相應(yīng)的版本號(hào)來(lái)向大家說(shuō)明你的修改??紤]使用這樣的版本號(hào)格式:X.Y.Z (主版本號(hào).次版本號(hào).修訂號(hào))修復(fù)問(wèn)題但不影響API 時(shí),遞增修訂號(hào);API 保持向下兼容的新增及修改時(shí),遞增次版本號(hào);進(jìn)行不向下兼容的修改時(shí),遞增主版本號(hào)。

我稱(chēng)這套系統(tǒng)為“語(yǔ)義化的版本控制”,在這套約定下,版本號(hào)及其更新方式包含了相鄰版本間的底層代碼和修改內(nèi)容的信息。

語(yǔ)義化版本控制規(guī)范(SemVer)

以下關(guān)鍵詞 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的敘述解讀。(譯注:為了保持語(yǔ)句順暢, 以下文件遇到的關(guān)鍵詞將依照整句語(yǔ)義進(jìn)行翻譯,在此先不進(jìn)行個(gè)別翻譯。)

  1. 使用語(yǔ)義化版本控制的軟件必須(MUST)定義公共 API。該 API 可以在代碼中被定義或出現(xiàn)于嚴(yán)謹(jǐn)?shù)奈募?nèi)。無(wú)論何種形式都應(yīng)該力求精確且完整。

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

  3. 標(biāo)記版本號(hào)的軟件發(fā)行后,禁止(MUST NOT)改變?cè)摪姹拒浖膬?nèi)容。任何修改都必須(MUST)以新版本發(fā)行。

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

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

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

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

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

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

版本編譯元數(shù)據(jù)可以(MAY)被標(biāo)注在修訂版或先行版本號(hào)之后,先加上一個(gè)加號(hào)再加上一連串以句點(diǎn)分隔的標(biāo)識(shí)符來(lái)修飾。標(biāo)識(shí)符必須(MUST)由 ASCII 字母數(shù)字和連接號(hào) [0-9A-Za-z-] 組成,且禁止(MUST NOT)留白。當(dāng)判斷版本的優(yōu)先層級(jí)時(shí),版本編譯元數(shù)據(jù)可(SHOULD)被忽略。因此當(dāng)兩個(gè)版本只有在版本編譯元數(shù)據(jù)有差別時(shí),屬于相同的優(yōu)先層級(jí)。范例:1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。
版本的優(yōu)先層級(jí)指的是不同版本在排序時(shí)如何比較。判斷優(yōu)先層級(jí)時(shí),必須(MUST)把版本依序拆分為主版本號(hào)、次版本號(hào)、修訂號(hào)及先行版本號(hào)后進(jìn)行比較(版本編譯元數(shù)據(jù)不在這份比較的列表中)。由左到右依序比較每個(gè)標(biāo)識(shí)符,第一個(gè)差異值用來(lái)決定優(yōu)先層級(jí):主版本號(hào)、次版本號(hào)及修訂號(hào)以數(shù)值比較,例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。當(dāng)主版本號(hào)、次版本號(hào)及修訂號(hào)都相同時(shí),改以?xún)?yōu)先層級(jí)比較低的先行版本號(hào)決定。例如:1.0.0-alpha < 1.0.0。有相同主版本號(hào)、次版本號(hào)及修訂號(hào)的兩個(gè)先行版本號(hào),其優(yōu)先層級(jí)必須(MUST)透過(guò)由左到右的每個(gè)被句點(diǎn)分隔的標(biāo)識(shí)符來(lái)比較,直到找到一個(gè)差異值后決定:只有數(shù)字的標(biāo)識(shí)符以數(shù)值高低比較,有字母或連接號(hào)時(shí)則逐字以 ASCII 的排序來(lái)比較。數(shù)字的標(biāo)識(shí)符比非數(shù)字的標(biāo)識(shí)符優(yōu)先層級(jí)低。若開(kāi)頭的標(biāo)識(shí)符都相同時(shí),欄位比較多的先行版本號(hào)優(yōu)先層級(jí)比較高。范例: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。

為什么要使用語(yǔ)義化的版本控制?

這并不是一個(gè)新的或者革命性的想法。實(shí)際上,你可能已經(jīng)在做一些近似的事情了。問(wèn)題在于只是“近似”還不夠。如果沒(méi)有某個(gè)正式的規(guī)范可循,版本號(hào)對(duì)于依賴(lài)的管理并無(wú)實(shí)質(zhì)意義。將上述的想法命名并給予清楚的定義,讓你對(duì)軟件使用者傳達(dá)意向變得容易。一旦這些意向變得清楚,彈性(但又不會(huì)太彈性)的依賴(lài)規(guī)范就能達(dá)成。

舉個(gè)簡(jiǎn)單的例子就可以展示語(yǔ)義化的版本控制如何讓依賴(lài)地獄成為過(guò)去。假設(shè)有個(gè)名為“救火車(chē)”的函式庫(kù),它需要另一個(gè)名為“梯子”并已經(jīng)有使用語(yǔ)義化版本控制的包。當(dāng)救火車(chē)創(chuàng)建時(shí),梯子的版本號(hào)為 3.1.0。因?yàn)榫然疖?chē)使用了一些版本 3.1.0 所新增的功能, 你可以放心地指定依賴(lài)于梯子的版本號(hào)大等于 3.1.0 但小于 4.0.0。這樣,當(dāng)梯子版本 3.1.1 和 3.2.0 發(fā)布時(shí),你可以將直接它們納入你的包管理系統(tǒng),因?yàn)樗鼈兡芘c原有依賴(lài)的軟件兼容。

作為一位負(fù)責(zé)任的開(kāi)發(fā)者,你理當(dāng)確保每次包升級(jí)的運(yùn)作與版本號(hào)的表述一致?,F(xiàn)實(shí)世界是復(fù)雜的,我們除了提高警覺(jué)外能做的不多。你所能做的就是讓語(yǔ)義化的版本控制為你提供一個(gè)健全的方式來(lái)發(fā)行以及升級(jí)包,而無(wú)需推出新的依賴(lài)包,節(jié)省你的時(shí)間及煩惱。

如果你對(duì)此認(rèn)同,希望立即開(kāi)始使用語(yǔ)義化版本控制,你只需聲明你的函式庫(kù)正在使用它并遵循這些規(guī)則就可以了。請(qǐng)?jiān)谀愕?README 文件中保留此頁(yè)連結(jié),讓別人也知道這些規(guī)則并從中受益。

FAQ

在 0.y.z 初始開(kāi)發(fā)階段,我該如何進(jìn)行版本控制?

最簡(jiǎn)單的做法是以 0.1.0 作為你的初始化開(kāi)發(fā)版本,并在后續(xù)的每次發(fā)行時(shí)遞增次版本號(hào)。

如何判斷發(fā)布 1.0.0 版本的時(shí)機(jī)?

當(dāng)你的軟件被用于正式環(huán)境,它應(yīng)該已經(jīng)達(dá)到了 1.0.0 版。如果你已經(jīng)有個(gè)穩(wěn)定的 API 被使用者依賴(lài),也會(huì)是 1.0.0 版。如果你很擔(dān)心向下兼容的問(wèn)題,也應(yīng)該算是 1.0.0 版了。

這不會(huì)阻礙快速開(kāi)發(fā)和迭代嗎?

主版本號(hào)為零的時(shí)候就是為了做快速開(kāi)發(fā)。如果你每天都在改變 API,那么你應(yīng)該仍在主版本號(hào)為零的階段(0.y.z),或是正在下個(gè)主版本的獨(dú)立開(kāi)發(fā)分支中。

對(duì)于公共 API,若即使是最小但不向下兼容的改變都需要產(chǎn)生新的主版本號(hào),豈不是很快就達(dá)到 42.0.0 版?

這是開(kāi)發(fā)的責(zé)任感和前瞻性的問(wèn)題。不兼容的改變不應(yīng)該輕易被加入到有許多依賴(lài)代碼的軟件中。升級(jí)所付出的代價(jià)可能是巨大的。要遞增主版本號(hào)來(lái)發(fā)行不兼容的改版,意味著你必須為這些改變所帶來(lái)的影響深思熟慮,并且評(píng)估所涉及的成本及效益比。

為整個(gè)公共 API 寫(xiě)文件太費(fèi)事了!

為供他人使用的軟件編寫(xiě)適當(dāng)?shù)奈募悄阕鳛橐幻麑?zhuān)業(yè)開(kāi)發(fā)者應(yīng)盡的職責(zé)。保持專(zhuān)案高效一個(gè)非常重要的部份是掌控軟件的復(fù)雜度,如果沒(méi)有人知道如何使用你的軟件或不知道哪些函數(shù)的調(diào)用是可靠的,要掌控復(fù)雜度會(huì)是困難的。長(zhǎng)遠(yuǎn)來(lái)看,使用語(yǔ)義化版本控制以及對(duì)于公共 API 有良好規(guī)范的堅(jiān)持,可以讓每個(gè)人及每件事都運(yùn)行順暢。

萬(wàn)一不小心把一個(gè)不兼容的改版當(dāng)成了次版本號(hào)發(fā)行了該怎么辦?

一旦發(fā)現(xiàn)自己破壞了語(yǔ)義化版本控制的規(guī)范,就要修正這個(gè)問(wèn)題,并發(fā)行一個(gè)新的次版本號(hào)來(lái)更正這個(gè)問(wèn)題并且恢復(fù)向下兼容。即使是這種情況,也不能去修改已發(fā)行的版本??梢缘脑挘瑢⒂袉?wèn)題的版本號(hào)記錄到文件中,告訴使用者問(wèn)題所在,讓他們能夠意識(shí)到這是有問(wèn)題的版本。

如果我更新了自己的依賴(lài)但沒(méi)有改變公共 API 該怎么辦?

由于沒(méi)有影響到公共 API,這可以被認(rèn)定是兼容的。若某個(gè)軟件和你的包有共同依賴(lài),則它會(huì)有自己的依賴(lài)規(guī)范,作者也會(huì)告知可能的沖突。要判斷改版是屬于修訂等級(jí)或是次版等級(jí),是依據(jù)你更新的依賴(lài)關(guān)系是為了修復(fù)問(wèn)題或是加入新功能。對(duì)于后者,我經(jīng)常會(huì)預(yù)期伴隨著更多的代碼,這顯然會(huì)是一個(gè)次版本號(hào)級(jí)別的遞增。

如果我變更了公共 API 但無(wú)意中未遵循版本號(hào)的改動(dòng)怎么辦呢?(意即在修訂等級(jí)的發(fā)布中,誤將重大且不兼容的改變加到代碼之中)

自行做最佳的判斷。如果你有龐大的使用者群在依照公共 API 的意圖而變更行為后會(huì)大受影響,那么最好做一次主版本的發(fā)布,即使嚴(yán)格來(lái)說(shuō)這個(gè)修復(fù)僅是修訂等級(jí)的發(fā)布。記住, 語(yǔ)義化的版本控制就是透過(guò)版本號(hào)的改變來(lái)傳達(dá)意義。若這些改變對(duì)你的使用者是重要的,那就透過(guò)版本號(hào)來(lái)向他們說(shuō)明。

我該如何處理即將棄用的功能?

棄用現(xiàn)存的功能是軟件開(kāi)發(fā)中的家常便飯,也通常是向前發(fā)展所必須的。當(dāng)你棄用部份公共 API 時(shí),你應(yīng)該做兩件事:(1)更新你的文件讓使用者知道這個(gè)改變,(2)在適當(dāng)?shù)臅r(shí)機(jī)將棄用的功能透過(guò)新的次版本號(hào)發(fā)布。在新的主版本完全移除棄用功能前,至少要有一個(gè)次版本包含這個(gè)棄用信息,這樣使用者才能平順地轉(zhuǎn)移到新版 API。

語(yǔ)義化版本對(duì)于版本的字串長(zhǎng)度是否有限制呢?

沒(méi)有,請(qǐng)自行做適當(dāng)?shù)呐袛唷Ee例來(lái)說(shuō),長(zhǎng)到 255 個(gè)字元的版本已過(guò)度夸張。再者,特定的系統(tǒng)對(duì)于字串長(zhǎng)度可能會(huì)有他們自己的限制。

關(guān)于

語(yǔ)義化版本控制的規(guī)范是由 Gravatars 創(chuàng)辦者兼 GitHub 共同創(chuàng)辦者 Tom Preston-Werner 所建立。

如果您有任何建議,請(qǐng)到 GitHub 上提出您的問(wèn)題。
原文鏈接https://semver.org/lang/zh-CN/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容