[Go] 到底go get 的版號怎麼運作的?
文章推薦指數: 80 %
在Go Module 模式底下使用go get 取得套件的時候常常會有各種版號出現,例如v1.0.2、v2.0.3 +incompatible、甚至是一段hash ...
Miles
I’mapersonwhoisenthusiasticaboutCoding,andthat’smyjobbytheway.
Home
Categories
Tags
Archives
Search
About
GitHub
LinkedIn
Pluralsight
Medium
RSS
[Go]到底goget的版號怎麼運作的?
Aug25,2020
in
Go
在GoModule模式底下使用goget取得套件的時候常常會有各種版號出現,例如v1.0.2、v2.0.3+incompatible、甚至是一段hashv0.0.0-20200226145339-3e397ee01bc6。
還有取得v2版本的時候,有時候是gogetgithub.com/my/[email protected]有時候是gogetgithub.com/my/foo/[email protected]。
為了搞懂這些差別,我參考了一些官方文章還有做了一些實驗,今天就來解說這些差別到底是什麼情況。
在閱讀此文章之前,建議要先了解
什麼是GoModule。
Ref:UsingGoModules
如何更改主版號(如:v1.0.0升級成v2.0.0)。
Ref:GoModules:v2andBeyond
v1.2.3版號的意義。
Ref:SemanticVersioning2.0.0
Semanticimportversion在文章開始前需簡短說明一下什麼是SemanticImportVersioning。
根據SemanticVersioning版本建議規則,當主版號變更的時候,代表有破壞性更新。
以Go來說,如果這時候更新的版本還是用同樣的路徑,會造成使用的人一更新套件(package)就會壞掉。
所以會建議使用新的路徑讓兩個版本並行,並且在採用漸進式升級的方式升級成新的版本。
例如v1.x.x的路徑會是importgithub.com/my/foo,主版號升級到v2後,路徑會是importgithub.com/my/foo/v2。
而這種不同版本相容的import方式稱為SemanticImportVersioning。
當GoModule啟用後,會強制按照SemanticImportVersioning的規則,履行下列義務
版本號需要使用SemanticVersioning的方式。
例如v1.2.3,v2.7.1。
當版本號大於等於v2+的時候,在go.mod的modulepath要加上/vN,例如modulegithub.com/my/foo/v2。
此時的要使用foo/mypkg套件的時候,import會變成importgithub.com/my/foo/v2/mypkg。
如果主版號是v0或v1則modulepath與importpath不需要加上/v0或/v1
有了上敘的知識後,就開始我們今天的故事吧!!
都跟取得套件的Repository有關係這些goget版本的路徑要怎麼指定,差別都是來自於你要goget那個目標的Repository。
我目前歸納出來有四個因素會影響goget的版號
Commit
標籤(tag)。
goget會參考tag當作版號,例如v.1.2.3
是否啟用GoModule
什麼時候啟用GoModule
接下來我會分三個情境來解說這些差別
如果目標Repository沒有啟用的GoModule
如果目標Repository沒有啟用的GoModule,但是有v2+以上版本會發生什麼事情?
如果在v2+版本以上啟用GoModule的時候會發生什麼事情?
如果目標Repository沒有啟用的GoModule如果你的目標Repository沒有啟用的GoModule的話,他會根據該Repository的tag版本,下載最後一版(VersionSelection)。
例如該Repository有v3.1.2,v2.1.1,v1.2.5,v1.1.0這4個tag,執行gogetgithub.com/my/foo@latest的話,他會下載v3.1.2那個tag的版本。
假設該Repository連tag都沒有的話,則採用Pseudo-versions的方式,會去抓取master分支的最後一個commit,然後你就會看到該版本號的資訊會類似v0.0.0-20200824153131-fdc22cc4ae4b這種格式,他是由v0.0.0-{commit時間}-{commithash}所組成的。
如果目標Repository沒有啟用的GoModule,但是有v2以上版本會發生什麼事情?在看一些GoModule文章的時候,例如UsingGoModules,裡面有提到,啟用GoModule後,如果是v2以上版本的時候,需要加上/vN路徑,例如gogetgithub.com/my/foo/v2,這是當作跟v1是不同路徑的方式來抓v2的版本。
那如果目標Repository沒有啟用GoModule,都採用tag的方式標示版本,會發生什麼事情呢?
這種情況底下,的做法就不是使用/v2,而是使用@的方式指定版本就可以了,例如gogetgithub.com/my/[email protected],因為沒有啟用GoModule的模式,所以所有版本都是在同一個路徑github.com/my/foo底下。
當下載v2以上版本的時候會看到go.mod紀錄的套件會有+incompatible這個字樣,例如requiregithub.com/my/foov3.0.1+incompatible,為什麼會有+incompatible呢?
為什麼有+incompatible?我們要從Go的FAQ-HowshouldImanagepackageversionsusinggoget?說起,這是Go的建議多年的套件管控機制,裡面有一段話說
Packagesintendedforpublicuseshouldtrytomaintainbackwardcompatibilityastheyevolve.TheGo1compatibilityguidelinesareagoodreferencehere:don’tremoveexportednames,encouragetaggedcompositeliterals,andsoon.Ifdifferentfunctionalityisrequired,addanewnameinsteadofchanginganoldone.Ifacompletebreakisrequired,createanewpackagewithanewimportpath
上面畫線的重點是,如果新的版本有包含破壞性更新,則建立一個新的packageimportpath,例如github.com/my/foo/v2。
這是因為當使用同一個packageimportpath時要能夠確保相容性,不能讓使用者更新套件後,程式就壞掉。
而這建議也是從SemanticImportVersioning來的。
GoModule也有根據這個原則設計,啟用GoModule後有三個原則需要遵守
importpath不一樣會當成不同的套件
例如github.com/my/foovsgithub.com/my/foo/v2是不一樣的套件
importpath如果沒有包含/v2+的路徑的話,會當作v1或v0版本
importpath是從go.mod裡面的modulepath定義的,如modulegithub.com/my/foo/v2
簡短來說,+incompatible是指說「當使用的套件沒有啟用GoModule以及其版本號大於v1,也就是v2+的時候,我們import的路徑會是importgithub.com/my/foo,這時候根據上敘的原則2,GoModule會將其看待成v1或v0版本,這就造成與原則2產生衝突。
。
」
這情況下,GoModule會認為該套件並沒有使用SemanticImportVersioning的方式來管控套件,就會認為他跟v1版本是不相容的,所以加上+incompatible當作警告,但不影響使用。
如果在v2+版本以上啟用GoModule的時候會發生什麼事情?現在假設有一個情況,有一個遠端的Repositorygetgithub.com/my/foo一直沒有啟用GoModule,而且已經存在了好幾版的tag,例如v1.2.1、v1.3.5、v1.3.7、v2.1.9、v2.4.7、v3.0.1。
在這情況下gogetgithub.com/my/foo@latest自然會取得v3.0.1+incompatible的版本。
這時候Repositorygithub.com/my/foo的作者又有新版v4.0.0想要釋出,他可以有兩個選擇
繼續不啟用GoModule,新增tagv4.0.0版本。
在這情況下,當然gogetgithub.com/my/foo@latest就會取得v4.0.0+incompatible的版本
決定啟用GoModule改用符合SemanticImportVersioning的規則管理套件,然後在這情況下釋出v4.0.0版本。
在第二個選擇的情況下,gogetgithub.com/my/foo@latest你還是會取得v3.0.1+incompatible,因為根據SemanticImportVersioning的原則,主要版本變更會要求不同路徑,要用gogetgithub.com/my/foo/v4才可以取得v4.0.0的版本,而之後所有的v4版本都會釋出在github.com/my/foo/v4這個路徑底下。
如果這時候新增一個v3.2.3的版本會發生麼事情?在沒有建立gogetgithub.com/my/foo/v3的路徑,直接新增v3.2.0tag的情況下,是沒辦法gogetgithub.com/my/[email protected]版本。
會出現這種錯誤訊息
invalidversion:modulecontainsago.modfile,somajorversionmustbecompatible:shouldbev0orv1,notv3
這是因為,當啟用GoModule後的那個commit就是一個切割點。
在那個commit之前的版本v1.2.1、v1.3.5、v1.3.7、v2.1.9、v2.4.7、v3.0.1都還是放在github.com/my/foo這個路徑底下,所以你還是可以gogetgithub.com/my/[email protected]。
但是在這commit之後,所有規則請按照SemanticImportVersioning來走。
想要新增一個v3的版本?請放在github.com/my/foo/v3底下。
當作者有按照規則走的時候,你就可以gogetgithub.com/my/foo/v3取得v3.2.0版本了。
在這規則底下,就是每一個主版本都放在他該存在的路徑,v2.x.x放在github.com/my/foo/v2路徑,v3.x.x放在github.com/my/foo/v3路徑,v1.x.x就放在github.com/my/foo路徑。
小結這些就是goget各種不同版號的運作機制啦。
這也是為什麼很多人,啟用GoModule後會直接跳一個主版本,否則可能會發生v3的舊版本的在github.com/my/foo路徑,啟用GoModule後的v3新版本會在github.com/my/foo/v3路徑。
到不如就把v3以前都放在github.com/my/foo未來所有版本都開始分路徑github.com/my/foo/v4+。
延伸閱讀[GoModuleswiki][TheGoBlog-UsingGoModules][FAQs—SemanticImportVersioning]
TAGGEDIN
GoGoModule
PREVIOUS
NEXT
PREVIOUS
NEXT
ShareonFacebook
ShareonTwitter
ShareonGoogle+
Miles
I’mapersonwhoisenthusiasticaboutCoding,andthat’smyjobbytheway.
WebDeveloper
Taiwan
by
nopostfound
[C#]動態指定泛型型別
Dec30,2016
前言今天為了程式能寫好看一點,一直在糾結怎麼指定動態泛型,
但是想想實用性好像不太大,可是把這技術忘掉太可惜XD
還是記錄下來,以防忘記
[Angular]AnatomyofanAngularApplication
Jan28,2017
ApplicationAngular2Application的都是由Component組合而成的,而Services則就是提供功能,可以在Component之間使用。
[Angular]AngularModules
Jan30,2017
前言javascrip一直存在著Namespaces的問題,意思是指很容易將variables或者functions定義在globalnamespace。
另一方面javascript並沒有提供管理javascriptcode的方式。
Modules幫我們解決了這個問題
[Angular]BootstrappingAppComponent
Feb2,2017
前言今天要說明的是Angular是如何BootstrappingComponent的。
我們會從pluralsight的課程Angular2:GettingStarted提供的Github範例做說明。
[Angular]Bindingsyntax
Feb4,2017
前言要從class將資料繫結到template上面,Angular有四種方式。
內嵌繫結(Interpolation)
屬性繫結(PropertyBinding)
事件繫結(EventBinding)
雙向繫結(Two-wayBinding)
[Angular]RoutingBasics
Feb8,2017
前言今天要介紹AngularRouting提供了View之間切換的功能,以及如何使用跟怎麼設定。
[Angular]NavigationandRoutingAdditionalTechniques
Feb9,2017
前言上一篇RoutingBasics介紹基本用法後,今天要來多加說明如何帶參數,以及如何使用程式碼navigate到其他route。
[Angular]ProtectingRouteswithGuards
Feb11,2017
前言預設的情況下,任何user都是可以瀏覽到route有對應到的網址,這並不是一個好的情況。
通常會有需要一些權限的控管。
[Angular]NgModuleDecorator
Feb13,2017
前言再深入講NgModule之前,要先說明App.Module的Decorator使用的一些原則。
[Angular]DiveintoAngularModules
Feb14,2017
前言今天要說明如何整合多個AngularModule,讓程式碼職責跟清晰,更好維護。
103postsfound
延伸文章資訊
- 1go get - GO 命令教程- 极客学院Wiki
命令 go get 可以根据要求和实际情况从互联网上下载或更新指定的代码包及其依赖包,并对它们进行编译和安装。在上面这个示例中,我们从著名的代码托管 ...
- 2GoGet – 你的求職夥伴
- 3Go 套件管理
go get 會自行判斷該使用的協定,以這邊的例子來說,就會使用 git 來複製檔案庫至src 目錄底下,結果就是src/github.com/JustinSDK 底下,會有個goexample...
- 4get package - cmd/go/internal/get - pkg.dev
Command{ UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [build flags] [packages]", Short: "do...
- 5Go 1.16 中关于go get 和go install 你需要注意的地方 - MoeLove
概览 · 基本上 go install <package>@<version> 是用于命令的全局安装: · go get 安装二进制的功能,后续版本将会删除; · go get 主要被设计为修改...