Go 模組參考

簡介

模組是 Go 管理相依項目的方式。

此文件是 Go 模組系統的詳細參考手冊。如需建立 Go 專案的簡介,請參閱 如何撰寫 Go 程式碼。如需使用模組、將專案移轉至模組和其他主題的資訊,請參閱部落格系列,從 使用 Go 模組 開始。

模組、套件和版本

模組 是同時發布、版本化和散發的一組套件。模組可以從版本控制儲存庫或模組代理伺服器直接下載。

模組由 模組路徑 識別,此路徑在 go.mod 檔案 中宣告,並附有模組依賴項目的資訊。模組根目錄 是包含 go.mod 檔案的目錄。主模組 是包含呼叫 go 指令目錄的模組。

模組中的每個 套件 都是同一目錄中會一起編譯的原始檔集合。套件路徑 是模組路徑與包含套件的子目錄(相對於模組根目錄)結合而成。例如,模組 "golang.org/x/net" 包含目錄 "html" 中的套件。該套件的路徑為 "golang.org/x/net/html"

模組路徑

模組路徑 是模組的正規名稱,在模組的 go.mod 檔案 中使用 module 指令 宣告。模組的路徑是模組中套件路徑的前綴。

模組路徑應同時描述模組的功能和尋找模組的位置。通常,模組路徑包含儲存庫根目錄路徑、儲存庫中的目錄(通常為空)和主要版本字尾(僅適用於主要版本 2 或更高)。

如果模組可能被其他模組依賴,則必須遵循這些規則,以便 go 命令可以找到並下載模組。模組路徑中允許使用的字元也有幾個 語法限制

永遠不會作為任何其他模組的依賴項擷取的模組可以使用任何有效的套件路徑作為其模組路徑,但必須注意不要與模組的依賴項或 Go 標準函式庫可能使用的路徑發生衝突。Go 標準函式庫使用在第一個路徑元素中不包含點的套件路徑,而 go 命令不會嘗試從網路伺服器解析此類路徑。路徑 exampletest 是保留給使用者的:它們不會用於標準函式庫,並且適合用於獨立模組,例如在教學課程或範例程式碼中定義的模組,或作為測試的一部分建立和操作的模組。

版本

一個 版本 會識別模組的不可變快照,它可能是 正式版本預先發布版本。每個版本都以字母 v 開頭,後接語意化版本。有關版本格式化、詮釋和比較的詳細資訊,請參閱 語意化版本 2.0.0

總之,語意化版本包含三個非負整數(主要版本、次要版本和修補程式版本,由左至右)並以點號分隔。修補程式版本後面可以接一個以連字號開頭的選用預先發布字串。預先發布字串或修補程式版本後面可以接一個以加號開頭的建置中繼資料字串。例如,v0.0.0v1.12.134v8.0.5-prev2.0.9+meta 都是有效的版本。

版本的每個部分都會指出版本是否穩定,以及它是否與前一個版本相容。

如果主要版本為 0 或有預先發布的字尾,則版本會被視為不穩定。不穩定的版本不受相容性要求約束。例如,v0.2.0 可能與 v0.1.0 不相容,而 v1.5.0-beta 可能與 v1.5.0 不相容。

Go 可以使用標籤、分支或未遵循這些慣例的修訂來存取版本控制系統中的模組。然而,在主模組中,go 指令會自動將未遵循此標準的修訂名稱轉換為正規版本。go 指令也會移除建置資料字尾 (+incompatible 除外) 作為此程序的一部分。這可能會產生偽版本,這是預先發布版本,編碼了版本控制系統中的修訂識別碼 (例如 Git commit hash) 和時間戳記。例如,指令 go get golang.org/x/net@daa7c041 會將 commit hash daa7c041 轉換為偽版本 v0.0.0-20191109021931-daa7c04131f5。主模組之外需要正規版本,如果 go.mod 檔案中出現 master 等非正規版本,go 指令會回報錯誤。

偽版本

偽版本是特別格式化的預先發布版本,編碼了版本控制儲存庫中特定修訂的資訊。例如,v0.0.0-20191109021931-daa7c04131f5是偽版本。

偽版本可能參考沒有語意版本標籤的修訂。它們可用於在建立版本標籤之前測試 commit,例如,在開發分支上。

每個偽版本都有三個部分

每個偽版本可能為三種形式之一,視基礎版本而定。這些形式確保偽版本比其基礎版本比較高,但比下一個標記版本低。

多個偽版本可能透過使用不同的基礎版本來參考相同的提交。當較低版本在寫入偽版本後標記時,這會自然發生。

這些形式賦予偽版本兩個有用的屬性

go 指令會執行多項檢查,以確保模組作者可以控制偽版本與其他版本比較的方式,以及偽版本參考實際上屬於模組提交記錄的一部分的修訂版本。

偽版本絕不需要手動輸入。許多指令接受提交雜湊或分支名稱,並會自動將其轉換為偽版本(或標籤版本,如果可用)。例如

go get example.com/mod@master
go list -m -json example.com/mod@abcd1234

主要版本字尾

從主要版本 2 開始,模組路徑必須具有主要版本字尾,例如 /v2,與主要版本相符。例如,如果模組在 v1.0.0 的路徑為 example.com/mod,則在版本 v2.0.0 的路徑必須為 example.com/mod/v2

主要版本字尾實作匯入相容性規則

如果舊套件和新套件具有相同的匯入路徑,則新套件必須與舊套件向後相容。

根據定義,模組新主要版本中的套件與前一主要版本中的對應套件不相容。因此,從 v2 開始,套件需要新的匯入路徑。這是透過在模組路徑中加入主要版本字尾來完成。由於模組路徑是模組中每個套件匯入路徑的前綴,因此在模組路徑中加入主要版本字尾會為每個不相容版本提供不同的匯入路徑。

主要版本字尾不允許在主要版本 v0v1 中使用。在 v0v1 之間不需要變更模組路徑,因為 v0 版本不穩定且沒有相容性保證。此外,對於大多數模組,v1 與最後一個 v0 版本相容;v1 版本作為相容性的承諾,而不是與 v0 相比不相容變更的指標。

作為特例,從 gopkg.in/ 開始的模組路徑必須始終具有主要版本字尾,即使在 v0v1 中也是如此。字尾必須以句點而非斜線開頭(例如,gopkg.in/yaml.v2)。

主要版本字尾讓模組的許多主要版本可以在同一個建置中並存。這可能是由於 菱形相依問題。通常,如果模組被傳遞相依關係要求兩個不同的版本,將會使用較高版本。然而,如果兩個版本不相容,則兩個版本都不會滿足所有用戶端。由於不相容版本必須有不同的主要版本號碼,因此它們也必須由於主要版本字尾而有不同的模組路徑。這解決了衝突:具有不同字尾的模組被視為不同的模組,而它們的套件(甚至相對於它們的模組根目錄位於同一個子目錄中的套件)是不同的。

許多 Go 專案在未遷移至模組前,便已在 v2 或更高版本中發布版本,且未使用主要版本字尾(可能是在模組推出之前)。這些版本會註解 +incompatible 建置標籤(例如 v2.0.0+incompatible)。請參閱 與非模組存放庫的相容性,以取得更多資訊。

將套件解析為模組

go 指令使用 套件路徑 載入套件時,它需要確定哪個模組提供該套件。

go 指令會從 建置清單 中搜尋路徑為套件路徑前綴的模組。例如,如果匯入了套件 example.com/a/b,且模組 example.com/a 在建置清單中,go 指令會檢查 example.com/a 是否包含套件,位於目錄 b 中。目錄中至少必須存在一個副檔名為 .go 的檔案,才能視為套件。不會套用 建置限制 於此目的。如果建置清單中只有一個模組提供該套件,則使用該模組。如果沒有模組提供該套件,或如果有兩個或更多模組提供該套件,go 指令會報告錯誤。-mod=mod 旗標指示 go 指令嘗試尋找提供遺失套件的新模組,並更新 go.modgo.sumgo getgo mod tidy 指令會自動執行此動作。

go 指令尋找新模組的套件路徑時,它會檢查 GOPROXY 環境變數,它是一個以逗號分隔的代理網址清單或關鍵字 directoff。代理網址表示 go 指令應該使用 模組代理 來透過 GOPROXY 協定 進行連繫。direct 表示 go 指令應該 與版本控制系統進行通訊off 表示不應嘗試進行任何通訊。GOPRIVATEGONOPROXY 環境變數 也可用於控制此行為。

對於 GOPROXY 清單中的每個項目,go 指令會要求可能提供套件的每個模組路徑的最新版本(也就是每個套件路徑的前綴)。對於每個成功要求的模組路徑,go 指令會下載最新版本的模組,並檢查模組是否包含要求的套件。如果一個或多個模組包含要求的套件,則會使用路徑最長的模組。如果找到一個或多個模組,但沒有任何模組包含要求的套件,則會回報錯誤。如果找不到任何模組,go 指令會嘗試 GOPROXY 清單中的下一個項目。如果沒有任何項目,則會回報錯誤。

例如,假設 go 指令正在尋找提供套件 golang.org/x/net/html 的模組,而 GOPROXY 設為 https://corp.example.com,https://proxy.golang.orggo 指令可能會提出以下要求

在找到合適的模組後,go 命令會將一個新的 需求,包含新模組的路徑和版本,新增到主模組的 go.mod 檔案中。這可確保在未來載入同一個套件時,會在同一個版本中使用同一個模組。如果已解析的套件並未由主模組中的套件匯入,新的需求會有一個 // indirect 註解。

go.mod 檔案

模組由其根目錄中一個名為 go.mod 的 UTF-8 編碼文字檔定義。go.mod 檔案是以行為導向。每一行都包含一個單一指令,由一個關鍵字和其後的引數組成。例如

module example.com/my/thing

go 1.12

require example.com/other/thing v1.0.2
require example.com/new/thing/v2 v2.3.4
exclude example.com/old/thing v1.2.3
replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5
retract [v1.9.0, v1.9.5]

前導關鍵字可以從相鄰行中抽離出來,以建立一個區塊,就像在 Go 匯入中一樣。

require (
    example.com/new/thing/v2 v2.3.4
    example.com/old/thing v1.2.3
)

go.mod 檔案被設計為人類可讀且機器可寫。go 命令提供了幾個會變更 go.mod 檔案的子命令。例如,go get 可以升級或降級特定依賴項。載入模組圖表的命令會在需要時 自動更新 go.modgo mod edit 可以執行低階編輯。Go 程式可以使用 golang.org/x/mod/modfile 套件以透過程式設計方式進行相同的變更。

主模組需要一個 go.mod 檔案,而任何使用本機檔案路徑指定的 替換模組 也需要。不過,缺乏明確 go.mod 檔案的模組仍然可以作為相依項 需要,或用於替換,並使用模組路徑和版本指定;請參閱 與非模組存放庫的相容性

字彙元素

剖析 go.mod 檔案時,其內容會切分成一連串的標記。有幾種標記:空白、註解、標點符號、關鍵字、識別碼,以及字串。

空白包含空格 (U+0020)、標籤 (U+0009)、回車 (U+000D) 和換行 (U+000A)。除了換行之外的空白字元沒有作用,除了分隔原本會組合在一起的標記。換行是重要的標記。

註解// 開頭,並執行到該行的結尾。不允許 /* */ 註解。

標點符號標記包括 ()=>

關鍵字區分 go.mod 檔案中不同類型的指令。允許的關鍵字包括 modulegorequirereplaceexcluderetract

識別碼是非空白字元的序列,例如模組路徑或語意版本。

字串是由字元組成的引號序列。有兩種字串:以引號 (",U+0022) 開頭和結尾的詮釋字串,以及以反引號 (`,U+0060) 開頭和結尾的原始字串。詮釋字串可能包含由反斜線 (\,U+005C) 後接另一個字元組成的跳脫序列。跳脫的引號 (\") 不會終止詮釋字串。詮釋字串的未引號值是引號之間的字元序列,每個跳脫序列都替換為反斜線後的字元(例如,\" 替換為 "\n 替換為 n)。相反地,原始字串的未引號值只是反引號之間的字元序列;反斜線在原始字串中沒有特殊意義。

識別碼和字串在 go.mod 語法中是可以互換的。

模組路徑和版本

go.mod 檔案中的大多數識別碼和字串都是模組路徑或版本。

模組路徑必須符合下列需求

如果模組路徑出現在 require 指令中且未被取代,或如果模組路徑出現在 replace 指令的右側,go 指令可能需要下載具有該路徑的模組,且必須滿足一些額外需求。

go.mod 檔案中的版本可能是 正規 或非正規。

正規版本以字母 v 開頭,後接遵循 語意化版本 2.0.0 規範的語意化版本。請參閱 版本 以取得更多資訊。

大多數其他識別碼和字串可以用作非正規版本,儘管有一些限制以避免檔案系統、儲存庫和 模組代理 的問題。非正規版本僅允許在主模組的 go.mod 檔案中。當 go 指令自動 更新 go.mod 檔案時,它將嘗試以等效的正規版本取代每個非正規版本。

在模組路徑與版本關聯的地方(例如在 requirereplaceexclude 指令中),最後路徑元素必須與版本一致。請參閱 主要版本字尾

語法

go.mod 語法如下,使用擴充貝克斯-瑙爾範式 (EBNF) 說明。有關 EBNF 語法的詳細資料,請參閱 Go 語言規範中的符號區段

GoMod = { Directive } .
Directive = ModuleDirective |
            GoDirective |
            RequireDirective |
            ExcludeDirective |
            ReplaceDirective |
            RetractDirective .

換行、識別碼和字串分別以 newlineidentstring 表示。

模組路徑和版本以 ModulePathVersion 表示。

ModulePath = ident | string . /* see restrictions above */
Version = ident | string .    /* see restrictions above */

module 指令

module 指令定義主要模組的 路徑go.mod 檔案必須只包含一個 module 指令。

ModuleDirective = "module" ( ModulePath | "(" newline ModulePath newline ")" ) newline .

範例

module golang.org/x/net

不建議使用

模組可以在包含字串 Deprecated: (大小寫敏感) 的註解區塊中標示為不建議使用,字串必須出現在段落的開頭。不建議使用的訊息從冒號之後開始,並一直到段落結尾。註解可以出現在 module 指令之前或之後的同一行。

範例

// Deprecated: use example.com/mod/v2 instead.
module example.com/mod

自 Go 1.17 起,go list -m -u 會檢查 建置清單 中所有不建議使用模組的資訊。go get 會檢查建置命令列上指定套件所需的不建議使用模組。

go 指令擷取模組的不建議使用資訊時,它會從與 @latest 版本查詢 相符的版本載入 go.mod 檔案,而不考慮 撤回排除 項目。go 指令會從相同的 go.mod 檔案載入 已撤回版本 清單。

若要將模組標示為不建議使用,作者可以新增 // Deprecated: 註解並標記新版本。作者可以在較高版本中變更或移除不建議使用的訊息。

不建議使用會套用到模組的所有次要版本。v2 以上的主要版本會視為獨立的模組,因為它們的 主要版本字尾 會讓它們有不同的模組路徑。

棄用訊息旨在告知使用者模組不再受支援,並提供遷移說明,例如最新主要版本。無法棄用個別次要版本和修補程式版本;retract 可能更適合。

go 指令

go 指令表示模組撰寫時假設使用特定 Go 版本的語意。版本必須是有效的 Go 版本,例如 1.91.141.21rc1

go 指令設定使用此模組所需的最低 Go 版本。在 Go 1.21 之前,此指令僅供參考;現在已成為強制性要求:Go 工具鏈拒絕使用宣告較新 Go 版本的模組。

go 指令是選擇要執行哪個 Go 工具鏈的輸入。詳情請參閱「Go 工具鏈」。

go 指令會影響新語言功能的使用

go 指令也會影響 go 指令的行為

go.mod 檔案最多可以包含一個 go 指令。如果沒有 go 指令,大多數指令會新增一個使用目前 Go 版本的 go 指令。

如果沒有 go 指令,會假設為 go 1.16

GoDirective = "go" GoVersion newline .
GoVersion = string | ident .  /* valid release version; see above */

範例

go 1.14

toolchain 指令

toolchain 指令宣告建議與模組一起使用的 Go 工具鏈。建議的 Go 工具鏈版本不能低於 go 指令中宣告的必要 Go 版本。toolchain 指令只有在模組是主模組,而且預設工具鏈版本低於建議工具鏈版本時才會生效。

為了可重製性,go 指令會在每次更新 go.mod 檔案中的 go 版本時(通常在 go get 期間),將自己的工具鏈名稱寫入 toolchain 行中。

如需詳細資訊,請參閱「Go 工具鏈」。

ToolchainDirective = "toolchain" ToolchainName newline .
ToolchainName = string | ident .  /* valid toolchain name; see “Go toolchains” */

範例

toolchain go1.21.0

require 指令

require 指令宣告給定模組相依性的必要最低版本。對於每個必要的模組版本,go 指令會載入該版本的 go.mod 檔案,並納入該檔案中的需求。載入所有需求後,go 指令會使用 最小版本選取 (MVS) 來解析這些需求,以產生 建置清單

go 指令會自動為某些需求新增 // indirect 註解。// indirect 註解表示沒有任何來自必要模組的套件是由 主模組 中的任何套件直接匯入的。

如果 go 指令 指定 go 1.16 或更低版本,當模組的選取版本高於主模組的其他相依性(傳遞)暗示的版本時,go 指令會新增間接需求。這可能是因為明確升級(go get -u ./...)、移除先前強制執行需求的其他相依性(go mod tidy),或匯入套件的相依性在自己的 go.mod 檔案中沒有對應需求(例如完全沒有 go.mod 檔案的相依性)。

