1. 版本選擇機制
使用go get <pkg>
來獲取某個依賴,如果沒有特別指定依賴的版本號,go get
會自動選擇一個最優版本,並且如果本地有go.mod
文件的話,還會自動更新go.mod文件.
事實上除了go get
,go build
和go mod tidy
也會自動幫我們選擇依賴的版本。這些命令選擇依賴版本時都遵循一些規則,本節我們就開始介紹Go module涉及到的版本選擇機制。
2.依賴包版本約定
2.1 Go module 之前版本兼容性
在Go v1.11
(開始引入Go module
的版本)之前,Go 語言建議: 依賴包需要保持向后兼容,這包括可導出的函數、變量、類型、常量等不可以隨便刪除。
以函數為例,如果需要修改函數的入參,可以增加新的函數而不是直接修改原有的函數。
如果確實需要做一些打破兼容性的修改,建議創建新的包。
比如倉庫github.com/RainbowMango/xxx
中包含一個package A,此時該倉庫只有一個package:
github.com/RainbowMango/xxx/A
那么其他項目引用該依賴時的import 路徑為:
import "github.com/RainbowMango/xxx/A"
如果該依賴包需要引入一個不兼容的特性,可以在該倉庫中增加一個新的package A1,此時該倉庫包含兩個包:
github.com/RainbowMango/xxx/A
github.com/RainbowMango/xxx/A1
那么其他項目在升級依賴包版本后不需要修改原有的代碼可以繼續使用package A,如果需要使用新的package A1,只需要將import 路徑修改為import "github.com/RainbowMango/xxx/A1"
並做相應的適配即可。
2.2 Go module 之后版本兼容性
從Go v1.11版本開始,隨着Go module特性的引入,依賴包的兼容性要求有了進一步的延伸,Go module開始關心依賴包版本管理系統(如Git)中的版本號。盡管如此,兼容性要求的核心內容沒有改變:
- 如果新
package
和舊的package
擁有相同的import 路徑,那么新package必須兼容舊的package; - 如果新的package不能兼容舊的package,那么新的package需要更換import路徑;
在前面的介紹中,我們知道Go module 的go.mod中記錄的module名字決定了import路徑。例如,要引用module module github.com/renhongcai/indirect
中的內容時,其import路徑需要為import github.com/renhongcai/indirect
。
在Go module時代,module版本號要遵循語義化版本規范,即版本號格式為v<major>.<minor>.<patch>
,如v1.2.3
。當有不兼容的改變時,需要增加major版本號,如v2.1.0。
Go module規定,如果major版本號大於1,則major版本號需要顯式地標記在module名字中,如module github.com/my/mod/v2
。這樣做的好處是Go module 會把module github.com/my/mod/v2
和 module github.com/my/mod
視做兩個module,他們甚至可以被同時引用。
另外,如果module的版本為v0.x.x
或v1.x.x
則都不需要在module名字中體現版本號。
3. 版本選擇機制
Go 的多個命令行工具都有自動選擇依賴版本的能力,如go build 和go test,當在源代碼中增加了新的import,這些命令將會自動選擇一個最優的版本,並更新go.mod文件。
需要特別說明的是,如果go.mod文件中已標記了某個依賴包的版本號,則這些命令不會主動更新go.mod中的版本號。所謂自動更新版本號只在go.mod中缺失某些依賴或者依賴不匹配時才會發生。
3.1 最新版本選擇
當在源代碼中新增加了一個import,比如:
import "github.com/RainbowMango/M"
如果go.mod的require指令中並沒有包含github.com/RainbowMango/M
這個依賴,那么go build 或go test
命令則會去github.com/RainbowMango/M
倉庫尋找最新的符合語義化版本規范的版本,比如v1.2.3,並在go.mod文件中增加一條require依賴:
require github.com/RainbowMango/M v1.2.3
這里,由於import路徑里沒有類似於v2或更高的版本號,所以版本選擇時只會選擇v1.x.x的版本,不會去選擇v2.x.x或更高的版本。
3.2 最小版本選擇
有時記錄在go.mod文件中的依賴包版本會隨着引入其他依賴包而發生變化。
如下圖所示: M最新版本是v1.5.0
Module A 依賴 Module M的v1.0.0版本,但之后 Module A 引入了 Module D,而Module D 依賴 Module M的v1.1.1版本,此時,由於依賴的傳遞,Module A也會選擇v1.1.1版本。
需要注意的是,此時會自動選擇最小可用的版本,而不是最新的tag(v1.5.0)版本。