本文是一篇翻譯文章: blog.golang.org/v2-go-modul…
原文做者:Jean de Klerk 和 Tyler Bui-Palsu 譯者:befovy 校對:polaris1119
譯文由 GCTT 原創編譯,Go語言中文網 榮譽推出git
本文是 Go modules 系統的第四部分github
隨着成功的項目逐漸成熟以及新需求的加入,早期的功能和設計決策可能再也不適用。 開發者們可能但願經過刪除廢棄使用的功能、重命名類型或將複雜的程序拆分爲可管理的小塊來融入他們的經驗教訓。這種類型的變動要求下游用戶進行更改才能將其代碼遷移到新的 API,所以在沒有認真考慮收益成本比重的狀況下,不該進行這種變動。golang
對於還在早期開發階段的項目(主版本號是 v0
),用戶會指望偶爾的重大變動。對於聲稱已經穩定的項目(主版本是 v1
或者更高版本),必須在新的主版本進行重大變動。這篇文章探討了主版本語義、如何建立併發布新的主版本以及如何維護一個 Go Modules 的多個主版本。數據庫
模塊在 Go 中肯定了一個重要的原則,即 「導入兼容性規則」api
若是舊包和新包的導入路徑相同,新包必須向後兼容舊的包bash
根據這條原則,一個軟件包新的主版本沒有向後兼容之前的版本。這意味着這個軟件包新的主版本必須使用和以前版本不一樣的模塊路徑。從 v2
開始,主版本號必須出如今模塊路徑的結尾(在 go.mod 文件的 module
語句中聲明)。例如,當模塊 github.com/googleapis/gax-go
的開發者們開發完 v2
,他們用了新的模塊路徑 github.com/googleapis/gax-go/v2
。想要使用 v2
的用戶必須把他們的包導入和模塊要求更改成 github.com/googleapis/gax-go/v2
併發
須要主版本號後綴是 Go 模塊和大多數其餘依賴管理系統不一樣的方式之一。後綴用於解決菱形依賴問題。在 Go 模塊以前,gopkg.in 容許軟件包維護者遵循咱們如今稱爲導入兼容性規則的內容。使用 gopkg.in 時,若是你依賴一個導入了 gopkg.in/yaml.v1
的包以及另外一個導入了 gopkg.in/yaml.v2
的包,這不會發生衝突,由於兩個 yaml
包有着不一樣的導入路徑(它們使用和 Go Modules 相似的版本後綴)。因爲 gopkg.in 和 Go Modules 共享相同的版本號後綴方法,所以 Go 命令接受 gopkg.in/yaml.v2
中的 .v2
做爲有效的版本號。這是一個爲了和 gopkg.in 兼容的特殊狀況,在其餘域託管的模塊須要使用像 /v2
這樣的斜槓後綴。app
推薦的策略是在以主版本後綴命名的目錄中開發 v2+
模塊。工具
github.com/googleapis/gax-go @ master branch
/go.mod → module github.com/googleapis/gax-go
/v2/go.mod → module github.com/googleapis/gax-go/v2
複製代碼
這種方式與不支持 Go Modules 的一些工具兼容:倉庫中的文件路徑與 GOPATH
模式下 go get
命令預期的路徑匹配。這一策略也容許全部的主版本一塊兒在不一樣的目錄中開發。ui
其餘的策略多是將主版本放置在單獨的分支上。然而,若是 v2+
的源代碼在倉庫的默認分支上(通常是 master),不支持版本的工具(包括 GOPATH 模式下的 Go 命令)可能沒法區分不一樣的主版本。
本文中的示例遵循主版本子目錄策略,因此提供了最大的兼容性。咱們建議模塊的做者遵循這種策略,只要他們還有用戶在使用 GOPATH
模式開發。
這篇文章以 github.com/googleapis/gax-go
爲例:
$ pwd
/tmp/gax-go
$ ls
CODE_OF_CONDUCT.md call_option.go internal
CONTRIBUTING.md gax.go invoke.go
LICENSE go.mod tools.go
README.md go.sum RELEASING.md
header.go
$ cat go.mod
module github.com/googleapis/gax-go
go 1.9
require (
github.com/golang/protobuf v1.3.1
golang.org/x/exp v0.0.0-20190221220918-438050ddec5e
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b
google.golang.org/grpc v1.19.0
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099
)
$
複製代碼
要開始開發 github.com/googleapis/gax-go
的 v2
版本,咱們將建立一個新的 v2/
目錄並將包的內容複製到該目錄中。
$ mkdir v2
$ cp *.go v2/
building file list ... done
call_option.go
gax.go
header.go
invoke.go
tools.go
sent 10588 bytes received 130 bytes 21436.00 bytes/sec
total size is 10208 speedup is 0.95
$
複製代碼
如今,咱們經過複製當前的 go.mod
文件而且在 module 路徑上添加 /v2
後綴來建立屬於 v2 的 go.mod
文件。
$ cp go.mod v2/go.mod
$ go mod edit -module github.com/googleapis/gax-go/v2 v2/go.mod
$
複製代碼
注意: v2
版本被視爲與 v0 / v1
版本分開的模塊,二者能夠共存於同一構建中。所以,若是你的 v2+
模塊具備多個軟件包,你應該更新它們使用新的 /v2
導入路徑,不然,你的 v2+
模塊會依賴你的 v0 / v1
模塊。要升級全部 github.com/my/project
爲 github.com/my/project/v2
,可使用 find
和 sed
命令:
$ find . -type f \
-name '*.go' \
-exec sed -i -e 's,github.com/my/project,github.com/my/project/v2,g' {} \;
$
複製代碼
如今咱們有了一個 v2
模塊,可是咱們要在版本發佈以前進行實驗並進行修改。在咱們發佈 v2.0.0
(或者其餘沒有預發佈後綴的版本)以前,咱們能夠進行開發而且能夠作出重大變動,就如同咱們決定實現新 API 同樣。 若是咱們但願用戶可以在正式發佈新 API 以前對其進行試驗,能夠選擇發佈 v2
預發佈版本:
$ git tag v2.0.0-alpha.1
$ git push origin v2.0.0-alpha.1
$
複製代碼
一旦咱們對 v2
API 感到滿意而且肯定不會再有別的重大變動,咱們能夠打上 Git 標記 v2.0.0
。
$ git tag v2.0.0
$ git push origin v2.0.0
$
複製代碼
到那時,就有兩個主版本須要維護。向後兼容的更改和錯誤修復使用新的次版本或者補丁版本發佈(好比 v1.1.0
, v2.0.1
等)。
主版本變動會帶來開發和維護的開銷,而且須要下游用戶的額外付出才能遷移。越大的項目中這種主版本變動的開銷就越大。只有在肯定了使人信服的理由以後,才應該進行主版本變動。一旦肯定了使人信服的重大變動緣由,咱們建議在 master 分支進行多個主版本的開發,由於這樣能與各類現有工具兼容。
對 v1+
模塊的重大變動應該始終發生在新的 vN+1
模塊中。一個新模塊發佈時,對於維護者和須要遷移到這個新軟件包的用戶來講意味着更多的工做。所以,維護人員應該在發佈穩定版本以前對其 API 進行驗證,並仔細考慮在 v1
版本以後是否確有必要進行重大變動。