go 1.17 及以上版本中,go 指令會新增一個間接需求,針對每個提供任何套件的模組,這些套件是由主模組中的套件或測試匯入(甚至是 間接 匯入),或作為引數傳遞給 go get。這些更全面的需求可啟用 模組圖形剪裁延遲載入模組

RequireDirective = "require" ( RequireSpec | "(" newline { RequireSpec } ")" newline ) .
RequireSpec = ModulePath Version newline .

範例

require golang.org/x/net v1.2.3

require (
    golang.org/x/crypto v1.4.5 // indirect
    golang.org/x/text v1.6.7
)

exclude 指令

exclude 指令可防止 go 指令載入模組版本。

自 Go 1.16 起,如果在任何 go.mod 檔案中由 require 指令參照的版本被主模組的 go.mod 檔案中的 exclude 指令排除,則會忽略該需求。這可能會導致 go getgo mod tidy 等指令在 go.mod 中新增對更高版本的新需求,並在適當情況下加上 // indirect 註解。

在 Go 1.16 之前,如果被排除的版本由 require 指令參照,則 go 指令會列出模組的可用版本(如 go list -m -versions 所示),並載入下一個較高的非排除版本。這可能會導致非決定性的版本選取,因為下一個較高版本可能會隨著時間而改變。基於此目的,會考慮發行版本和預發行版本,但不會考慮偽版本。如果沒有較高的版本,則 go 指令會報告錯誤。

exclude 指令僅適用於主模組的 go.mod 檔案,並會在其他模組中被忽略。詳情請參閱 最小版本選取

ExcludeDirective = "exclude" ( ExcludeSpec | "(" newline { ExcludeSpec } ")" newline ) .
ExcludeSpec = ModulePath Version newline .

範例

exclude golang.org/x/net v1.2.3

exclude (
    golang.org/x/crypto v1.4.5
    golang.org/x/text v1.6.7
)

replace 指令

replace 指令會使用在其他地方找到的內容取代特定模組版本的內容,或取代模組的所有版本。替換內容可以用另一個模組路徑和版本,或平台特定的檔案路徑來指定。

如果箭頭 (=>) 左側有版本,則只會取代該特定版本的模組;其他版本將會正常存取。如果省略左側版本,則會取代模組的所有版本。

如果箭頭右側的路徑是絕對路徑或相對路徑 (以 ./../ 開頭),則會將其解譯為替換模組根目錄的本機檔案路徑,其中必須包含 go.mod 檔案。在此情況下,必須省略替換版本。

如果右側的路徑不是本機路徑,則它必須是有效的模組路徑。在此情況下,需要版本。建置清單中也不得出現相同的模組版本。

無論替換是使用本機路徑或模組路徑指定,如果替換模組有 go.mod 檔案,則其 module 指令必須與其取代的模組路徑相符。

replace 指令只會套用在主模組的 go.mod 檔案中,且會在其他模組中被忽略。詳情請參閱 最小版本選取

如果有多個主模組,則會套用所有主模組的 go.mod 檔案。不允許主模組之間有衝突的 replace 指令,且必須在 go.work 檔案中的替換 中移除或覆寫。

請注意,單獨的 replace 指令並不會將模組新增至 模組圖。還需要一個參照替換模組版本的 require 指令,這個指令可以出現在主模組的 go.mod 檔案或依賴項的 go.mod 檔案中。如果左側的模組版本不是必需的,則 replace 指令不會產生任何效果。

ReplaceDirective = "replace" ( ReplaceSpec | "(" newline { ReplaceSpec } ")" newline ) .
ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline
            | ModulePath [ Version ] "=>" ModulePath Version newline .
FilePath = /* platform-specific relative or absolute file path */

範例

replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5

replace (
    golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5
    golang.org/x/net => example.com/fork/net v1.4.5
    golang.org/x/net v1.2.3 => ./fork/net
    golang.org/x/net => ./fork/net
)

retract 指令

retract 指令表示不應依賴由 go.mod 定義的模組版本或版本範圍。當版本過早發布或在版本發布後發現嚴重問題時,retract 指令會很有用。已撤回的版本應持續在版本控制儲存庫和 模組代理 中提供,以確保依賴它們的建置不會中斷。retract 一詞取自學術文獻:已撤回的研究論文仍然可用,但它有問題,不應作為未來工作的基礎。

當模組版本被撤回時,使用者將不會使用 go getgo mod tidy 或其他指令自動升級到該版本。依賴已撤回版本的建置應持續運作,但當使用者使用 go list -m -u 檢查更新或使用 go get 更新相關模組時,系統會通知使用者撤回事項。

若要撤回版本,模組作者應將 retract 指令新增至 go.mod,然後發布包含該指令的新版本。新版本必須高於其他發行版本或預發行版本;也就是說,@latest 版本查詢 應在考慮撤回之前解析為新版本。go 指令會載入並套用 go list -m -retracted $modpath@latest(其中 $modpath 是模組路徑)所顯示版本的撤回事項。

除非使用 -retracted 旗標,否則縮回的版本會隱藏在 go list -m -versions 印出的版本清單中。在解析版本查詢(例如 @>=v1.2.3@latest)時,會排除縮回的版本。

包含縮回的版本可能會縮回它自己。如果模組的最高發行版本或預發行版本縮回它自己,那麼在排除縮回的版本後,@latest 查詢會解析為較低的版本。

舉例來說,考慮模組 example.com/m 的作者意外發布版本 v1.0.0 的情況。為了防止使用者升級到 v1.0.0,作者可以在 go.mod 中新增兩個 retract 指令,然後使用縮回標記 v1.0.1

retract (
    v1.0.0 // Published accidentally.
    v1.0.1 // Contains retractions only.
)

當使用者執行 go get example.com/m@latest 時,go 指令會從 v1.0.1(現在是最高版本)讀取縮回。v1.0.0v1.0.1 都已縮回,因此 go 指令將升級(或降級!)到下一個較高的版本,可能是 v0.9.5

retract 指令可以寫入單一版本(例如 v1.0.0),或寫入一個封閉的版本區間,其上下界限由 [] 分隔(例如 [v1.1.0, v1.2.0])。單一版本等於上下界限相同的區間。與其他指令一樣,多個 retract 指令可以群組在一起,並以一行結尾的 ( 和單獨一行的 ) 分隔成一個區塊。

每個 retract 指令都應該有一個註解來說明收回的原因,儘管這不是強制性的。go 指令可能會在有關已收回版本的警告和 go list 輸出中顯示理由註解。理由註解可以寫在 retract 指令的正上方(中間沒有空白行),或寫在同一行的後面。如果註解出現在區塊上方,則它適用於區塊中沒有自己註解的所有 retract 指令。理由註解可以跨越多行。

RetractDirective = "retract" ( RetractSpec | "(" newline { RetractSpec } ")" newline ) .
RetractSpec = ( Version | "[" Version "," Version "]" ) newline .

範例

retract v1.0.0
retract [v1.0.0, v1.9.9]
retract (
    v1.0.0
    [v1.0.0, v1.9.9]
)
retract [v0.0.0, v1.0.1] // assuming v1.0.1 contains this retraction.
retract [v0.0.0-0, v0.15.2]  // assuming v0.15.2 contains this retraction.

retract 指令已新增至 Go 1.16。如果在 主模組的 go.mod 檔案中寫入 retract 指令,Go 1.15 和更低版本會回報錯誤,並且會忽略相依項的 go.mod 檔案中的 retract 指令。

自動更新

如果 go.mod 遺失資訊或無法準確反映現實,大多數指令都會回報錯誤。go getgo mod tidy 指令可用於修復這些問題的大部分。此外,-mod=mod 旗標可用於大多數支援模組的指令(go buildgo test 等),以指示 go 指令自動修復 go.modgo.sum 中的問題。

例如,考慮這個 go.mod 檔案

module example.com/M

go 1.16

require (
    example.com/A v1
    example.com/B v1.0.0
    example.com/C v1.0.0
    example.com/D v1.2.3
    example.com/E dev
)

exclude example.com/D v1.2.3

使用 -mod=mod 觸發的更新會將非正規版本識別碼改寫為 正規 semver 形式,因此 example.com/Av1 會變成 v1.0.0,而 example.com/Edev 會變成 dev 分支上最新提交的偽版本,可能是 v0.0.0-20180523231146-b3f5c0f6e5f1

此更新修改了尊重排除項的要求,因此對排除的 example.com/D v1.2.3 的要求已更新為使用 example.com/D 的下一個可用版本,可能是 v1.2.4v1.3.0

此更新移除了多餘或誤導性的要求。例如,如果 example.com/A v1.0.0 本身需要 example.com/B v1.2.0example.com/C v1.0.0,則 go.modexample.com/B v1.0.0 的要求具有誤導性(被 example.com/Av1.2.0 的需求所取代),而它對 example.com/C v1.0.0 的要求是多餘的(由 example.com/A 對相同版本的需要所暗示),因此這兩個要求都將被移除。如果主模組包含直接從 example.com/Bexample.com/C 匯入套件的套件,則這些要求將會保留,但會更新為實際使用的版本。

最後,此更新以規範格式重新格式化 go.mod,以便未來的機械變更會產生最小的差異。如果只需要格式變更,go 指令不會更新 go.mod

由於模組圖定義了匯入陳述的意義,因此載入套件的任何指令也會使用 go.mod,因此可以更新它,包括 go buildgo getgo installgo listgo testgo mod tidy

在 Go 1.15 及更低版本中,-mod=mod 旗標預設為啟用,因此更新會自動執行。自 Go 1.16 以來,go 指令的作用就像設定了 -mod=readonly:如果需要對 go.mod 進行任何變更,go 指令會回報錯誤並建議修正。

最小版本選取 (MVS)

Go 使用一種稱為 最小版本選取 (MVS) 的演算法來選取在建置套件時要使用的模組版本組。MVS 在 Russ Cox 的 最小版本選取 中有詳細說明。

在概念上,MVS 運作於模組的有向圖,並使用 go.mod 檔案 指定。圖中的每個頂點代表一個模組版本。每個邊緣代表相依性所需的最低版本,並使用 require 指令指定。此圖表可以透過主模組的 go.mod 檔案中的 excludereplace 指令,以及 go.work 檔案中的 replace 指令進行修改。

MVS 產生 建置清單 作為輸出,也就是用於建置的模組版本清單。

MVS 從主模組(圖表中沒有版本的特殊頂點)開始,並遍歷圖表,追蹤每個模組的最高所需版本。在遍歷結束時,最高所需版本組成建置清單:它們是滿足所有需求的最低版本。

可以使用命令 go list -m all 來檢查建置清單。與其他相依性管理系統不同,建置清單不會儲存在「鎖定」檔案中。MVS 是確定性的,並且在相依性發布新版本時,建置清單不會改變,因此 MVS 用於在每個模組感知命令的開頭計算它。

考慮下圖中的範例。主模組需要版本 1.2 或更高的模組 A,以及版本 1.2 或更高的模組 B。A 1.2 和 B 1.2 分別需要 C 1.3 和 C 1.4。C 1.3 和 C 1.4 都需要 D 1.2。

Module version graph with visited versions highlighted

MVS 會拜訪並載入以藍色突出的每個模組版本的 go.mod 檔案。在圖表遍歷結束時,MVS 會傳回包含粗體版本的建置清單:A 1.2、B 1.2、C 1.4 和 D 1.2。請注意,B 和 D 有較高版本可用,但 MVS 沒有選擇它們,因為沒有任何東西需要它們。

替換

模組的內容(包括其 go.mod 檔案)可以使用主模組的 go.mod 檔案或工作區的 go.work 檔案中的 replace 指令 進行取代。replace 指令可以套用於模組的特定版本或所有版本。

取代會變更模組圖表,因為取代模組可能具有與取代版本不同的依賴項。

考量以下範例,其中 C 1.4 已被 R 取代。R 依賴於 D 1.3,而非 D 1.2,因此 MVS 會傳回包含 A 1.2、B 1.2、C 1.4(已由 R 取代)和 D 1.3 的建置清單。

Module version graph with a replacement

排除

模組也可以使用主模組的 go.mod 檔案中的 exclude 指令 在特定版本中排除。

排除也會變更模組圖表。當版本被排除時,它會從模組圖表中移除,而對它的需求會重新導向到下一個較高版本。

考量以下範例。C 1.3 已被排除。MVS 會像 A 1.2 需要 C 1.4(下一個較高版本),而非 C 1.3 一樣運作。

Module version graph with an exclusion

升級

go get 指令可以用於升級一組模組。為了執行升級,go 指令會在執行 MVS 之前變更模組圖表,方法是從已拜訪的版本新增邊緣到已升級的版本。

考量以下範例。模組 B 可以從 1.2 升級到 1.3,C 可以從 1.3 升級到 1.4,而 D 可以從 1.2 升級到 1.3。

Module version graph with upgrades

升級(和降級)可能會新增或移除間接依賴項。在這種情況下,E 1.1 和 F 1.1 會在升級後出現在建置清單中,因為 B 1.3 需要 E 1.1。

為了保留升級,go 命令會更新 go.mod 中的要求。它會將 B 的要求變更為版本 1.3。它還會新增對 C 1.4 和 D 1.3 的要求,並加上 // indirect 註解,因為否則不會選取這些版本。

降級

go get 命令也可以用來降級一組模組。若要執行降級,go 命令會透過移除降級版本以上的版本來變更模組圖形。它還會移除依賴於已移除版本的其他模組版本,因為它們可能與其相依項目的降級版本不相容。如果主模組需要降級所移除的模組版本,則會將要求變更為尚未移除的先前版本。如果沒有可用的先前版本,則會移除要求。

考慮以下範例。假設在 C 1.4 中發現問題,因此我們降級到 C 1.3。C 1.4 會從模組圖形中移除。B 1.2 也會移除,因為它需要 C 1.4 或更高版本。主模組對 B 的要求會變更為 1.1。

Module version graph with downgrade

go get 也可以使用參數後的 @none 字尾來完全移除相依項目。這與降級的運作方式類似。已命名模組的所有版本都會從模組圖形中移除。

模組圖形剪裁

如果主模組在 go 1.17 或更高版本,則用於 最小版本選取模組圖形 僅包含每個模組相依項目的立即要求,這些相依項目在自己的 go.mod 檔案中指定 go 1.17 或更高版本,除非該模組版本也由 go 1.16 或以下的其他相依項目(傳遞)要求。(go 1.17 相依項目的傳遞相依項目會從模組圖形中剪裁掉。)

由於 go 1.17 go.mod 檔案包含每個相依性的一個 require 指令,以建置該模組中的任何套件或測試,因此已修剪的模組圖表包含所有相依性,這些相依性是 go buildgo test 所需的,且由 主模組 明確要求的任何相依性。在給定的模組中,不需要建置任何套件或測試的模組無法影響其套件的執行時期行為,因此從模組圖表中修剪出的相依性只會造成原本無關的模組之間的干擾。

其需求已修剪出的模組仍出現在模組圖表中,且仍由 go list -m all 報告:其 選取版本 已知且定義明確,且可以從這些模組載入套件(例如,作為從其他模組載入的測試的傳遞相依性)。然而,由於 go 指令無法輕易識別這些模組的哪些相依性已滿足,因此 go buildgo test 的引數無法包含需求已修剪出的模組的套件。go get 將包含每個已命名套件的模組提升為明確相依性,允許在該套件上呼叫 go buildgo test

由於 Go 1.16 及更早版本不支援模組圖表修剪,因此仍為每個指定 go 1.16 或更低版本的模組包含相依性的完整傳遞閉包,包括傳遞的 go 1.17 相依性。(在 go 1.16 及更低版本,go.mod 檔案僅包含 直接相依性,因此必須載入一個更大的圖表,以確保包含所有間接相依性。)

go mod tidy 為模組所記錄的 go.sum 檔案 預設包含 Go 版本所需的檢查和,版本比其 go 指令 中指定的版本低一。因此,go 1.17 模組包含 Go 1.16 載入的完整模組圖表所需的檢查和,但 go 1.18 模組只會包含 Go 1.17 載入的已修剪模組圖表所需的檢查和。-compat 旗標可用於覆寫預設版本(例如,在 go 1.17 模組中更積極地修剪 go.sum 檔案)。

請參閱 設計文件 以取得更多詳細資訊。

延遲模組載入

為模組圖表修剪所新增的更全面需求,在模組內作業時也啟用了另一項最佳化。如果主模組為 go 1.17 或更高版本,go 指令會避免載入完整的模組圖表,直到(且除非)需要為止。它只會載入主模組的 go.mod 檔案,然後嘗試只使用那些需求來載入要建置的套件。如果要匯入的套件(例如,主模組外部套件的測試相依性)未在那些需求中找到,則會依需求載入模組圖表的其餘部分。

如果所有匯入的套件都可以在不載入模組圖表的情況下找到,go 指令接著會載入包含那些套件的模組的 go.mod 檔案,並將其需求與主模組的需求進行比對,以確保它們在本地是一致的。(不一致的情況可能因版本控制合併、手動編輯,以及已使用本機檔案系統路徑 取代 的模組變更而產生。)

工作區

一個 工作區 是磁碟上的一組模組,在執行 最小版本選取 (MVS) 時用作主要模組。

工作區可以在 go.work 檔案 中宣告,該檔案會指定工作區中每個模組的模組目錄的相對路徑。如果沒有 go.work 檔案,工作區將包含包含目前目錄的單一模組。

大多數與模組一起運作的 go 子指令會在由目前工作區決定的模組組上執行。go mod initgo mod whygo mod editgo mod tidygo mod vendorgo get 始終會在單一主要模組上執行。

指令會先檢查 GOWORK 環境變數,以判斷它是否在工作區背景中。如果 GOWORK 設為 off,指令將會在單一模組背景中。如果它為空或未提供,指令將會搜尋目前工作目錄,然後搜尋後續父目錄,以尋找 go.work 檔案。如果找到檔案,指令將會在它定義的工作區中執行;否則,工作區將只包含包含工作目錄的模組。如果 GOWORK 命名為以 .work 結尾的現有檔案的路徑,工作區模式將會啟用。任何其他值都是錯誤。你可以使用 go env GOWORK 指令來判斷 go 指令正在使用哪個 go.work 檔案。如果 go 指令不在工作區模式中,go env GOWORK 將會為空。

go.work 檔案

工作區由名為 go.work 的 UTF-8 編碼文字檔定義。go.work 檔案是逐行導向的。每一行都包含一個單一指令,由一個關鍵字後接引數組成。例如

go 1.18

use ./my/first/thing
use ./my/second/thing

replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5

就像在 go.mod 檔案中,可以將領先關鍵字從相鄰行中抽離出來,以建立區塊。

use (
    ./my/first/thing
    ./my/second/thing
)

go 指令提供多個子指令來操作 go.work 檔案。go work init 會建立新的 go.work 檔案。go work use 會將模組目錄新增到 go.work 檔案。go work edit 會執行低階編輯。Go 程式可以使用 golang.org/x/mod/modfile 套件以程式化方式進行相同的變更。

go 指令會維護一個 go.work.sum 檔案,用來追蹤工作區使用的雜湊,這些雜湊不在工作區模組的 go.sum 檔案中。

字彙元素

go.work 檔案中的詞彙元素定義方式與 go.mod 檔案 完全相同。

語法

go.work 語法如下使用擴充貝克斯-瑙爾範式 (EBNF) 指定。有關 EBNF 語法的詳細資訊,請參閱 Go 語言規範中的符號區段

GoWork = { Directive } .
Directive = GoDirective |
            ToolchainDirective |
            UseDirective |
            ReplaceDirective .

換行、識別碼和字串分別以 newlineidentstring 表示。

模組路徑和版本使用 ModulePathVersion 表示。模組路徑和版本指定方式與 go.mod 檔案 完全相同。

ModulePath = ident | string . /* see restrictions above */
Version = ident | string .    /* see restrictions above */

go 指令

有效的 go.work 檔案中需要 go 指令。版本必須是有效的 Go 發行版本:正整數後接一個小數點和一個非負整數(例如 1.181.19)。

go 指令指出 go.work 檔案預計與哪個 go 工具鏈版本搭配使用。如果變更 go.work 檔案格式,未來版本的工具鏈會根據其指定的版本來詮釋檔案。

go.work 檔案最多可以包含一個 go 指令。

GoDirective = "go" GoVersion newline .
GoVersion = string | ident .  /* valid release version; see above */

範例

go 1.18

toolchain 指令

toolchain 指令宣告建議在工作區中使用的 Go 工具鏈。只有當預設工具鏈比建議的工具鏈舊時,才會產生作用。

如需詳細資訊,請參閱「Go 工具鏈」。

ToolchainDirective = "toolchain" ToolchainName newline .
ToolchainName = string | ident .  /* valid toolchain name; see “Go toolchains” */

範例

toolchain go1.21.0

use 指令

use 會將磁碟上的模組新增到工作區中主模組的集合中。其引數是包含模組的 go.mod 檔案的目錄的相對路徑。use 指令不會新增其引數目錄的子目錄中所包含的模組。這些模組可以透過包含其 go.mod 檔案的目錄在個別的 use 指令中新增。

UseDirective = "use" ( UseSpec | "(" newline { UseSpec } ")" newline ) .
UseSpec = FilePath newline .
FilePath = /* platform-specific relative or absolute file path */

範例

use ./mymod  // example.com/mymod

use (
    ../othermod
    ./subdir/thirdmod
)

replace 指令

go.mod 檔案中的 replace 指令類似,go.work 檔案中的 replace 指令會將特定版本模組或所有版本模組的內容替換為在其他地方找到的內容。go.work 中的萬用字元替換會覆寫 go.mod 檔案中特定版本的 replace

go.work 檔案中的 replace 指令會覆寫工作區模組中相同模組或模組版本的任何替換。

ReplaceDirective = "replace" ( ReplaceSpec | "(" newline { ReplaceSpec } ")" newline ) .
ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline
            | ModulePath [ Version ] "=>" ModulePath Version newline .
FilePath = /* platform-specific relative or absolute file path */

範例

replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5

replace (
    golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5
    golang.org/x/net => example.com/fork/net v1.4.5
    golang.org/x/net v1.2.3 => ./fork/net
    golang.org/x/net => ./fork/net
)

與非模組儲存庫的相容性

為了確保從 GOPATH 到模組的順利過渡,go 指令可以透過新增 go.mod 檔案,以模組感知模式從尚未轉移到模組的儲存庫下載並建置套件。

go 指令從儲存庫中直接下載特定版本的模組時,它會查詢模組路徑的儲存庫 URL,將版本對應到儲存庫中的修訂版本,然後擷取該修訂版本的儲存庫封存檔。如果模組路徑等於儲存庫根路徑,且儲存庫根目錄不包含 go.mod 檔案,go 指令會在模組快取中合成一個 go.mod 檔案,其中包含module 指令,而沒有其他內容。由於合成的 go.mod 檔案不包含其相依項目的require 指令,因此其他相依於這些項目的模組可能需要額外的 require 指令(加上 // indirect 註解),以確保每次建置時都能以相同版本擷取每個相依項目。

go 指令從代理伺服器下載模組時,它會將 go.mod 檔案與模組內容的其他部分分開下載。如果原始模組沒有 go.mod 檔案,則代理伺服器預期會提供合成的 go.mod 檔案。

+incompatible 版本

在主版本 2 或更高版本發布的模組,其模組路徑上必須有對應的主版本後綴。例如,如果模組在 v2.0.0 發布,其路徑必須有 /v2 後綴。這允許 go 指令將專案的各個主版本視為不同的模組,即使它們是在同一個儲存庫中開發的。

當模組支援新增到 go 指令時,引入了主版本後綴需求,且許多儲存庫已在之前標記了主版本為 2 或更高版本。為了與這些儲存庫保持相容性,go 指令會在沒有 go.mod 檔案的主版本 2 或更高版本中新增 +incompatible 後綴。+incompatible 表示版本屬於與較低主版本號碼版本相同模組的一部分;因此,go 指令可能會自動升級到較高的 +incompatible 版本,即使這可能會中斷建置。

考慮以下範例需求

require example.com/m v4.1.2+incompatible

版本 v4.1.2+incompatible 參照儲存庫中提供模組 example.com/m語意版本標籤 v4.1.2。模組必須在儲存庫根目錄中(也就是說,儲存庫根路徑 也必須是 example.com/m),而且不能存在 go.mod 檔案。模組可能會有主要版本號較低的版本,例如 v1.5.2,而且 go 指令可能會從這些版本自動升級到 v4.1.2+incompatible(請參閱 最小版本選取 (MVS),以取得升級運作方式的資訊)。

在版本 v2.0.0 之後才移轉到模組的儲存庫,通常應該要發布新的主要版本。在上述範例中,作者應該建立路徑為 example.com/m/v5 的模組,並且應該發布版本 v5.0.0。作者還應該更新模組中套件的匯入,以使用前置詞 example.com/m/v5,而不是 example.com/m。請參閱 Go 模組:v2 及其後續版本,以取得更詳細的範例。

請注意,+incompatible 字尾不應該出現在儲存庫中的標籤上;像 v4.1.2+incompatible 這樣的標籤將會被忽略。字尾只會出現在 go 指令所使用的版本中。請參閱 將版本對應到提交,以取得版本和標籤之間區別的詳細資料。

另請注意,+incompatible 字尾可能會出現在 偽版本 上。例如,v2.0.1-20200722182040-012345abcdef+incompatible 可能是一個有效的偽版本。

最小模組相容性

在主要版本 2 或更高版本發布的模組必須在 主要版本字尾 上有 模組路徑。模組可以在其儲存庫中的 主要版本子目錄 中開發,也可以不開發。這對在建置 GOPATH 模式時匯入模組內套件的套件有影響。

通常在 GOPATH 模式中,套件會儲存在與其 儲存庫根路徑 相符的目錄中,並與其在儲存庫中的目錄結合。例如,儲存庫中路徑為 example.com/repo、子目錄為 sub 的套件會儲存在 $GOPATH/src/example.com/repo/sub 中,並會匯入為 example.com/repo/sub

對於有主要版本字尾的模組,可能會在目錄 $GOPATH/src/example.com/repo/v2/sub 中找到套件 example.com/repo/v2/sub。這需要在儲存庫的 v2 子目錄中開發模組。go 指令支援此功能,但並不要求如此(請參閱 將版本對應至提交)。

如果模組沒有在主要版本子目錄中開發,則其在 GOPATH 中的目錄不會包含主要版本字尾,且其套件可以在沒有主要版本字尾的情況下匯入。在上述範例中,套件會在目錄 $GOPATH/src/example.com/repo/sub 中找到,並會匯入為 example.com/repo/sub

這會為打算在模組模式和 GOPATH 模式中建置的套件造成問題:模組模式需要字尾,而 GOPATH 模式不需要。

為了修正此問題,在 Go 1.11 中加入了 最小模組相容性,並回溯移植到 Go 1.9.7 和 1.10.3。當匯入路徑解析為 GOPATH 模式中的目錄時

這些規則允許已遷移到模組的套件匯入已遷移到模組的其他套件,即使在使用 GOPATH 模式建置時未曾使用主要版本子目錄。

支援模組的指令

大多數 go 指令可以在支援模組模式GOPATH 模式中執行。在支援模組模式中,go 指令使用 go.mod 檔案來尋找已設定版本的相依性,並且通常會從 模組快取 中載入套件,如果缺少模組,則下載模組。在 GOPATH 模式中,go 指令會忽略模組;它會在 vendor 目錄GOPATH 中尋找相依性。

從 Go 1.16 開始,支援模組模式預設啟用,無論是否有 go.mod 檔案。在較低版本中,當目前目錄或任何父目錄中存在 go.mod 檔案時,會啟用支援模組模式。

支援模組模式可以用 GO111MODULE 環境變數控制,該變數可以設定為 onoffauto

在模組感知模式中,GOPATH 不再定義建置期間匯入的意義,但它仍會儲存已下載的相依性 (在 GOPATH/pkg/mod 中;請參閱 模組快取) 和已安裝的指令 (在 GOPATH/bin 中,除非設定了 GOBIN)。

建置指令

所有載入封包資訊的指令都是模組感知的。這包括

在模組感知模式下執行時,這些指令會使用 go.mod 檔案來詮釋在指令列上列出或寫在 Go 原始碼檔案中的匯入路徑。這些指令接受以下旗標,這適用於所有模組指令。

供應

在使用模組時,go 指令通常會透過從來源下載模組到模組快取中,然後從那些下載的副本載入套件,來滿足相依性。供應 可以用來允許與舊版 Go 互通,或確保用於建置的所有檔案都儲存在單一檔案樹中。

go mod vendor 指令會在 主模組 的根目錄中建構一個名為 vendor 的目錄,其中包含建置和測試主模組中套件所需的所有套件副本。僅由主模組外部套件的測試匯入的套件不會包含在內。與 go mod tidy 和其他模組指令一樣,建構 vendor 目錄時不會考慮 建置限制,但 ignore 除外。

go mod vendor 也會建立檔案 vendor/modules.txt,其中包含已供應套件的清單,以及複製來源的模組版本。當供應已啟用時,此清單會用作模組版本資訊的來源,如 go list -mgo version -m 所報告的。當 go 指令讀取 vendor/modules.txt 時,它會檢查模組版本是否與 go.mod 一致。如果 go.mod 已在 vendor/modules.txt 產生後變更,go 指令會報告錯誤。應再次執行 go mod vendor 以更新 vendor 目錄。

如果 vendor 目錄存在於主模組的根目錄中,如果主模組的 go.mod 檔案 中的 go 版本1.14 或更高,則會自動使用它。若要明確啟用供應,請使用旗標 -mod=vendor 呼叫 go 指令。若要停用供應,請使用旗標 -mod=readonly-mod=mod

當供應已啟用時,建置指令(例如 go buildgo test)會從 vendor 目錄載入套件,而不是存取網路或本機模組快取。go list -m 指令只會列印 go.mod 中所列模組的資訊。當供應已啟用時,go mod 指令(例如 go mod downloadgo mod tidy)不會有不同的作用,而且仍會下載模組並存取模組快取。當供應已啟用時,go get 也不會以不同的方式運作。

GOPATH 模式中的供應 不同,go 命令會略過主模組根目錄以外位置的供應目錄。此外,由於其他模組中的供應目錄並未被使用,因此 go 命令在建置 模組 zip 檔案 時不會包含供應目錄(但請參閱已知錯誤 #31562#37397)。

go get

用法

go get [-d] [-t] [-u] [build flags] [packages]

範例

# Upgrade a specific module.
$ go get golang.org/x/net

# Upgrade modules that provide packages imported by packages in the main module.
$ go get -u ./...

# Upgrade or downgrade to a specific version of a module.
$ go get golang.org/x/text@v0.3.2

# Update to the commit on the module's master branch.
$ go get golang.org/x/text@master

# Remove a dependency on a module and downgrade modules that require it
# to versions that don't require it.
$ go get golang.org/x/text@none

# Upgrade the minimum required Go version for the main module.
$ go get go

# Upgrade the suggested Go toolchain, leaving the minimum Go version alone.
$ go get toolchain

# Upgrade to the latest patch release of the suggested Go toolchain.
$ go get toolchain@patch

go get 命令會更新 go.mod 檔案主模組 的模組相依性,然後建置並安裝命令列上列出的套件。

第一步是決定要更新哪些模組。go get 接受一組套件、套件模式和模組路徑作為引數。如果指定套件引數,go get 會更新提供該套件的模組。如果指定套件模式(例如,all 或具有 ... 萬用字元的路徑),go get 會將模式擴充為一組套件,然後更新提供這些套件的模組。如果引數命名模組但未命名套件(例如,模組 golang.org/x/net 在其根目錄中沒有套件),go get 會更新模組,但不會建置套件。如果未指定引數,go get 會像指定 . 一樣作用(目前目錄中的套件);這可以與 -u 旗標一起使用,以更新提供已匯入套件的模組。

每個引數都可能包含一個 版本查詢字尾,表示所需的版本,例如 go get golang.org/x/text@v0.3.0。版本查詢字尾包含一個 @ 符號,後接一個 版本查詢,其中可能表示特定版本(v0.3.0)、版本前綴(v0.3)、分支或標籤名稱(master)、修訂(1234abcd)或特殊查詢之一,例如 latestupgradepatchnone。如果未提供版本,go get 會使用 @upgrade 查詢。

一旦 go get 已將其引數解析為特定模組和版本,go get 將會新增、變更或移除主模組 go.mod 檔案中的 require 指令,以確保模組在未來維持在想要的版本。請注意,go.mod 檔案中的所需版本為最低版本,且可能會在新增新的相依性時自動增加。有關模組感知命令如何選取版本以及解決衝突的詳細資訊,請參閱 最小版本選取 (MVS)

如果命令列上命名的模組被新增、升級或降級,其他模組可能會升級,如果命名模組的新版本需要其他模組的更高版本。例如,假設模組 example.com/a 升級到版本 v1.5.0,而該版本需要模組 example.com/b 的版本 v1.2.0。如果模組 example.com/b 目前需要版本 v1.1.0go get example.com/a@v1.5.0 也會將 example.com/b 升級到 v1.2.0

go get upgrading a transitive requirement

如果命令列上命名的模組被降級或移除,其他模組可能會降級。繼續上述範例,假設模組 example.com/b 降級到 v1.1.0。模組 example.com/a 也會降級到需要 example.com/b 版本 v1.1.0 或更低版本的版本。

go get downgrading a transitive requirement

可以使用版本字尾 @none 移除模組需求。這是一種特殊的降級。相依於已移除模組的模組會視需要降級或移除。即使主模組中的套件匯入了其中一個或多個套件,模組需求也可能會被移除。在此情況下,下一個建置命令可能會新增新的模組需求。

如果模組需要兩個不同版本(在命令列引數中明確指定,或用於滿足升級和降級),go get 會回報錯誤。

go get 選擇一組新版本後,它會檢查任何新選取的模組版本或任何提供命令列中指定套件的模組是否已 撤回棄用go get 會為它找到的每個已撤回版本或已棄用模組印出警告。go list -m -u all 可用於檢查所有相依項中的撤回和棄用。

go get 更新 go.mod 檔案後,它會建立命令列中指定的套件。可執行檔會安裝在 GOBIN 環境變數指定的目錄中,如果未設定 GOPATH 環境變數,預設為 $GOPATH/bin$HOME/go/bin

go get 支援下列旗標

自 Go 1.16 起,go install 是建議用於建立和安裝程式碼的指令。當與版本字尾(例如 @latest@v1.4.6)一起使用時,go install 會以模組感知模式建立套件,忽略目前目錄或任何父目錄(如果有)中的 go.mod 檔案。

go get 更專注於管理 go.mod 中的要求。-d 旗標已棄用,且在 Go 1.18 中,它將永遠啟用。

go install

用法

go install [build flags] [packages]

範例

# Install the latest version of a program,
# ignoring go.mod in the current directory (if any).
$ go install golang.org/x/tools/gopls@latest

# Install a specific version of a program.
$ go install golang.org/x/tools/gopls@v0.6.4

# Install a program at the version selected by the module in the current directory.
$ go install golang.org/x/tools/gopls

# Install all programs in a directory.
$ go install ./cmd/...

go install 指令會建立並安裝指令列上路徑所指定的套件。可執行檔(main 套件)會安裝到 GOBIN 環境變數指定的目錄,如果未設定 GOPATH 環境變數,則預設為 $GOPATH/bin$HOME/go/bin$GOROOT 中的可執行檔會安裝到 $GOROOT/bin$GOTOOLDIR,而不是 $GOBIN。非可執行檔套件會建立並快取,但不會安裝。

自 Go 1.16 起,如果引數有版本字尾(例如 @latest@v1.0.0),go install 會以模組感知模式建立套件,忽略目前目錄或任何父目錄(如果有)中的 go.mod 檔案。這對於安裝可執行檔而不影響主模組的相依性很有用。

為了消除對建立中使用的模組版本造成混淆,引數必須符合下列限制

請參閱 版本查詢 以取得支援的版本查詢語法。Go 1.15 及更早版本不支援在 go install 中使用版本查詢。

如果參數沒有版本字尾,go install 可能會在模組感知模式或 GOPATH 模式中執行,具體取決於 GO111MODULE 環境變數和 go.mod 檔案的存在。請參閱 模組感知指令 以取得詳細資訊。如果啟用模組感知模式,go install 會在主模組的內容中執行,這可能與包含要安裝套件的模組不同。

go list -m

用法

go list -m [-u] [-retracted] [-versions] [list flags] [modules]

範例

$ go list -m all
$ go list -m -versions example.com/m
$ go list -m -json example.com/m@latest

-m 旗標會導致 go list 列出模組而不是套件。在此模式中,go list 的參數可以是模組、模組模式(包含 ... 萬用字元)、版本查詢 或特殊模式 all,它會比對 建置清單 中的所有模組。如果未指定任何參數,則會列出 主模組

列出模組時,-f 旗標仍會指定套用至 Go 結構的格式範本,但現在是 Module 結構

type Module struct {
    Path       string        // module path
    Version    string        // module version
    Versions   []string      // available module versions
    Replace    *Module       // replaced by this module
    Time       *time.Time    // time version was created
    Update     *Module       // available update (with -u)
    Main       bool          // is this the main module?
    Indirect   bool          // module is only indirectly needed by main module
    Dir        string        // directory holding local copy of files, if any
    GoMod      string        // path to go.mod file describing module, if any
    GoVersion  string        // go version used in module
    Retracted  []string      // retraction information, if any (with -retracted or -u)
    Deprecated string        // deprecation message, if any (with -u)
    Error      *ModuleError  // error loading module
}

type ModuleError struct {
    Err string // the error itself
}

預設輸出會列印模組路徑,然後是關於版本和替換的資訊(如果有的話)。例如,go list -m all 可能會列印

example.com/main/module
golang.org/x/net v0.1.0
golang.org/x/text v0.3.0 => /tmp/text
rsc.io/pdf v0.1.1

Module 結構有一個 String 方法,用於格式化這行輸出,因此預設格式等於 -f '{{.String}}'

請注意,當模組已被替換時,其 Replace 欄位會描述替換模組,而其 Dir 欄位會設定為替換模組的原始程式碼(如果存在)。(也就是說,如果 Replace 為非 nil,則 Dir 會設定為 Replace.Dir,無法存取已替換的原始程式碼。)

-u 旗標會新增關於可用升級的資訊。當給定模組的最新版本比目前版本新時,list -u 會將模組的 Update 欄位設定為關於較新模組的資訊。list -u 也會列印目前選取的版本是否已 撤回,以及模組是否已 標示為不建議使用。模組的 String 方法會透過在目前版本後以括號格式化較新版本,來指出可用的升級。例如,go list -m -u all 可能會列印

example.com/main/module
golang.org/x/old v1.9.9 (deprecated)
golang.org/x/net v0.1.0 (retracted) [v0.2.0]
golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
rsc.io/pdf v0.1.1 [v0.1.2]

(對於工具而言,go list -m -u -json all 可能較容易解析。)

-versions 旗標會導致 list 將模組的 Versions 欄位設定為該模組所有已知版本的清單,並根據語意版本控管從最低到最高排序。此旗標也會變更預設輸出格式,以顯示模組路徑,後接以空格分隔的版本清單。除非同時指定 -retracted 旗標,否則會從此清單中省略已撤回的版本。

-retracted 旗標指示 list 在使用 -versions 旗標列印的清單中顯示已撤回的版本,並在解析 版本查詢 時考量已撤回的版本。例如,go list -m -retracted example.com/m@latest 會顯示模組 example.com/m 的最高發行版本或預發行版本,即使該版本已撤回。 retract 指令不建議使用 會從此版本的 go.mod 檔案載入。-retracted 旗標已新增至 Go 1.16。

範本函數 module 會接收一個字串引數,該引數必須是模組路徑或查詢,並會傳回指定的模組作為 Module 結構。如果發生錯誤,結果將會是 Error 欄位為非 nil 的 Module 結構。

go mod download

用法

go mod download [-x] [-json] [-reuse=old.json] [modules]

範例

$ go mod download
$ go mod download golang.org/x/mod@v0.2.0

go mod download 指令會將指定的模組下載至 模組快取。引數可以是模組路徑或模組模式,用於選取主模組的相依項或 path@version 格式的 版本查詢。如果沒有引數,download 會套用至 主模組 的所有相依項。

go 指令會在一般執行期間根據需要自動下載模組。go mod download 指令主要用於預先填入模組快取或載入資料以供 模組代理 服務。

預設情況下,download 什麼都不會寫入標準輸出。它會將進度訊息和錯誤列印至標準錯誤。

-json 旗標會導致 download 將 JSON 物件的順序列印至標準輸出,說明每個已下載的模組 (或失敗),對應至這個 Go 結構

type Module struct {
    Path     string // module path
    Query    string // version query corresponding to this version
    Version  string // module version
    Error    string // error loading module
    Info     string // absolute path to cached .info file
    GoMod    string // absolute path to cached .mod file
    Zip      string // absolute path to cached .zip file
    Dir      string // absolute path to cached source root directory
    Sum      string // checksum for path, version (as in go.sum)
    GoModSum string // checksum for go.mod (as in go.sum)
    Origin   any    // provenance of module
    Reuse    bool   // reuse of old module info is safe
}

-x 旗標會導致 downloaddownload 執行的指令列印到標準錯誤。

-reuse 旗標會接受包含先前「go mod download -json」呼叫的 JSON 輸出的檔案名稱。go 指令可能會使用這個檔案來判斷模組自上次呼叫以來是否未變更,並避免重新下載它。未重新下載的模組會在新的輸出中標記,方法是將 Reuse 欄位設為 true。通常模組快取會自動提供這種重複使用;在未保留模組快取的系統上,-reuse 旗標會很有用。

go mod edit

用法

go mod edit [editing flags] [-fmt|-print|-json] [go.mod]

範例

# Add a replace directive.
$ go mod edit -replace example.com/a@v1.0.0=./a

# Remove a replace directive.
$ go mod edit -dropreplace example.com/a@v1.0.0

# Set the go version, add a requirement, and print the file
# instead of writing it to disk.
$ go mod edit -go=1.14 -require=example.com/m@v1.0.0 -print

# Format the go.mod file.
$ go mod edit -fmt

# Format and print a different .mod file.
$ go mod edit -print tools.mod

# Print a JSON representation of the go.mod file.
$ go mod edit -json

go mod edit 指令提供一個指令列介面,用於編輯和格式化 go.mod 檔案,主要供工具和腳本使用。go mod edit 只讀取一個 go.mod 檔案;它不會查詢其他模組的資訊。預設情況下,go mod edit 會讀取和寫入主模組的 go.mod 檔案,但可以在編輯旗標後指定不同的目標檔案。

編輯旗標會指定一系列編輯作業。

編輯旗標可以重複。變更會按給定的順序套用。

go mod edit 有其他控制其輸出的旗標。

type Module struct {
    Path    string
    Version string
}

type GoMod struct {
    Module  ModPath
    Go      string
    Require []Require
    Exclude []Module
    Replace []Replace
    Retract []Retract
}

type ModPath struct {
    Path       string
    Deprecated string
}

type Require struct {
    Path     string
    Version  string
    Indirect bool
}

type Replace struct {
    Old Module
    New Module
}

type Retract struct {
    Low       string
    High      string
    Rationale string
}

請注意,這只描述 go.mod 檔案本身,而不是間接參照的其他模組。如需建置可用的完整模組集,請使用 go list -m -json all。請參閱 go list -m

例如,工具可以透過剖析 go mod edit -json 的輸出,取得 go.mod 檔案作為資料結構,然後可以透過使用 -require-exclude 等參數呼叫 go mod edit 來進行變更。

工具也可以使用套件 golang.org/x/mod/modfile 來剖析、編輯和格式化 go.mod 檔案。

go mod graph

用法

go mod graph [-go=version]

go mod graph 指令會以文字格式列印 模組需求圖(套用替換)。例如

example.com/main example.com/a@v1.1.0
example.com/main example.com/b@v1.2.0
example.com/a@v1.1.0 example.com/b@v1.1.1
example.com/a@v1.1.0 example.com/c@v1.3.0
example.com/b@v1.1.0 example.com/c@v1.1.0
example.com/b@v1.2.0 example.com/c@v1.2.0

模組圖中的每個頂點代表模組的特定版本。圖中的每條邊代表對依賴項最小版本的需求。

go mod graph 會列印圖的邊,每行一條。每行有兩個以空白分隔的欄位:模組版本及其依賴項之一。每個模組版本都識別為 path@version 格式的字串。主模組沒有 @version 字尾,因為它沒有版本。

-go 旗標會導致 go mod graph 報告由指定的 Go 版本載入的模組圖,而不是 go.mod 檔案中的 go 指令 指出的版本。

請參閱 最小版本選取 (MVS),以取得關於如何選取版本的詳細資訊。另請參閱 go list -m 以列印選取的版本,以及 go mod why 以了解為何需要模組。

go mod init

用法

go mod init [module-path]

範例

go mod init
go mod init example.com/m

go mod init 指令會初始化並撰寫新的 go.mod 檔案至目前目錄,實際上會在目前目錄建立根目錄的新模組。go.mod 檔案不能已經存在。

init 接受一個選用引數,即新模組的 模組路徑。請參閱 模組路徑 以取得關於如何選取模組路徑的說明。如果省略模組路徑引數,init 會嘗試使用 .go 檔案中的匯入註解、供應工具組態檔案和目前目錄(如果在 GOPATH 中)來推斷模組路徑。

如果供應工具的組態檔案存在,init 會嘗試從中匯入模組需求。init 支援下列組態檔案。

供應工具組態檔案無法總是能以完美的保真度轉換。例如,如果同一個存放庫中的多個套件以不同的版本匯入,而存放庫只包含一個模組,匯入的 go.mod 只能在一個版本中要求模組。您可能想要執行 go list -m all 來檢查 建置清單 中的所有版本,以及 go mod tidy 來新增遺失的要求並移除未使用的要求。

go mod tidy

用法

go mod tidy [-e] [-v] [-go=version] [-compat=version]

go mod tidy 可確保 go.mod 檔案與模組中的原始碼相符。它會新增任何遺失的模組需求,以建置目前的模組套件和相依性,並移除未提供任何相關套件的模組需求。它也會新增任何遺失的項目至 go.sum,並移除不必要的項目。

-e 旗標(新增於 Go 1.16)會讓 go mod tidy 嘗試繼續進行,即使在載入套件時遇到錯誤。

-v 旗標會讓 go mod tidy 將已移除模組的資訊印出至標準錯誤。

go mod tidy 的運作方式是載入 主模組 中的所有套件,以及所有它們匯入的套件(遞迴)。這包含測試匯入的套件(包括其他模組中的測試)。go mod tidy 的行為就像所有建置標記都已啟用,因此它會考慮特定平台的原始檔和需要自訂建置標記的檔案,即使那些原始檔通常不會被建置。有一個例外:ignore 建置標記並未啟用,因此具有建置限制 // +build ignore 的檔案不會被考慮。請注意,go mod tidy 對於主模組中命名為 testdata 的目錄,或名稱以 ._ 開頭的套件不會考慮,除非這些套件是由其他套件明確匯入。

一旦 go mod tidy 載入這組套件,它會確保提供一個或多個套件的每個模組在主模組的 go.mod 檔案中都有 require 指令,或者 — 如果主模組在 go 1.16 或以下版本 — 由另一個必要的模組所需要。go mod tidy 會在每個遺失模組的最新版本上新增一個需求(請參閱 版本查詢 以取得 latest 版本的定義)。go mod tidy 會移除在上述所述組中未提供任何套件的模組的 require 指令。

go mod tidy 也可能會在 require 指令上新增或移除 // indirect 註解。// indirect 註解表示一個模組,它未提供主模組中套件所匯入的套件。(請參閱 require 指令 以取得更多詳細資料,說明何時會新增 // indirect 相依關係和註解。)

如果設定 -go 旗標,go mod tidy 會將 go 指令 更新為所指示的版本,根據該版本啟用或停用 模組圖表修剪延遲載入模組(並視需要新增或移除間接需求)。

預設情況下,go mod tidy 會檢查模組的 已選版本 在由 go 指令中所指示版本緊接在前的 Go 版本載入模組圖表時不會變更。也可以透過 -compat 旗標明確指定已檢查相容性的版本。

go mod vendor

用法

go mod vendor [-e] [-v] [-o]

go mod vendor 指令會在 主模組 的根目錄中建構一個名為 vendor 的目錄,其中包含支援主模組中套件的建構和測試所需的所有套件副本。僅由主模組外部套件的測試匯入的套件不會包含在內。與 go mod tidy 和其他模組指令一樣,建構 vendor 目錄時不會考慮 建構約束,但 ignore 除外。

當啟用供應商時,go 指令會從 vendor 目錄載入套件,而不是從其來源下載模組到模組快取並使用那些下載副本的套件。請參閱 供應商 以取得更多資訊。

go mod vendor 也會建立 vendor/modules.txt 檔案,其中包含供應商套件和複製來源的模組版本的清單。當啟用供應商時,此清單會用作模組版本資訊的來源,如 go list -mgo version -m 所報告。當 go 指令讀取 vendor/modules.txt 時,它會檢查模組版本是否與 go.mod 一致。如果在產生 vendor/modules.txt 之後 go.mod 已變更,則應再次執行 go mod vendor

請注意,go mod vendor 會在重新建構 vendor 目錄之前移除它(如果它存在)。不應對供應商套件進行本機變更。go 指令不會檢查 vendor 目錄中的套件是否未經修改,但可以透過執行 go mod vendor 並檢查是否未進行任何變更來驗證 vendor 目錄的完整性。

-e 旗標(在 Go 1.16 中新增)會導致 go mod vendor 嘗試在載入套件時遇到錯誤時繼續進行。

-v 旗標會導致 go mod vendor 將已供應的模組和套件的名稱列印至標準錯誤。

-o 旗標(在 Go 1.18 中新增)會導致 go mod vendor 在指定的目錄中輸出供應樹,而不是 vendor。參數可以是絕對路徑或相對於模組根目錄的路徑。

go mod verify

用法

go mod verify

go mod verify 會檢查儲存在 模組快取 中的 主模組 的相依性自下載後是否未經修改。若要執行此檢查,go mod verify 會對每個已下載的模組 .zip 檔案 和已解壓縮的目錄進行雜湊,然後將這些雜湊與模組首次下載時所記錄的雜湊進行比較。go mod verify 會檢查 建置清單 中的每個模組(可以使用 go list -m all 列印)。

如果所有模組都未修改,go mod verify 會列印「已驗證所有模組」。否則,它會報告哪些模組已變更,並退出並顯示非零狀態。

請注意,所有模組感知命令都會驗證主模組的 go.sum 檔案中的雜湊是否與為下載至模組快取的模組所記錄的雜湊相符。如果 go.sum 中缺少雜湊(例如,因為模組是第一次使用),go 命令會使用 雜湊資料庫 驗證其雜湊(除非模組路徑與 GOPRIVATEGONOSUMDB 相符)。有關詳細資訊,請參閱 驗證模組

相比之下,go mod verify 檢查模組 .zip 檔案及其解壓目錄的雜湊值是否與首次下載時記錄在模組快取中的雜湊值相符。這對於在模組下載並驗證之後偵測模組快取中檔案的變更很有用。go mod verify 沒有下載快取中沒有的模組內容,而且它不會使用 go.sum 檔案來驗證模組內容。不過,go mod verify 可能會下載 go.mod 檔案,以執行最小版本選取。它會使用 go.sum 來驗證這些檔案,而且它可能會新增遺失雜湊值的 go.sum 項目。

go mod why

用法

go mod why [-m] [-vendor] packages...

go mod why 會顯示從主模組到每個已列出套件的匯入圖形中的最短路徑。

輸出是一連串小節,每個小節對應命令列中指定的一個套件或模組,並以空白行分隔。每個小節都以一個從 # 開始的註解行開頭,提供目標套件或模組。後續行會提供匯入圖形中的路徑,每行一個套件。如果套件或模組未從主模組中參照,小節會顯示一個括號備註,指出這個事實。

例如

$ go mod why golang.org/x/text/language golang.org/x/text/encoding
# golang.org/x/text/language
rsc.io/quote
rsc.io/sampler
golang.org/x/text/language

# golang.org/x/text/encoding
(main module does not need package golang.org/x/text/encoding)

-m 旗標會導致 go mod why 將其參數視為模組清單。go mod why 會列印路徑到每個模組中的任何套件。請注意,即使使用了 -mgo mod why 查詢的也是套件圖形,而不是 go mod graph 列印的模組圖形。

-vendor 旗標會導致 go mod why 忽略主模組外部套件測試中的匯入(如同 go mod vendor 所做)。預設情況下,go mod why 會考慮與 all 模式相符的套件圖。在宣告 go 1.16 或更高版本(使用 go.mod 中的 go 指令)的模組中,此旗標在 Go 1.16 之後不會產生任何效果,因為 all 的意義已變更,以符合 go mod vendor 所符合的套件組。

go version -m

用法

go version [-m] [-v] [file ...]

範例

# Print Go version used to build go.
$ go version

# Print Go version used to build a specific executable.
$ go version ~/go/bin/gopls

# Print Go version and module versions used to build a specific executable.
$ go version -m ~/go/bin/gopls

# Print Go version and module versions used to build executables in a directory.
$ go version -m ~/go/bin/

go version 會回報用於建置命令列上所列每個可執行檔的 Go 版本。

如果命令列上未列出任何檔案,go version 會列印其自己的版本資訊。

如果列出一個目錄,go version 會遞迴瀏覽該目錄,尋找已識別的 Go 二進位檔並回報其版本。預設情況下,go version 不會回報在目錄掃描期間找到的未識別檔案。-v 旗標會讓它回報未識別的檔案。

-m 旗標會讓 go version 列印每個可執行檔的嵌入式模組版本資訊(如果有的話)。對於每個可執行檔,go version -m 會列印一個表格,其中包含以 tab 分隔的欄位,如下所示。

$ go version -m ~/go/bin/goimports
/home/jrgopher/go/bin/goimports: go1.14.3
        path    golang.org/x/tools/cmd/goimports
        mod     golang.org/x/tools      v0.0.0-20200518203908-8018eb2c26ba      h1:0Lcy64USfQQL6GAJma8BdHCgeofcchQj+Z7j0SXYAzU=
        dep     golang.org/x/mod        v0.2.0          h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
        dep     golang.org/x/xerrors    v0.0.0-20191204190536-9bdfabe68543      h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

表格的格式未來可能會變更。相同的資訊可以從 runtime/debug.ReadBuildInfo 取得。

表格中每一列的意義是由第一欄中的字詞決定的。

go clean -modcache

用法

go clean [-modcache]

-modcache 旗標會導致 go clean 移掉整個 模組快取,包括版本化依賴項的未封裝原始碼。

這通常是移除模組快取的最佳方式。預設情況下,模組快取中的大多數檔案和目錄都是唯讀的,以防止測試和編輯器在檔案 驗證 後意外變更檔案。很不幸地,這會導致像 rm -r 這樣的指令失敗,因為在讓它們的父目錄可寫入之前無法移除檔案。

-modcacherw 旗標(go build 和其他支援模組的指令接受)會讓模組快取中的新目錄可寫入。若要將 -modcacherw 傳遞給所有支援模組的指令,請將它新增到 GOFLAGS 變數。GOFLAGS 可以設定在環境中或使用 go env -w。例如,以下指令會永久設定它

go env -w GOFLAGS=-modcacherw

-modcacherw 應謹慎使用;開發人員應小心不要變更模組快取中的檔案。go mod verify 可用於檢查快取中的檔案是否與主模組的 go.sum 檔案中的雜湊值相符。

版本查詢

多個指令允許您使用 版本查詢來指定模組的版本,版本查詢會出現在指令列中模組或套件路徑後的 @ 字元之後。

範例

go get example.com/m@latest
go mod download example.com/m@master
go list -m -json example.com/m@e3702bed2

版本查詢可以是下列其中一項

除了特定命名版本或修訂版本的查詢外,所有查詢都考慮 go list -m -versions 報告的可用版本(請參閱 go list -m)。此清單僅包含標記版本,不包含偽版本。主模組的 go.mod 檔案exclude 指令 所禁止的模組版本不會被考慮。go.mod 檔案中來自相同模組的 latest 版本的 retract 指令 所涵蓋的版本也會被忽略,除非在 go list -m 中使用 -retracted 旗標,以及載入 retract 指令時除外。

發行版本 優先於預發行版本。例如,如果版本 v1.2.2v1.2.3-pre 可用,latest 查詢將選取 v1.2.2,即使 v1.2.3-pre 較高。<v1.2.4 查詢也會選取 v1.2.2,即使 v1.2.3-pre 較接近 v1.2.4。如果沒有可用的發行版本或預發行版本,latestupgradepatch 查詢將選取儲存庫預設分支頂端的提交的偽版本。其他查詢將報告錯誤。

模組外的模組指令

具模組感知功能的 Go 指令通常會在由工作目錄或父目錄中的 go.mod 檔案定義的 主模組 的背景下執行。有些指令可以在沒有 go.mod 檔案的情況下以具模組感知功能的模式執行,但大多數指令在沒有 go.mod 檔案時會以不同的方式運作或回報錯誤。

請參閱 具模組感知功能的指令 以取得關於啟用和停用具模組感知功能模式的資訊。

指令 行為
go build
go doc
go fix
go fmt
go generate
go install
go list
go run
go test
go vet
只有標準函式庫中的套件和在指令列上指定為 .go 檔案的套件才能載入、匯入和建置。無法建置來自其他模組的套件,因為沒有地方可以記錄模組需求並確保確定性的建置。
go get 套件和可執行檔可以像平常一樣建置和安裝。請注意,在沒有 go.mod 檔案的情況下執行 go get 時沒有主模組,因此不會套用 replaceexclude 指令。
go list -m 大多數引數都需要明確的 版本查詢,除非使用 -versions 旗標。
go mod download 大多數引數都需要明確的 版本查詢
go mod edit 需要明確的檔案引數。
go mod graph
go mod tidy
go mod vendor
go mod verify
go mod why
這些指令需要 go.mod 檔案,如果沒有,將回報錯誤。

go work init

用法

go work init [moddirs]

Init 會初始化並在目前目錄中寫入新的 go.work 檔案,實際上會在目前目錄中建立新的工作空間。

go work init 選擇性地接受工作空間模組的路徑作為引數。如果省略引數,將建立沒有模組的空工作空間。

每個參數路徑都會新增到 go.work 檔案中的使用指令。目前的 go 版本也會列在 go.work 檔案中。

go work edit

用法

go work edit [editing flags] [go.work]

go work edit 指令提供用於編輯 go.work 的命令列介面,主要由工具或指令碼使用。它只會讀取 go.work;它不會查詢所涉模組的資訊。如果未指定任何檔案,編輯會在目前目錄及其父目錄中尋找 go.work 檔案

編輯旗標會指定一系列編輯作業。

編輯旗標可以重複。變更會按給定的順序套用。

go work edit 有其他旗標來控制其輸出

type Module struct {
    Path    string
    Version string
}

type GoWork struct {
    Go        string
    Directory []Directory
    Replace   []Replace
}

type Use struct {
    Path       string
    ModulePath string
}

type Replace struct {
    Old Module
    New Module
}

go work use

用法

go work use [-r] [moddirs]

go work use 指令提供一個命令列介面,用於將目錄(選擇性地遞迴)新增到 go.work 檔案。

對於命令列上列出的每個參數目錄,如果它存在於磁碟上,將會新增一個 use 指令go.work 檔案中;如果它不存在於磁碟上,則會從 go.work 檔案中移除。

-r 旗標會在參數目錄中遞迴搜尋模組,而 use 指令會像每個目錄都指定為參數一樣運作:也就是說,對於存在的目錄會新增 use 指令,而對於不存在的目錄會移除。

go work sync

用法

go work sync

go work sync 指令會將工作區的建置清單同步回工作區的模組。

工作區的建置清單是所有(傳遞)相依模組版本集合,這些模組用於在工作區中進行建置。go work sync 使用 最小版本選擇 (MVS) 演算法產生該建置清單,然後將這些版本同步回工作區中指定的每個模組(使用 use 指令)。

在計算出工作區建置清單後,會重新撰寫工作區中每個模組的 go.mod 檔案,將與該模組相關的相依項升級為與工作區建置清單相符。請注意,最小版本選擇 保證建置清單中每個模組的版本始終與每個工作區模組中的版本相同或更高。

模組代理

GOPROXY 協定

模組代理 是一個 HTTP 伺服器,可以回應以下路徑的 GET 要求。這些要求沒有查詢參數,也不需要特定的標頭,因此,即使從固定檔案系統(包括 file:// URL)提供服務的網站也可以是模組代理。

成功的 HTTP 回應必須有狀態碼 200(確定)。將會遵循重新導向(3xx)。狀態碼為 4xx 和 5xx 的回應會被視為錯誤。錯誤碼 404(找不到)和 410(已移除)表示請求的模組或版本在代理中不可用,但可能可以在其他地方找到。錯誤回應應具有內容類型 text/plaincharsetutf-8us-ascii

go 指令可設定為使用 GOPROXY 環境變數連繫代理伺服器或原始碼控制伺服器,此變數會接受代理伺服器 URL 清單。清單中可包含關鍵字 directoff(詳細資訊請參閱 環境變數)。清單元素可使用逗號 (,) 或直線 (|) 分隔,這會決定錯誤回退行為。當 URL 後面接逗號時,go 指令僅在收到 404(找不到)或 410(已移除)回應後才會回退至後續來源。當 URL 後面接直線時,go 指令會在發生任何錯誤(包括非 HTTP 錯誤,例如逾時)後回退至後續來源。這種錯誤處理行為讓代理伺服器可以作為未知模組的守門員。例如,代理伺服器可以對未列在核准清單中的模組回應 403(禁止)錯誤(請參閱 提供私人模組的私人代理伺服器)。

下表指定模組代理伺服器必須回應的查詢。對於每個路徑,$base 是代理伺服器 URL 的路徑部分,$module 是模組路徑,而 $version 是版本。例如,如果代理伺服器 URL 是 https://example.com/mod,而客戶端正在要求版本為 v0.3.2 的模組 golang.org/x/textgo.mod 檔案,則客戶端會傳送 GET 要求給 https://example.com/mod/golang.org/x/text/@v/v0.3.2.mod

為避免在提供服務時,因不區分大小寫的檔案系統而產生歧義,$module$version 元素會以大小寫編碼方式進行編碼,方法是將每個大寫字母替換為驚嘆號,後接對應的小寫字母。這允許模組 example.com/Mexample.com/m 都儲存在磁碟上,因為前者編碼為 example.com/!m

路徑 說明
$base/$module/@v/list 傳回給定模組已知版本清單,以純文字表示,每行一個版本。此清單不應包含偽版本。
$base/$module/@v/$version.info

傳回模組特定版本的 JSON 格式化元資料。回應必須是 JSON 物件,對應於下列 Go 資料結構

type Info struct {
    Version string    // version string
    Time    time.Time // commit time
}

Version 欄位為必填,且必須包含有效的 正規版本(請參閱 版本)。請求路徑中的 $version 不需要是相同版本,甚至不需要是有效版本;此端點可用於尋找分支名稱或修訂識別碼的版本。但是,如果 $version 是主要版本與 $module 相容的正規版本,則成功回應中的 Version 欄位必須相同。

Time 欄位為選填。如果存在,則必須是 RFC 3339 格式的字串。它表示建立版本的時間。

未來可能會新增更多欄位,因此保留其他名稱。

$base/$module/@v/$version.mod 傳回模組特定版本的 go.mod 檔案。如果模組在請求的版本中沒有 go.mod 檔案,則必須傳回只包含具有請求模組路徑的 module 陳述式的檔案。否則,必須傳回原始、未修改的 go.mod 檔案。
$base/$module/@v/$version.zip 傳回包含模組特定版本內容的 zip 檔案。請參閱 模組 zip 檔案,了解此 zip 檔案的格式化方式詳細資料。
$base/$module/@latest 傳回模組最新已知版本的 JSON 格式化元資料,格式與 $base/$module/@v/$version.info 相同。如果 $base/$module/@v/list 為空或沒有適當的版本列出,最新版本應為 go 指令應使用的模組版本。此端點為選用,且模組代理程式不需要實作它。

在解析模組的最新版本時,go 指令會要求 $base/$module/@v/list,然後,如果找不到適當的版本,會要求 $base/$module/@latestgo 指令偏好順序為:語意最高的發行版本、語意最高的預發行版本,以及時間順序最新的偽版本。在 Go 1.12 及更早版本中,go 指令會將 $base/$module/@v/list 中的偽版本視為預發行版本,但從 Go 1.13 開始不再如此。

模組代理程式必須始終提供相同內容,以針對 $base/$module/$version.mod$base/$module/$version.zip 查詢提供成功的回應。此內容使用 加密驗證,方法是使用 go.sum 檔案,而且預設會使用 雜湊資料庫

go 指令會將它從模組代理程式下載的大部分內容快取在 $GOPATH/pkg/mod/cache/download 中的模組快取中。即使直接從版本控制系統下載,go 指令也會綜合明確的 infomodzip 檔案,並將它們儲存在此目錄中,就像直接從代理程式下載一樣。快取配置與代理程式 URL 空間相同,因此在 (或將其複製到) https://example.com/proxy 中提供 $GOPATH/pkg/mod/cache/download 會讓使用者能夠透過將 GOPROXY 設定為 https://example.com/proxy 來存取快取的模組版本。

與代理程式通訊

go 指令可能會從 模組代理 下載模組原始碼和元資料。GOPROXY 環境變數 可用於設定 go 指令可以連線的代理,以及是否可以與 版本控制系統 直接通訊。已下載的模組資料會儲存在 模組快取 中。go 指令只會在需要快取中沒有的資訊時,才會連線代理。

GOPROXY 通訊協定 部分說明了可以傳送至 GOPROXY 伺服器的要求。不過,了解 go 指令何時提出這些要求也很有幫助。例如,go build 會遵循以下程序

go 指令計算建置清單時,它會載入 模組圖 中每個模組的 go.mod 檔案。如果 go.mod 檔案不在快取中,go 指令會使用 $module/@v/$version.mod 要求(其中 $module 是模組路徑,而 $version 是版本)從代理下載檔案。這些要求可以使用類似 curl 的工具進行測試。例如,以下指令會下載 golang.org/x/mod 在版本 v0.2.0 中的 go.mod 檔案

$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.mod
module golang.org/x/mod

go 1.12

require (
    golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
    golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
    golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
)

為了載入套件,go 指令需要提供該套件的模組的原始碼。模組原始碼會分發在 .zip 檔案中,這些檔案會解壓縮到模組快取中。如果模組 .zip 不在快取中,go 指令會使用 $module/@v/$version.zip 要求下載檔案。

$ curl -O https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.zip
$ unzip -l v0.2.0.zip | head
Archive:  v0.2.0.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
     1479  00-00-1980 00:00   golang.org/x/mod@v0.2.0/LICENSE
     1303  00-00-1980 00:00   golang.org/x/mod@v0.2.0/PATENTS
      559  00-00-1980 00:00   golang.org/x/mod@v0.2.0/README
       21  00-00-1980 00:00   golang.org/x/mod@v0.2.0/codereview.cfg
      214  00-00-1980 00:00   golang.org/x/mod@v0.2.0/go.mod
     1476  00-00-1980 00:00   golang.org/x/mod@v0.2.0/go.sum
     5224  00-00-1980 00:00   golang.org/x/mod@v0.2.0/gosumcheck/main.go

請注意,.mod.zip 要求是分開的,即使 go.mod 檔案通常包含在 .zip 檔案中。go 指令可能需要為許多不同的模組下載 go.mod 檔案,而 .mod 檔案比 .zip 檔案小很多。此外,如果 Go 專案沒有 go.mod 檔案,代理程式會提供一個僅包含 module 指令 的合成 go.mod 檔案。合成 go.mod 檔案是由 go 指令在從 版本控制系統 下載時產生的。

如果 go 指令需要載入建置清單中任何模組未提供的套件,它會嘗試尋找提供該套件的新模組。將套件解析為模組 一節說明此程序。總之,go 指令會要求提供可能包含該套件的每個模組路徑的最新版本資訊。例如,對於套件 golang.org/x/net/htmlgo 指令會嘗試尋找模組 golang.org/x/net/htmlgolang.org/x/netgolang.org/x/golang.org 的最新版本。實際上只有 golang.org/x/net 存在且提供該套件,因此 go 指令會使用該模組的最新版本。如果有多個模組提供該套件,go 指令會使用路徑最長的模組。

go 指令要求模組的最新版本時,它會先傳送 $module/@v/list 的要求。如果清單是空的,或沒有任何傳回的版本可以使用,它會傳送 $module/@latest 的要求。選取版本後,go 指令會傳送 $module/@v/$version.info 要求以取得元資料。然後它可能會傳送 $module/@v/$version.mod$module/@v/$version.zip 要求以載入 go.mod 檔案和原始碼。

$ curl https://proxy.golang.org/golang.org/x/mod/@v/list
v0.1.0
v0.2.0

$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.info
{"Version":"v0.2.0","Time":"2020-01-02T17:33:45Z"}

下載 .mod.zip 檔案後,go 指令會計算加密雜湊,並檢查它是否與主模組的 go.sum 檔案中的雜湊相符。如果 go.sum 中沒有雜湊,預設情況下,go 指令會從 雜湊資料庫 中擷取它。如果計算出的雜湊不符,go 指令會報告安全性錯誤,且不會在模組快取中安裝檔案。GOPRIVATEGONOSUMDB 環境變數 可用於停用特定模組的雜湊資料庫要求。GOSUMDB 環境變數也可以設定為 off 以完全停用雜湊資料庫要求。有關更多資訊,請參閱 驗證模組。請注意,為 .info 要求傳回的版本清單和版本元資料未經驗證,且可能會隨著時間而改變。

直接從代理伺服器提供模組

大多數模組都是從版本控制儲存庫開發和提供的。在 直接模式 中,go 指令會使用版本控制工具下載此類模組(請參閱 版本控制系統)。也可以直接從模組代理伺服器提供模組。這對於想要提供模組而不公開其版本控制伺服器的組織,以及使用 go 指令不支援的版本控制工具的組織很有用。

go 指令在直接模式下載模組時,它會先根據模組路徑使用 HTTP GET 要求查詢模組伺服器的 URL。它會在 HTML 回應中尋找名稱為 go-import<meta> 標籤。標籤的內容必須包含 儲存庫根路徑、版本控制系統和 URL,並以空格分隔。有關詳細資訊,請參閱 尋找模組路徑的儲存庫

如果版本控制系統是 modgo 指令會使用 GOPROXY 協定 從指定的 URL 下載模組。

例如,假設 go 指令嘗試下載模組 example.com/gopher 的版本 v1.0.0。它會傳送要求至 https://example.com/gopher?go-get=1。伺服器會回應包含標籤的 HTML 文件

<meta name="go-import" content="example.com/gopher mod https://modproxy.example.com">

根據這個回應,go 指令會透過傳送要求至 https://modproxy.example.com/example.com/gopher/@v/v1.0.0.infov1.0.0.modv1.0.0.zip 來下載模組。

請注意,直接從代理伺服器提供的模組無法在 GOPATH 模式中使用 go get 下載。

版本控制系統

go 指令可以直接從版本控制儲存庫下載模組原始碼和元資料。通常從 代理伺服器 下載模組較快,但如果沒有代理伺服器,或如果代理伺服器無法存取模組的儲存庫(私人儲存庫經常如此),則必須直接連線至儲存庫。支援 Git、Subversion、Mercurial、Bazaar 和 Fossil。版本控制工具必須安裝在 PATH 中的目錄中,go 指令才能使用它。

若要從原始碼儲存庫而非代理伺服器下載特定模組,請設定 GOPRIVATEGONOPROXY 環境變數。若要設定 go 指令直接從原始碼儲存庫下載所有模組,請將 GOPROXY 設定為 direct。如需更多資訊,請參閱 環境變數

尋找模組路徑的儲存庫

go 指令在 direct 模式下載模組時,它會從尋找包含模組的儲存庫開始。

如果模組路徑在路徑組件的結尾處具有 VCS 限定詞(.bzr.fossil.git.hg.svn 之一),go 指令會將該路徑限定詞之前的所有內容用作儲存庫 URL。例如,對於模組 example.com/foo.git/bargo 指令會使用 git 下載 example.com/foo.git 處的儲存庫,並預期在 bar 子目錄中找到模組。go 指令會根據版本控制工具支援的協定來猜測要使用的協定。

如果模組路徑沒有限定詞,go 指令會將 HTTP GET 要求傳送至從模組路徑衍生的 URL,並加上 ?go-get=1 查詢字串。例如,對於模組 golang.org/x/modgo 指令可能會傳送下列要求

https://go.dev.org.tw/x/mod?go-get=1 (preferred)
https://go.dev.org.tw/x/mod?go-get=1  (fallback, only with GOINSECURE)

go 指令會遵循重新導向,但會忽略回應狀態碼,因此伺服器可能會回應 404 或任何其他錯誤狀態。可以設定 GOINSECURE 環境變數,以允許特定模組回退和重新導向至未加密的 HTTP。

伺服器必須回應包含 <meta> 標籤的 HTML 文件,該標籤位於文件的 <head> 中。<meta> 標籤應出現在文件開頭,以避免混淆 go 指令的受限剖析器。特別是,它應出現在任何原始 JavaScript 或 CSS 之前。<meta> 標籤必須具有下列格式

<meta name="go-import" content="root-path vcs repo-url">

root-path 是儲存庫根路徑,即模組路徑中對應於儲存庫根目錄的部分。它必須是要求的模組路徑的前置詞或完全相符。如果它不是完全相符,則會針對前置詞提出另一個要求,以驗證 <meta> 標籤是否相符。

vcs 是版本控制系統。它必須是下表中列出的工具之一,或關鍵字 mod,指示 go 指令使用 GOPROXY 協定 從指定的 URL 下載模組。請參閱 直接從代理程式提供模組 以取得詳細資料。

repo-url 是儲存庫的網址。如果網址不包含 scheme(可能是因為模組路徑有 VCS 限定詞,或因為 <meta> 標籤缺少 scheme),go 指令會嘗試版本控制系統支援的每個通訊協定。例如,對於 Git,go 指令會先嘗試 https://,然後再嘗試 git+ssh://。不安全的通訊協定(例如 http://git://)只能在模組路徑與 GOINSECURE 環境變數相符時使用。

名稱 指令 GOVCS 預設值 安全的 scheme
Bazaar bzr 僅限私人 httpsbzr+ssh
Fossil fossil 僅限私人 https
Git git 公開和私人 httpsgit+sshssh
Mercurial hg 公開和私人 httpsssh
Subversion svn 僅限私人 httpssvn+ssh

舉例來說,再考慮 golang.org/x/modgo 指令會傳送請求至 https://go.dev.org.tw/x/mod?go-get=1。伺服器會回應包含標籤的 HTML 文件

<meta name="go-import" content="golang.org/x/mod git https://go.googlesource.com/mod">

從這個回應中,go 指令會使用遠端網址 https://go.googlesource.com/mod 的 Git 儲存庫。

GitHub 和其他熱門的託管服務會回應所有儲存庫的 ?go-get=1 查詢,因此通常不需要為託管在這些網站上的模組進行伺服器設定。

找到儲存庫 URL 後,go 指令會將儲存庫複製到模組快取中。一般來說,go 指令會嘗試避免從儲存庫中擷取不需要的資料。然而,實際使用的指令會因版本控制系統而異,並且可能會隨著時間而改變。對於 Git,go 指令可以在不下載提交記錄的情況下列出大部分可用的版本。它通常會在不下載祖先提交記錄的情況下擷取提交記錄,但有時有必要這麼做。

將版本對應到提交記錄

go 指令可能會在儲存庫中以特定的正規版本,例如 v1.2.3v2.4.0-betav3.0.0+incompatible,檢出一個模組。每個模組版本都應該在儲存庫中有一個語意版本標籤,用來指出應該為特定版本檢出哪個版本。

如果模組定義在儲存庫根目錄或根目錄的主要版本子目錄中,則每個版本標籤名稱等於對應的版本。例如,模組 golang.org/x/text 定義在其儲存庫的根目錄中,因此版本 v0.3.2 在該儲存庫中具有標籤 v0.3.2。這適用於大多數模組。

如果模組定義在儲存庫中的子目錄中,也就是說,模組路徑的模組子目錄部分不為空,則每個標籤名稱都必須加上模組子目錄的前綴,後接斜線。例如,模組 golang.org/x/tools/gopls 定義在儲存庫的 gopls 子目錄中,根路徑為 golang.org/x/tools。該模組的版本 v0.4.0 在該儲存庫中必須具有名稱為 gopls/v0.4.0 的標籤。

語意版本標籤的主要版本號碼必須與模組路徑的主要版本字尾(如果有)一致。例如,標籤 v1.0.0 可以屬於模組 example.com/mod,但不能屬於 example.com/mod/v2,後者的標籤應該是 v2.0.0 之類的標籤。

如果沒有 go.mod 檔案,且模組位於儲存庫根目錄中,則具有主要版本 v2 或更高版本標籤的標籤可能屬於沒有主要版本字尾的模組。此類版本會標示為字尾 +incompatible。版本標籤本身不得具有字尾。請參閱 與非模組儲存庫的相容性

建立標籤後,不應刪除或變更為不同的修訂版本。版本會 驗證 以確保安全、可重複的建置。如果修改標籤,客戶端在下載時可能會看到安全性錯誤。即使在刪除標籤後,其內容仍可能在 模組代理 上提供。

將偽版本對應至提交

go 指令可能會在儲存庫中以特定修訂版本檢出模組,編碼為 偽版本,例如 v1.3.2-0.20191109021931-daa7c04131f5

偽版本的最後 12 個字元(以上面的範例為 daa7c04131f5)表示要檢出的儲存庫中的修訂版本。這表示的意義取決於版本控制系統。對於 Git 和 Mercurial,這是提交雜湊值的前綴。對於 Subversion,這是零填充的修訂版本號碼。

在檢出提交之前,go 指令會驗證時間戳記(以上面為 20191109021931)是否與提交日期相符。它還會驗證基礎版本(以上面的範例為 v1.3.1,即 v1.3.2 之前的版本)是否對應於提交的祖先的語意版本標籤。這些檢查可確保模組作者完全控制偽版本與其他已發布版本進行比較的方式。

請參閱 偽版本 以取得更多資訊。

將分支和提交對應到版本

模組可以使用 版本查詢 在特定分支、標籤或版本中簽出。

go get example.com/mod@master

go 指令會將這些名稱轉換成 正規版本,可用於 最小版本選取 (MVS)。MVS 依賴於明確排序版本的能力。隨著時間推移,無法可靠地比較分支名稱和版本,因為它們依賴於可能變更的儲存庫結構。

如果版本標記了一個或多個語義版本標籤,例如 v1.2.3,將使用最高有效版本的標籤。go 指令只會考慮可能屬於目標模組的語義版本標籤;例如,標籤 v1.5.2 對於 example.com/mod/v2 來說不會被考慮,因為主版本與模組路徑的後綴不符。

如果版本未標記有效的語義版本標籤,go 指令會產生 偽版本。如果版本有具備有效語義版本標籤的祖先,最高祖先版本將用作偽版本基礎。請參閱 偽版本

儲存庫中的模組目錄

在特定版本中簽出模組的儲存庫後,go 指令必須找到包含模組 go.mod 檔案的目錄(模組的根目錄)。

請回想一下,模組路徑 包含三個部分:儲存庫根路徑(對應到儲存庫根目錄)、模組子目錄,以及主版本後綴(僅適用於在 v2 或更高版本發布的模組)。

對於大多數模組,模組路徑等於儲存庫根路徑,因此模組的根目錄就是儲存庫的根目錄。

模組有時會定義在儲存庫子目錄中。這通常用於具有多個元件的大型儲存庫,這些元件需要獨立發佈和版本控制。預期此類模組會出現在與儲存庫根路徑後的模組路徑部分相符的子目錄中。例如,假設模組 example.com/monorepo/foo/bar 在根路徑為 example.com/monorepo 的儲存庫中。其 go.mod 檔案必須在 foo/bar 子目錄中。

如果模組在主版本 v2 或更高版本發佈,其路徑必須具有 主版本字尾。具有主版本字尾的模組可以在兩個子目錄之一中定義:一個帶有字尾,一個不帶字尾。例如,假設上述模組的新版本以路徑 example.com/monorepo/foo/bar/v2 發佈。其 go.mod 檔案可以位於 foo/barfoo/bar/v2 中。

具有主版本字尾的子目錄是 主版本子目錄。它們可用於在單一分支上開發模組的多個主版本。當多個主版本的開發在不同的分支上進行時,這可能是沒有必要的。但是,主版本子目錄有一個重要的特性:在 GOPATH 模式下,套件匯入路徑與 GOPATH/src 下的目錄完全匹配。go 命令在 GOPATH 模式下提供最小的模組相容性(請參閱 與非模組儲存庫的相容性),因此主版本子目錄對於與在 GOPATH 模式下建置的專案相容並不總是必要的。不過,不支援最小模組相容性的舊工具可能會遇到問題。

go 指令找到模組根目錄後,會建立目錄內容的 .zip 檔案,然後將 .zip 檔案解壓縮到模組快取中。有關 .zip 檔案中可以包含哪些檔案的詳細資訊,請參閱 檔案路徑和大小限制.zip 檔案的內容會在解壓縮到模組快取中之前進行 驗證,就像從代理程式下載 .zip 檔案一樣。

模組 zip 檔案不包含 vendor 目錄或任何巢狀模組 (包含 go.mod 檔案的子目錄) 的內容。這表示模組必須注意不要參照目錄外部或其他模組中的檔案。例如,//go:embed 模式不得比對巢狀模組中的檔案。在不應將檔案包含在模組中的情況下,此行為可作為有用的解決方法。例如,如果存放庫已將大型檔案簽入 testdata 目錄,模組作者可以在 testdata 中新增一個空的 go.mod 檔案,這樣他們的使用者就不需要下載這些檔案。當然,這可能會減少使用者測試其相依項的涵蓋範圍。

LICENSE 檔案的特殊情況

go 指令為不在儲存庫根目錄的模組建立 .zip 檔案時,如果模組的根目錄中沒有名為 LICENSE 的檔案(與 go.mod 並列),則 go 指令會從儲存庫根目錄複製名為 LICENSE 的檔案(如果它存在於同一版本)。

這個特殊情況允許相同的 LICENSE 檔案套用至儲存庫中的所有模組。這僅套用至特別命名為 LICENSE 的檔案,沒有 .txt 等副檔名。不幸的是,這無法擴充而不中斷現有模組的加密雜湊總和;請參閱 驗證模組。其他工具和網站,例如 pkg.go.dev,可能會辨識其他名稱的檔案。

另外請注意,go 指令在建立模組 .zip 檔案時不包含符號連結;請參閱 檔案路徑和大小限制。因此,如果儲存庫的根目錄沒有 LICENSE 檔案,作者可以改為在子目錄中定義的模組中建立授權檔案的副本,以確保這些檔案包含在模組 .zip 檔案中。

使用 GOVCS 控制版本控制工具

go 指令使用 git 等版本控制指令下載模組的能力對於分散式套件生態系統至關重要,其中程式碼可以從任何伺服器匯入。如果惡意伺服器找到一種方法,導致調用的版本控制指令執行意外的程式碼,這也可能是一個潛在的安全問題。

為了平衡功能性和安全性考量,預設情況下,go 指令只會使用 githg 從公用伺服器下載程式碼。它會使用任何 已知的版本控制系統 從私有伺服器下載程式碼,定義為符合 GOPRIVATE 環境變數 的主機套件。僅允許 Git 和 Mercurial 的原因在於這兩個系統最注重作為不受信任伺服器客戶端執行的問題。相比之下,Bazaar、Fossil 和 Subversion 主要用於受信任的驗證環境,且未像攻擊面那樣受到仔細審查。

版本控制指令限制僅在使用直接版本控制存取來下載程式碼時套用。從代理伺服器下載模組時,go 指令改用 GOPROXY 通訊協定,該協定始終被允許。預設情況下,go 指令對公用模組使用 Go 模組鏡像 (proxy.golang.org),僅對私有模組或鏡像拒絕提供公用套件(通常基於法律原因)時才回歸版本控制。因此,客戶端仍可存取從 Bazaar、Fossil 或 Subversion 儲存庫提供的公用程式碼,因為這些下載使用 Go 模組鏡像,它承擔使用自訂沙盒執行版本控制指令的安全性風險。

GOVCS 變數可用於變更特定模組允許的版本控制系統。GOVCS 變數在模組感知模式和 GOPATH 模式中建置套件時套用。使用模組時,模式與模組路徑相符。使用 GOPATH 時,模式與對應於版本控制儲存庫根目錄的匯入路徑相符。

GOVCS 變數的一般形式是逗號分隔的 pattern:vcslist 規則清單。此模式是 glob 模式,必須與模組或匯入路徑的一個或多個開頭元素相符。vcslist 是允許的版本控制命令的管線分隔清單,或 all 以允許使用任何已知命令,或 off 以不允許任何命令。請注意,如果模組與 vcslist off 的模式相符,如果原始伺服器使用 mod 架構,它仍然可以下載,這會指示 go 命令使用 GOPROXY 通訊協定 下載模組。清單中最早相符的模式會套用,即使後面的模式也可能相符。

例如,請考慮

GOVCS=github.com:git,evil.com:off,*:git|hg

使用此設定,模組或匯入路徑以 github.com/ 開頭的程式碼只能使用 gitevil.com 上的路徑不能使用任何版本控制命令,而所有其他路徑(* 與所有內容相符)只能使用 githg

特殊模式 publicprivate 與公開和私人模組或匯入路徑相符。如果路徑與 GOPRIVATE 變數相符,則表示它是私人路徑;否則,它是公開路徑。

如果 GOVCS 變數中的規則沒有與特定模組或匯入路徑相符,則 go 命令會套用其預設規則,現在可以用 GOVCS 表示法總結為 public:git|hg,private:all

若要允許對任何套件使用任何版本控制系統,請使用

GOVCS=*:all

若要停用所有版本控制的使用,請使用

GOVCS=*:off

可以使用 go env -w 命令 為未來的 go 命令呼叫設定 GOVCS 變數。

GOVCS 在 Go 1.16 中引入。較早版本的 Go 可能對任何模組使用任何已知的版本控制工具。

模組 zip 檔案

模組版本以 .zip 檔案形式發佈。很少需要直接與這些檔案互動,因為 go 指令會從 模組代理 和版本控制存放庫自動建立、下載和解壓縮這些檔案。不過,瞭解這些檔案對於理解跨平台相容性限制或實作模組代理仍然很有用。

go mod download 指令會為一個或多個模組下載 zip 檔案,然後將這些檔案解壓縮到 模組快取 中。根據 GOPROXY 和其他 環境變數go 指令可能會從代理下載 zip 檔案,或複製原始碼控制存放庫並從中建立 zip 檔案。-json 旗標可用於在模組快取中尋找下載的 zip 檔案及其解壓縮內容的位置。

golang.org/x/mod/zip 套件 可用於以程式方式建立、解壓縮或檢查 zip 檔案的內容。

檔案路徑和大小限制

模組 zip 檔案的內容有一些限制。這些限制可確保 zip 檔案可以在各種平台上安全且一致地解壓縮。

私人模組

Go 模組經常在版本控制伺服器和模組代理上開發和發行,而這些伺服器和代理並未在網際網路上公開。go 指令可以從私人來源下載和建置模組,儘管通常需要一些設定。

下列環境變數可用於設定對私人模組的存取。詳情請參閱 環境變數。另請參閱 隱私權,以取得有關控制傳送至公開伺服器的資訊的資訊。

這些變數可以在開發環境中設定(例如在 .profile 檔案中),或使用 go env -w 永久設定。

本節的其餘部分說明提供存取權限給私人模組代理程式和版本控制儲存庫的常見模式。

提供所有模組服務的私人代理程式

提供所有模組(公開和私人)服務的中央私人代理程式伺服器,可提供管理員最大的控制權,而且個別開發人員所需的設定最少。

若要設定 go 指令以使用此類伺服器,請設定下列環境變數,將 https://proxy.corp.example.com 取代為您的代理程式 URL,並將 corp.example.com 取代為您的模組字首

GOPROXY=https://proxy.corp.example.com
GONOSUMDB=corp.example.com

GOPROXY 設定指示 go 指令僅從 https://proxy.corp.example.com 下載模組;go 指令不會連線到其他代理程式或版本控制儲存庫。

GONOSUMDB 設定指示 go 指令不要使用公開雜湊資料庫來驗證路徑以 corp.example.com 開頭的模組。

在此設定中執行的代理程式可能需要讀取存取權限給私人版本控制伺服器。它也需要存取公開網際網路才能下載公開模組的新版本。

有幾個現有的 GOPROXY 伺服器實作可以這樣使用。最小的實作會從 模組快取 目錄提供檔案,並使用 go mod download(搭配適當設定)來擷取遺失的模組。

提供私人模組服務的私人代理程式

私人代理程式伺服器可以提供私人模組服務,而不提供公開可用的模組服務。go 指令可以設定為對私人伺服器上不可用的模組,退回至公開來源。

若要設定 go 指令以這種方式執行,請設定下列環境變數,並將 https://proxy.corp.example.com 替換為代理伺服器 URL,將 corp.example.com 替換為模組字首

GOPROXY=https://proxy.corp.example.com,https://proxy.golang.org,direct
GONOSUMDB=corp.example.com

GOPROXY 設定指示 go 指令先嘗試從 https://proxy.corp.example.com 下載模組。如果該伺服器回應 404 (未找到) 或 410 (已移除),go 指令將會回退到 https://proxy.golang.org,然後再直接連線到儲存庫。

GONOSUMDB 設定指示 go 指令不要使用公開雜湊資料庫來驗證路徑以 corp.example.com 開頭的模組。

請注意,即使此組態中使用的代理伺服器不提供公開模組,它仍可能控制對公開模組的存取。如果代理伺服器回應請求時傳回的錯誤狀態不是 404 或 410,go 指令將不會回退到 GOPROXY 清單中的後續項目。例如,對於具有不適當授權或已知安全漏洞的模組,代理伺服器可能會回應 403 (禁止)。

直接存取私人模組

go 指令可以設定為繞過公開代理伺服器,並直接從版本控制伺服器下載私人模組。當無法執行私人代理伺服器時,這會很有用。

若要設定 go 指令以這種方式執行,請設定 GOPRIVATE,並將 corp.example.com 替換為私人模組字首

GOPRIVATE=corp.example.com

在這種情況下,不需要變更 GOPROXY 變數。它的預設值為 https://proxy.golang.org,direct,指示 go 指令先嘗試從 https://proxy.golang.org 下載模組,如果該代理伺服器回應 404 (未找到) 或 410 (已移除),則回退到直接連線。

GOPRIVATE 設定指示 go 指令不要連線到代理伺服器或雜湊資料庫,以取得以 corp.example.com 開頭的模組。

可能仍需要一個內部 HTTP 伺服器來將模組路徑解析為儲存庫 URL。例如,當 go 指令下載模組 corp.example.com/mod 時,它會傳送 GET 要求至 https://corp.example.com/mod?go-get=1,並在回應中尋找儲存庫 URL。若要避免此需求,請確保每個私人模組路徑都有一個 VCS 字尾 (例如 .git) 來標記儲存庫根目錄字首。例如,當 go 指令下載模組 corp.example.com/repo.git/mod 時,它會複製位於 https://corp.example.com/repo.gitssh://corp.example.com/repo.git 的 Git 儲存庫,而不需要提出其他要求。

開發人員需要對包含私人模組的儲存庫有讀取權限。這可以在全域 VCS 設定檔中設定,例如 .gitconfig。最好將 VCS 工具設定為不需要互動式驗證提示。預設情況下,在呼叫 Git 時,go 指令會透過設定 GIT_TERMINAL_PROMPT=0 來停用互動式提示,但它會尊重明確的設定。

傳遞憑證給私人代理伺服器

go 指令在與代理伺服器通訊時支援 HTTP 基本驗證

憑證可以指定在 .netrc 檔案 中。例如,包含以下列行的 .netrc 檔案會設定 go 指令以使用指定的使用者名稱和密碼連線至機器 proxy.corp.example.com

machine proxy.corp.example.com
login jrgopher
password hunter2

檔案位置可以用 NETRC 環境變數設定。如果未設定 NETRCgo 指令會在類 UNIX 平台上讀取 $HOME/.netrc,或在 Windows 上讀取 %USERPROFILE%\_netrc

.netrc 中的欄位以空白、標籤和換行符號分隔。遺憾的是,這些字元無法用於使用者名稱或密碼。另請注意,機器名稱不能是完整的 URL,因此無法為同一台機器上的不同路徑指定不同的使用者名稱和密碼。

或者,可以在 GOPROXY URL 中直接指定憑證。例如

GOPROXY=https://jrgopher:hunter2@proxy.corp.example.com

採用此方法時請小心:環境變數可能會出現在 shell 歷程記錄和記錄檔中。

傳遞憑證給私人儲存庫

go 指令可能會直接從版本控制儲存庫下載模組。如果未使用私人代理程式,則私人模組需要這樣做。請參閱 直接存取私人模組 以取得組態資訊。

go 指令在直接下載模組時會執行版本控制工具,例如 git。這些工具會執行自己的驗證,因此您可能需要在特定於工具的組態檔案(例如 .gitconfig)中組態憑證。

為確保順利運作,請確定 go 指令使用正確的儲存庫 URL,且版本控制工具不需要互動式輸入密碼。go 指令偏好 https:// URL,而非其他方案(例如 ssh://),除非在 查詢儲存庫 URL 時指定了該方案。特別是對於 GitHub 儲存庫,go 指令假設為 https://

對於大多數伺服器,您可以將您的客戶端組態為透過 HTTP 驗證。例如,GitHub 支援使用 OAuth 個人存取權杖作為 HTTP 密碼。您可以將 HTTP 密碼儲存在 .netrc 檔案中,就像 傳遞憑證給私人代理程式 時一樣。

或者,您可以將 https:// URL 改寫為另一種方案。例如,在 .gitconfig

[url "git@github.com:"]
    insteadOf = https://github.com/

如需更多資訊,請參閱 「go get」在複製儲存庫時為何使用 HTTPS?

隱私權

go 命令可能會從模組代理伺服器和版本控制系統下載模組和元資料。環境變數 GOPROXY 控制使用哪些伺服器。環境變數 GOPRIVATEGONOPROXY 控制從代理伺服器擷取哪些模組。

GOPROXY 的預設值為

https://proxy.golang.org,direct

使用此設定時,當 go 命令下載模組或模組元資料時,它會先將要求傳送至 proxy.golang.org,這是由 Google 營運的公開模組代理伺服器 (隱私權政策)。有關每個要求中傳送哪些資訊的詳細資訊,請參閱 GOPROXY 協定go 命令不會傳輸個人可識別資訊,但它會傳輸正在要求的完整模組路徑。如果代理伺服器回應 404 (找不到) 或 410 (已移除) 狀態,go 命令會嘗試直接連線至提供模組的版本控制系統。有關詳細資訊,請參閱 版本控制系統

GOPRIVATEGONOPROXY 環境變數可以設定為與私人模組前綴相符的 glob 模式清單,且不應從任何代理伺服器要求。例如

GOPRIVATE=*.corp.example.com,*.research.example.com

GOPRIVATE 僅作為 GONOPROXYGONOSUMDB 的預設值,因此除非 GONOSUMDB 應具有不同的值,否則不必設定 GONOPROXY。當模組路徑與 GONOPROXY 相符時,go 命令會忽略該模組的 GOPROXY,並直接從其版本控制存放庫中擷取。這在沒有代理伺服器提供私人模組時很有用。請參閱 直接存取私人模組

如果有一個 受信任的代理程式服務所有模組,則不應設定 GONOPROXY。例如,如果 GOPROXY 設定為一個來源,go 指令不會從其他來源下載模組。在此情況下,仍應設定 GONOSUMDB

GOPROXY=https://proxy.corp.example.com
GONOSUMDB=*.corp.example.com,*.research.example.com

如果有一個 受信任的代理程式僅服務私人模組,則不應設定 GONOPROXY,但必須小心確保代理程式以正確的狀態碼回應。例如,考慮以下組態

GOPROXY=https://proxy.corp.example.com,https://proxy.golang.org
GONOSUMDB=*.corp.example.com,*.research.example.com

假設開發人員因輸入錯誤而嘗試下載不存在的模組。

go mod download corp.example.com/secret-product/typo@latest

go 指令會先從 proxy.corp.example.com 要求此模組。如果該代理程式以 404 (找不到) 或 410 (已移除) 回應,go 指令會退回到 proxy.golang.org,在要求 URL 中傳送 secret-product 路徑。如果私人代理程式以任何其他錯誤碼回應,go 指令會列印錯誤訊息,且不會退回到其他來源。

除了代理程式之外,go 指令可能會連線到檢查總和資料庫,以驗證未列在 go.sum 中的模組的加密雜湊。GOSUMDB 環境變數會設定檢查總和資料庫的名稱、URL 和公開金鑰。GOSUMDB 的預設值為 sum.golang.org,這是由 Google 營運的公開檢查總和資料庫 (隱私權政策)。請參閱 檢查總和資料庫,以取得關於每個要求傳輸內容的詳細資訊。與代理程式一樣,go 指令不會傳輸個人可識別資訊,但它會傳輸正在要求的完整模組路徑,而檢查總和資料庫無法計算非公開模組的檢查總和。

GONOSUMDB 環境變數可以設定為模式,用以指出哪些模組是私有的,不應從檢查總和資料庫中請求。GOPRIVATE 作為 GONOSUMDBGONOPROXY 的預設值,因此除非 GONOPROXY 應具有不同的值,否則不必設定 GONOSUMDB

代理伺服器可能會 鏡像檢查總和資料庫。如果 GOPROXY 中的代理伺服器執行此動作,go 指令將不會直接連線至檢查總和資料庫。

GOSUMDB 可以設定為 off 以完全停用檢查總和資料庫。使用此設定時,go 指令將不會驗證已下載的模組,除非它們已存在於 go.sum 中。請參閱 驗證模組

模組快取

模組快取go 指令儲存已下載模組檔案的目錄。模組快取與建置快取不同,後者包含已編譯的套件和其他建置成品。

模組快取的預設位置為 $GOPATH/pkg/mod。若要使用不同的位置,請設定 GOMODCACHE 環境變數

模組快取沒有最大容量,而且 go 指令不會自動移除其內容。

快取可以由在同一台機器上開發的多個 Go 專案共用。go 指令將使用相同的快取,而與主模組的位置無關。多個 go 指令執行個體可以同時安全地存取相同的模組快取。

go 指令會在快取中建立模組原始碼檔案和目錄,並設定為唯讀權限,以防止模組下載後意外變更。這會造成一個不幸的副作用,讓快取難以使用 rm -rf 等指令刪除。快取可以用 go clean -modcache 刪除。或者,當使用 -modcacherw 旗標時,go 指令會建立具有讀寫權限的新目錄。這會增加編輯器、測試和其他程式修改模組快取中檔案的風險。go mod verify 指令可用於偵測主模組相依項目的修改。它會掃描每個模組相依項目的解壓縮內容,並確認它們與 go.sum 中預期的雜湊值相符。

下表說明模組快取中大多數檔案的目的。某些暫時檔案(鎖定檔案、暫時目錄)已省略。對於每個路徑,$module 是模組路徑,而 $version 是版本。以斜線 (/) 結尾的路徑是目錄。模組路徑和版本中的大寫字母會使用驚嘆號轉譯(Azure 轉譯為 !azure),以避免在不區分大小寫的檔案系統上發生衝突。

路徑 說明
$module@$version/ 包含模組 .zip 檔案解壓縮內容的目錄。這會作為已下載模組的模組根目錄。如果原始模組沒有 go.mod 檔案,它將不會包含 go.mod 檔案。
cache/download/ 包含從模組代理伺服器下載的檔案和衍生自 版本控制系統 的檔案的目錄。此目錄的配置遵循 GOPROXY 協定,因此當由 HTTP 檔案伺服器提供服務或使用 file:// URL 參照時,此目錄可以用作代理伺服器。
快取/下載/$module/@v/清單 已知版本清單(請參閱 GOPROXY 協定)。此清單可能會隨著時間而變更,因此 go 指令通常會擷取新的副本,而不是重複使用此檔案。
快取/下載/$module/@v/$version.info 版本的 JSON 元資料(請參閱 GOPROXY 協定)。此元資料可能會隨著時間而變更,因此 go 指令通常會擷取新的副本,而不是重複使用此檔案。
快取/下載/$module/@v/$version.mod 此版本的 go.mod 檔案(請參閱 GOPROXY 協定)。如果原始模組沒有 go.mod 檔案,這將會是一個沒有需求的合成檔案。
快取/下載/$module/@v/$version.zip 模組的壓縮內容(請參閱 GOPROXY 協定模組 zip 檔案)。
快取/下載/$module/@v/$version.ziphash .zip 檔案中檔案的加密雜湊。請注意,.zip 檔案本身並未雜湊,因此檔案順序、壓縮、對齊和元資料不會影響雜湊。在使用模組時,go 指令會驗證此雜湊是否與 go.sum 中的對應行相符。go mod verify 指令會檢查模組 .zip 檔案和解壓目錄的雜湊是否與這些檔案相符。
快取/下載/sumdb/ 包含從 雜湊資料庫(通常為 sum.golang.org)下載的檔案的目錄。
快取/vcs/ 包含從其來源直接擷取的模組的克隆版本控制儲存庫。目錄名稱是從儲存庫類型和 URL 衍生的十六進位編碼雜湊。儲存庫已針對磁碟大小最佳化。例如,克隆的 Git 儲存庫在可能的情況下是空的且淺的。

驗證模組

go 指令將模組 zip 檔案go.mod 檔案 下載到 模組快取 中時,它會計算加密雜湊並與已知值進行比較,以驗證檔案自首次下載以來是否未變更。如果下載的檔案沒有正確的雜湊,go 指令會報告安全性錯誤。

對於 go.mod 檔案,go 指令會從檔案內容計算雜湊。對於模組 zip 檔案,go 指令會以確定性的順序從檔案庫中檔案的名稱和內容計算雜湊。雜湊不受檔案順序、壓縮、對齊和其他元資料影響。請參閱 golang.org/x/mod/sumdb/dirhash 以取得雜湊實作詳細資料。

go 指令會將每個雜湊與主模組的 go.sum 檔案 中的對應行進行比較。如果雜湊與 go.sum 中的雜湊不同,go 指令會報告安全性錯誤並刪除下載的檔案,而不會將其新增到模組快取中。

如果 go.sum 檔案不存在,或是不包含已下載檔案的雜湊,go 指令可能會使用 雜湊資料庫 來驗證雜湊,這是公開模組雜湊的全球來源。一旦驗證了雜湊,go 指令就會將其新增到 go.sum,並將已下載的檔案新增到模組快取中。如果模組是私有的(由 GOPRIVATEGONOSUMDB 環境變數比對)或如果雜湊資料庫已停用(透過設定 GOSUMDB=off),go 指令會接受雜湊,並將檔案新增到模組快取中,而不會驗證它。

模組快取通常由系統上的所有 Go 專案共用,每個模組都可能有自己的 go.sum 檔案,其中包含不同的雜湊。為了避免需要信任其他模組,go 指令會在存取模組快取中的檔案時,使用主模組的 go.sum 來驗證雜湊。Zip 檔案雜湊的運算成本很高,因此 go 指令會檢查與 Zip 檔案一起儲存的預先運算雜湊,而不是重新雜湊檔案。go mod verify 指令可用於檢查 Zip 檔案和已解壓縮的目錄自新增到模組快取後,是否未經修改。

go.sum 檔案

模組可能在其根目錄中有一個名為 go.sum 的文字檔,與其 go.mod 檔案並列。go.sum 檔案包含模組的直接和間接相依項的加密雜湊。當 go 指令將模組 .mod.zip 檔案下載到 模組快取 中時,它會運算雜湊,並檢查雜湊是否與主模組 go.sum 檔案中的對應雜湊相符。如果模組沒有相依項,或如果所有相依項都已使用 replace 指令 替換為本機目錄,則 go.sum 可能為空或不存在。

go.sum 中的每一行都有三個欄位,以空格分隔:模組路徑、版本(可能以 /go.mod 結尾)和雜湊。

go.sum 檔案可能包含多個模組版本的雜湊。go 命令可能需要從多個依賴項版本載入 go.mod 檔案,才能執行 最小版本選取go.sum 也可能包含不再需要的模組版本雜湊(例如,在升級後)。go mod tidy 會新增遺失的雜湊,並從 go.sum 中移除不必要的雜湊。

檢查總和資料庫

檢查總和資料庫是 go.sum 行的全球來源。go 命令可以在許多情況下使用它來偵測代理伺服器或原始伺服器的異常行為。

檢查總和資料庫允許所有公開模組版本具有全球一致性和可靠性。它讓不受信任的代理伺服器成為可能,因為它們無法在不被注意的情況下提供錯誤的程式碼。它還確保與特定版本相關聯的位元不會從一天到另一天改變,即使模組作者隨後更改其儲存庫中的標籤。

雜湊資料庫由 Google 營運的 sum.golang.org 提供。它是 go.sum 行雜湊的 透明記錄(或「梅克爾樹」),由 Trillian 支援。梅克爾樹的主要優點是,獨立稽核員可以驗證它未遭竄改,因此比單純的資料庫更值得信賴。

go 指令使用最初在 提案:保護公開的 Go 模組生態系統 中概述的通訊協定,與雜湊資料庫互動。

下表指定雜湊資料庫必須回應的查詢。對於每個路徑,$base 是雜湊資料庫 URL 的路徑部分,$module 是模組路徑,而 $version 是版本。例如,如果雜湊資料庫 URL 是 https://sum.golang.org,而客戶端要求版本 v0.3.2 的模組 golang.org/x/text 的記錄,客戶端會傳送 GET 要求給 https://sum.golang.org/lookup/golang.org/x/text@v0.3.2

為了避免在從不區分大小寫的檔案系統提供服務時產生歧義,$module$version 元素會 進行大小寫編碼,方法是將每個大寫字母替換為驚嘆號,後接對應的小寫字母。這允許模組 example.com/Mexample.com/m 都儲存在磁碟上,因為前者編碼為 example.com/!m

由方括號括起來的路徑部分,例如 [.p/$W] 表示選用值。

路徑 說明
$base/latest 傳回最新記錄的已簽署、編碼樹狀結構描述。此已簽署描述為 備註 的形式,此備註為已由一個或多個伺服器金鑰簽署的文字,並可以使用伺服器公開金鑰進行驗證。樹狀結構描述提供樹狀結構的大小和該大小的樹狀結構主節點雜湊。此編碼在 golang.org/x/mod/sumdb/tlog#FormatTree 中進行描述。
$base/lookup/$module@$version 傳回關於 $module$version 的記錄的記錄編號,接著是記錄的資料(亦即 $module$versiongo.sum 行)和包含記錄的已簽署、編碼樹狀結構描述。
$base/tile/$H/$L/$K[.p/$W] 傳回 [記錄磁磚](https://research.swtch.com/tlog#serving_tiles),此磁磚為組成記錄一部分的雜湊值集合。每個磁磚在二維座標中定義為磁磚層級 $L,從左邊開始為第 $K 個,磁磚高度為 $H。選用的 .p/$W 字尾表示只有 $W 個雜湊值的記錄部分磁磚。如果找不到部分磁磚,客戶端必須改為擷取完整磁磚。
$base/tile/$H/data/$K[.p/$W] 傳回 /tile/$H/0/$K[.p/$W] 中樹葉雜湊值的記錄資料(使用文字 data 路徑元素)。

如果 go 指令諮詢檢查和資料庫,則第一步是透過 /lookup 端點擷取記錄資料。如果模組版本尚未記錄在日誌中,檢查和資料庫會嘗試在回應前從原始伺服器擷取它。此 /lookup 資料提供此模組版本的總和及其在日誌中的位置,它會告知用戶端應擷取哪些磁磚來執行證明。go 指令會執行「包含」證明(特定記錄存在於日誌中)和「一致性」證明(樹狀結構未被竄改),然後才將新的 go.sum 行新增至主模組的 go.sum 檔案。重要的是,絕不應在未先根據已簽署的樹狀結構雜湊驗證資料,並根據用戶端已簽署的樹狀結構雜湊時間表驗證已簽署的樹狀結構雜湊的情況下,使用來自 /lookup 的資料。

已簽署的樹狀結構雜湊和檢查和資料庫提供的新的磁磚會儲存在模組快取中,因此 go 指令只需要擷取遺失的磁磚。

go 指令不需要直接連接到檢查和資料庫。它可以透過模組代理程式要求模組總和,該代理程式會 鏡像檢查和資料庫 並支援上述通訊協定。這對於封閉的企業代理程式(會封鎖組織外的要求)特別有幫助。

GOSUMDB 環境變數會識別要使用的檢查和資料庫名稱,並選擇性地識別其公開金鑰和 URL,如下所示

GOSUMDB="sum.golang.org"
GOSUMDB="sum.golang.org+<publickey>"
GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"

go 指令知道 sum.golang.org 的公開金鑰,也知道名稱 sum.golang.google.cn(中國大陸內可用)會連接到 sum.golang.org 檢查和資料庫;使用任何其他資料庫都需要明確提供公開金鑰。URL 預設為 https:// 後面接資料庫名稱。

GOSUMDB 預設為 sum.golang.org,這是 Google 執行的 Go 檢查和資料庫。請參閱 https://sum.golang.org/privacy 以取得服務的隱私權政策。

如果將 GOSUMDB 設為 off,或使用 -insecure 旗標呼叫 go get,則不會諮詢檢查總和資料庫,且會接受所有無法辨識的模組,但代價是放棄所有模組已驗證可重複下載的安全保證。繞過特定模組的檢查總和資料庫的較佳方式是使用 GOPRIVATEGONOSUMDB 環境變數。詳情請參閱 私人模組

go env -w 指令可用於 設定這些變數,以供將來呼叫 go 指令時使用。

環境變數

go 指令中的模組行為可以使用下列所列的環境變數來設定。此清單僅包含與模組相關的環境變數。請參閱 go help environment,以取得 go 指令辨識的所有環境變數清單。

變數 說明
GO111MODULE

控制 go 指令是在模組感知模式或 GOPATH 模式下執行。辨識三種值

  • offgo 指令忽略 go.mod 檔案,並在 GOPATH 模式下執行。
  • on (或未設定):即使沒有 go.mod 檔案,go 指令也會在模組感知模式下執行。
  • auto:如果在目前目錄或任何父目錄中存在 go.mod 檔案,則 go 指令會在模組感知模式下執行。在 Go 1.15 及更早版本中,這是預設值。

請參閱 模組感知指令,以取得更多資訊。

GOMODCACHE

go 指令將儲存已下載模組和相關檔案的目錄。請參閱 模組快取,以取得此目錄結構的詳細資料。

如果未設定 GOMODCACHE,它會預設為 $GOPATH/pkg/mod

GOINSECURE

以逗號分隔的 glob 模式清單(語法為 Go 的 path.Match),其中包含模組路徑前綴,這些前綴可能總是會以不安全的方式擷取。僅適用於直接擷取的依賴項。

go get 上的 -insecure 旗標不同,GOINSECURE 不會停用模組檢查總和資料庫驗證。GOPRIVATEGONOSUMDB 可用於達成此目的。

GONOPROXY

以逗號分隔的 glob 模式清單(語法為 Go 的 path.Match),其中包含模組路徑前綴,這些前綴應始終直接從版本控制儲存庫擷取,而不是從模組代理程式擷取。

如果未設定 GONOPROXY,它會預設為 GOPRIVATE。請參閱 隱私

GONOSUMDB

以逗號分隔的 glob 模式清單(語法為 Go 的 path.Match),其中包含模組路徑前綴,go 不應使用檢查總和資料庫驗證其檢查總和。

如果未設定 GONOSUMDB,它會預設為 GOPRIVATE。請參閱 隱私

GOPATH

GOPATH 模式中,GOPATH 變數是可能包含 Go 程式碼的目錄清單。

在模組感知模式中,模組快取 儲存在第一個 GOPATH 目錄的 pkg/mod 子目錄中。快取外的模組原始程式碼可以儲存在任何目錄中。

如果未設定 GOPATH,它會預設為使用者家目錄的 go 子目錄。

GOPRIVATE 以逗號分隔的 glob 模式清單(語法為 Go 的 path.Match),其中包含應視為私人模組路徑前綴。GOPRIVATEGONOPROXYGONOSUMDB 的預設值。請參閱 隱私權GOPRIVATE 也決定模組是否視為 GOVCS 的私人模組。
GOPROXY

以逗號 (,) 或直線 (|) 分隔的模組代理網址清單。當 go 指令查詢模組資訊時,它會依序連絡清單中的每個代理,直到收到成功的回應或終端錯誤。代理可能會回應 404(找不到)或 410(已移除)狀態,以表示該伺服器上沒有該模組。

go 指令的錯誤回退行為由網址之間的分隔字元決定。如果代理網址後面跟著逗號,則 go 指令在 404 或 410 錯誤後會回退到下一個網址;所有其他錯誤都視為終端錯誤。如果代理網址後面跟著直線,則 go 指令在任何錯誤(包括逾時等非 HTTP 錯誤)後都會回退到下一個來源。

GOPROXY 網址可以有 httpshttpfile 等架構。如果網址沒有架構,則假設為 https。模組快取可以用作檔案代理直接使用

GOPROXY=file://$(go env GOMODCACHE)/cache/download

可以使用兩個關鍵字取代代理網址

  • off:禁止從任何來源下載模組。
  • direct:直接從版本控制存放庫下載,而不是使用模組代理。

GOPROXY 預設為 https://proxy.golang.org,direct。在該設定下,go 指令會先連線由 Google 執行的 Go 模組鏡像,如果鏡像沒有該模組,則會改為直接連線。請參閱 https://proxy.golang.org/privacy,以取得鏡像的隱私權政策。可以設定 GOPRIVATEGONOPROXY 環境變數,以防止特定模組使用代理伺服器下載。有關私人代理伺服器設定的資訊,請參閱 隱私權

請參閱 模組代理伺服器將套件解析為模組,以取得有關如何使用代理伺服器的更多資訊。

GOSUMDB

識別要使用的雜湊總和資料庫名稱,以及其公開金鑰和 URL(如果有的話)。例如

GOSUMDB="sum.golang.org"
GOSUMDB="sum.golang.org+<publickey>"
GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"

go 指令知道 sum.golang.org 的公開金鑰,也知道名稱 sum.golang.google.cn(中國大陸境內可用)會連線到 sum.golang.org 資料庫;使用任何其他資料庫都需要明確提供公開金鑰。URL 預設為 https://,後接資料庫名稱。

GOSUMDB 預設為 sum.golang.org,這是由 Google 執行的 Go 雜湊總和資料庫。請參閱 https://sum.golang.org/privacy,以取得服務的隱私權政策。

如果 GOSUMDB 設定為 off,或如果使用 -insecure 旗標呼叫 go get,則不會查詢雜湊總和資料庫,而且會接受所有未識別的模組,但代價是放棄所有模組經過驗證的可重複下載安全性保證。繞過特定模組的雜湊總和資料庫的較好方法是使用 GOPRIVATEGONOSUMDB 環境變數。

請參閱 模組驗證隱私權 以取得更多資訊。

GOVCS

控制 go 指令可以使用的版本控制工具組,用於下載公用和私人模組(由其路徑是否符合 GOPRIVATE 中的模式定義)或符合 glob 模式的其他模組。

如果未設定 GOVCS,或如果模組不符合 GOVCS 中的任何模式,則 go 指令可能會對公用模組使用 githg,或對私人模組使用任何已知的版本控制工具。具體來說,go 指令會像 GOVCS 已設定為

public:git|hg,private:all

請參閱 使用 GOVCS 控制版本控制工具 以取得完整說明。

GOWORK

GOWORK 環境變數指示 go 指令使用提供的 [`go.work` 檔案](#go-work-file) 定義工作區,以進入工作區模式。如果將 GOWORK 設定為 off,則會停用工作區模式。這可以用於在單一模組模式下執行 go 指令:例如,GOWORK=off go build . 會在單一模組模式下建置 . 套件。如果 GOWORK 為空,則 go 指令會搜尋 `go.work` 檔案,如 [工作區](#workspaces) 區段中所述。

詞彙表

建置限制:決定在編譯套件時是否使用 Go 原始檔的條件。建置限制可以用檔案名稱字尾(例如,foo_linux_amd64.go)或建置限制註解(例如,// +build linux,amd64)表示。請參閱 建置限制

建置清單:模組版本清單,將用於建置指令,例如 go buildgo listgo test。建置清單是由 主模組的 go.mod 檔案 和傳遞所需模組中的 go.mod 檔案使用 最小版本選取 來決定的。建置清單包含 模組圖 中所有模組的版本,而不僅僅是與特定指令相關的那些模組。

正規版本:格式正確的 版本,沒有 +incompatible 以外的建置元資料字尾。例如,v1.2.3 是正規版本,但 v1.2.3+meta 不是。

目前模組:主模組 的同義詞。

已棄用模組:不再受其作者支援的模組(儘管主要版本被視為此目的的相異模組)。已棄用模組會在其 go.mod 檔案 的最新版本中標記 棄用註解

直接依賴項:其路徑出現在 主模組 或包含此類模組的模組中,針對某個套件或測試的 .go 原始檔中的 import 宣告 中的套件。(比較 間接依賴項。)

直接模式:環境變數 的設定,導致 go 指令從 版本控制系統 直接下載模組,而不是從 模組代理 下載。GOPROXY=direct 對所有模組執行此操作。GOPRIVATEGONOPROXY 對符合模式清單的模組執行此操作。

go.mod 檔案:定義模組路徑、需求和其他元資料的檔案。出現在 模組根目錄 中。請參閱 go.mod 檔案 部分。

go.work 檔案 定義要使用在 工作區 中的模組集的檔案。請參閱 go.work 檔案 部分。

匯入路徑:用於在 Go 原始碼檔案中匯入套件的字串。與 套件路徑 同義。

間接依賴項:主模組 中的套件或測試傳遞匯入的套件,但其路徑未出現在主模組中的任何 import 宣告 中;或出現在 模組圖 中但未提供主模組直接匯入的任何套件。(比較 直接依賴項。)

延遲模組載入:Go 1.17 中的變更,可避免為不需要模組圖的指令載入模組圖,適用於指定 go 1.17 或更高版本的模組。請參閱 延遲模組載入

主模組:呼叫 go 指令的模組。主模組由目前目錄或父目錄中的 go.mod 檔案 定義。請參閱 模組、套件和版本

主版本:語意化版本中的第一個數字(v1.2.3 中的 1)。在有不相容變更的版本中,主版本必須遞增,次要版本和修補版本必須設為 0。主版本為 0 的語意化版本被視為不穩定。

主要版本子目錄:版本控制儲存庫中的子目錄,與模組的主要版本字尾相符,模組可以在其中定義。例如,儲存庫中具有根路徑example.com/mod的模組example.com/mod/v2可以在儲存庫根目錄或主要版本子目錄v2中定義。請參閱儲存庫中的模組目錄

主要版本字尾:與主要版本號碼相符的模組路徑字尾。例如,example.com/mod/v2中的/v2。主要版本字尾在v2.0.0及之後的版本中是必需的,在較早的版本中則不允許。請參閱主要版本字尾部分。

最小版本選擇 (MVS):用於確定將在建置中使用的所有模組版本的演算法。請參閱最小版本選擇部分以取得詳細資訊。

次要版本:語意版本中的第二個數字(v1.2.3中的2)。在具有新的向下相容功能的版本中,次要版本必須遞增,且補丁版本必須設為 0。

模組:一起發布、設定版本和發行的套件集合。

模組快取:儲存在GOPATH/pkg/mod中的本地目錄,用於儲存已下載的模組。請參閱模組快取

模組圖:主模組為根的模組需求有向圖。圖中的每個頂點都是一個模組;每條邊都是go.mod檔案中require陳述式中的版本(受主模組go.mod檔案中的replaceexclude陳述式約束)。

模組圖形剪裁:Go 1.17 中的變更,透過省略指定 go 1.17 或更高版本的模組的傳遞依賴項,來減少模組圖形的尺寸。請參閱 模組圖形剪裁

模組路徑:識別模組的路徑,並作為模組中套件匯入路徑的前置詞。例如,"golang.org/x/net"

模組代理:實作 GOPROXY 協定 的網路伺服器。go 指令會從模組代理下載版本資訊、go.mod 檔案和模組 zip 檔案。

模組根目錄:包含定義模組的 go.mod 檔案的目錄。

模組子目錄:模組路徑儲存庫根路徑 之後的部份,表示定義模組的子目錄。模組子目錄在非空時,也是 語意版本標籤 的前置詞。模組子目錄不包含 主版本字尾(如果有),即使模組在 主版本子目錄 中也是如此。請參閱 模組路徑

套件:同一個目錄中會一起編譯的來源檔案集合。請參閱 Go 語言規範中的 套件區段

套件路徑:唯一識別套件的路徑。套件路徑是 模組路徑 與模組中的子目錄結合而成。例如,"golang.org/x/net/html""golang.org/x/net" 模組中 "html" 子目錄中套件的套件路徑。同義字為 匯入路徑

修補版本:語意版本中的第三個數字(v1.2.3 中的 3)。在沒有變更模組公開介面的版本中,必須遞增修補版本。

預發行版本:版本號碼後面緊接著一個破折號,然後是數個以點分隔的識別碼,例如,v1.2.3-beta4。預發行版本被視為不穩定,且不保證與其他版本相容。預發行版本會排在對應的發行版本之前:v1.2.3-pre 會在 v1.2.3 之前。另請參閱 發行版本

擬版本:編碼修訂識別碼(例如 Git commit hash)和版本控制系統中時間戳記的版本。例如,v0.0.0-20191109021931-daa7c04131f5。用於 與非模組存放庫相容,以及在沒有標記版本的情況下。

發行版本:沒有預發行後綴的版本。例如,v1.2.3,而不是 v1.2.3-pre。另請參閱 預發行版本

存放庫根路徑:模組路徑 的一部分,對應於版本控制存放庫的根目錄。請參閱 模組路徑

撤回版本:不應依賴的版本,可能是因為它過早發布,或是在發布後發現嚴重問題。請參閱 retract 指令

語意版本標籤:版本控制存放庫中的標籤,將 版本 對應到特定修訂。請參閱 將版本對應到提交

已選版本:最小版本選取 選擇的特定模組版本。已選版本是 模組圖 中找到的模組路徑的最高版本。

供應商目錄: 名為 vendor 的目錄,其中包含來自其他模組的套件,這些套件是建置主模組中套件所需要的。使用 go mod vendor 來維護。請參閱 供應商

版本: 模組不變快照的識別碼,寫成字母 v 後接語意版本。請參閱 版本 區段。

工作區: 磁碟上的一組模組,在執行 最小版本選取 (MVS) 時用作主模組。請參閱 工作區 區段。