Go Modules 參考

引言

Go 使用 Modules 來管理依賴項。

本文件是 Go 模組系統的詳細參考手冊。有關建立 Go 專案的介紹,請參閱 如何編寫 Go 程式碼。有關使用模組、將專案遷移到模組以及其他主題的資訊,請參閱從 使用 Go Modules 開始的系列部落格文章。

Modules、Packages 和 Versions

模組 (module) 是一個包的集合,它們被一起釋出、版本化和分發。模組可以直接從版本控制倉庫或從模組代理伺服器下載。

模組透過 模組路徑 (module path) 標識,該路徑在 go.mod 檔案 中宣告,幷包含有關模組依賴項的資訊。模組根目錄 (module root directory) 是包含 go.mod 檔案的目錄。主模組 (main module) 是包含呼叫 go 命令的目錄的模組。

模組中的每個 包 (package) 都是同一目錄中的原始檔集合,它們一起編譯。包路徑 (package path) 是模組路徑與包含包的子目錄(相對於模組根目錄)的組合。例如,模組 "golang.org/x/net" 在目錄 "html" 中包含一個包。該包的路徑是 "golang.org/x/net/html"

模組路徑

模組路徑 (module path) 是模組的規範名稱,透過模組的 go.mod 檔案 中的 module 指令 宣告。模組路徑是模組內包路徑的字首。

模組路徑應描述模組的功能以及在哪裡可以找到它。通常,模組路徑由倉庫根路徑、倉庫內的目錄(通常為空)和主版本字尾(僅適用於主版本 2 或更高版本)組成。

  • 倉庫根路徑 (repository root path) 是模組路徑中與開發模組的版本控制倉庫的根目錄相對應的部分。大多數模組都在其倉庫的根目錄中定義,因此這通常是整個路徑。例如,golang.org/x/net 是同名模組的倉庫根路徑。有關 go 命令如何使用派生自模組路徑的 HTTP 請求定位倉庫的資訊,請參閱 查詢模組路徑的倉庫
  • 如果模組未在倉庫的根目錄中定義,則 模組子目錄 (module subdirectory) 是模組路徑中命名目錄的部分,不包括主版本字尾。這也可以作為語義版本標籤的字首。例如,模組 golang.org/x/tools/gopls 位於根路徑為 golang.org/x/tools 的倉庫的 gopls 子目錄中,因此其模組子目錄為 gopls。請參閱 將版本對映到提交倉庫內的模組目錄
  • 如果模組釋出的主版本為 2 或更高,則模組路徑必須以 主版本字尾 結尾,例如 /v2。這可能包含也可能不包含在子目錄名稱中。例如,路徑為 golang.org/x/repo/sub/v2 的模組可能位於倉庫 golang.org/x/repo/sub/sub/v2 子目錄中。

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

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

版本

版本 (version) 標識模組的不可變快照,可以是 釋出版本 (release)預釋出版本 (pre-release)。每個版本都以字母 v 開頭,後跟一個語義版本。有關版本如何格式化、解釋和比較的詳細資訊,請參閱 語義化版本 2.0.0

總而言之,語義版本由三個非負整數(主版本、次版本和補丁版本,從左到右)組成,用點分隔。補丁版本後可能跟一個以連字元開頭的可選預釋出字串。預釋出字串或補丁版本後可能跟一個以加號開頭的構建元資料字串。例如,v0.0.0v1.12.134v8.0.5-prev2.0.9+meta 都是有效版本。

版本的每個部分都表示該版本是否穩定以及是否與以前的版本相容。

  • 在對模組的公共介面或文件功能進行向後不相容更改後,例如刪除包後,必須增加 主版本 (major version),並將次版本和補丁版本設定為零。
  • 在向後相容更改後,例如新增新函式後,必須增加 次版本 (minor version),並將補丁版本設定為零。
  • 在不影響模組公共介面的更改(例如錯誤修復或最佳化)後,必須增加 補丁版本 (patch version)
  • 預釋出字尾表示版本是 預釋出版本。預釋出版本在相應的釋出版本之前排序。例如,v1.2.3-prev1.2.3 之前。
  • 構建元資料字尾在比較版本時被忽略。go 命令接受帶有構建元資料的版本,並將它們轉換為偽版本以維持版本之間的總排序。
    • 特殊字尾 +incompatible 表示在遷移到模組主版本 2 或更高版本之前釋出的版本(請參閱 與非模組倉庫的相容性)。
    • 特殊字尾 +dirty 附加到二進位制檔案的版本資訊中,當它使用 Go toolchain 1.24 或更高版本在包含工作目錄中未提交更改的有效本地版本控制系統 (VCS) 倉庫中構建時。

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

Go 可以使用不遵循這些約定的標籤、分支或修訂版訪問版本控制系統中的模組。但是,在主模組中,go 命令會自動將不遵循此標準的修訂名稱轉換為規範版本。go 命令在此過程中還會刪除構建元資料字尾(除了 +incompatible)。這可能會導致 偽版本 (pseudo-version),這是一個預釋出版本,其中包含修訂識別符號(例如 Git 提交雜湊)和版本控制系統的時間戳。例如,命令 go get golang.org/x/net@daa7c041 將把提交雜湊 daa7c041 轉換為偽版本 v0.0.0-20191109021931-daa7c04131f5。在主模組之外需要規範版本,如果 go.mod 檔案中出現 master 等非規範版本,go 命令將報告錯誤。

偽版本

偽版本 (pseudo-version) 是一種特殊格式的 預釋出 版本,它編碼了版本控制倉庫中特定修訂版的資訊。例如,v0.0.0-20191109021931-daa7c04131f5 是一個偽版本。

偽版本可以引用沒有 語義版本標籤 可用的修訂版。例如,它們可以用於在建立版本標籤之前測試提交,例如在開發分支上。

每個偽版本有三個部分

  • 一個基本版本字首(vX.0.0vX.Y.Z-0),它要麼來自在修訂版之前的語義版本標籤,要麼在沒有此類標籤時為 vX.0.0
  • 一個時間戳(yyyymmddhhmmss),這是修訂版建立的 UTC 時間。在 Git 中,這是提交時間,而不是作者時間。
  • 一個修訂識別符號(abcdefabcdef),它是提交雜湊的 12 個字元字首,或者在 Subversion 中是零填充的修訂號。

根據基本版本,每個偽版本可以採用三種形式之一。這些形式確保偽版本與它的基本版本相比排序更高,但低於下一個帶標籤的版本。

  • 當沒有已知基本版本時,使用 vX.0.0-yyyymmddhhmmss-abcdefabcdef。與所有版本一樣,主版本 X 必須與模組的 主版本字尾 匹配。
  • 當基本版本是預釋出版本(例如 vX.Y.Z-pre)時,使用 vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
  • 當基本版本是釋出版本(例如 vX.Y.Z)時,使用 vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef。例如,如果基本版本是 v1.2.3,則偽版本可能是 v1.2.4-0.20191109021931-daa7c04131f5

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

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

  • 已知基本版本的偽版本排序高於這些版本,但低於後續版本的其他預釋出版本。
  • 相同基本版本字首的偽版本按時間順序排序。

go 命令執行多項檢查,以確保模組作者可以控制偽版本與其他版本的比較方式,並確保偽版本引用實際屬於模組提交歷史的修訂版。

  • 如果指定了基本版本,則必須有一個相應的語義版本標籤作為偽版本描述的修訂版的祖先。這可以防止開發人員使用比所有帶標籤版本都高的偽版本(例如 v1.999.999-99999999999999-daa7c04131f5)來繞過 最小版本選擇
  • 時間戳必須與修訂版的時間戳匹配。這可以防止攻擊者向 模組代理 氾濫注入無限數量的 otherwise 相同的偽版本。這還可以防止模組消費者改變版本的相對排序。
  • 該修訂版必須是模組倉庫分支或標籤的祖先之一。這可以防止攻擊者引用未經批准的更改或拉取請求。

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

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

主版本字尾

從主版本 2 開始,模組路徑必須具有與主版本匹配的 主版本字尾 (major version suffix),例如 /v2。例如,如果模組在 v1.0.0 時的路徑是 example.com/mod,則在 v2.0.0 版本時其路徑必須是 example.com/mod/v2

主版本字尾實現了 匯入相容性規則 (import compatibility rule)

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

根據定義,模組新主版本中的包與前一個主版本中的相應包不向後相容。因此,從 v2 開始,包需要新的匯入路徑。這透過向模組路徑新增主版本字尾來實現。由於模組路徑是模組中每個包的匯入路徑的字首,因此向模組路徑新增主版本字尾為每個不相容版本提供了不同的匯入路徑。

主版本字尾不允許用於主版本 v0v1v0v1 之間無需更改模組路徑,因為 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 環境變數,該變數是一個逗號分隔的代理 URL 列表或關鍵字 directoff。代理 URL 表示 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 命令可能會發出以下請求

  • 並行請求 https://corp.example.com/
    • 請求 golang.org/x/net/html 的最新版本
    • 請求 golang.org/x/net 的最新版本
    • 請求 golang.org/x 的最新版本
    • 請求 golang.org 的最新版本
  • 如果所有對 https://corp.example.com/ 的請求都以 404 或 410 失敗,則請求 https://proxy.golang.org/
    • 請求 golang.org/x/net/html 的最新版本
    • 請求 golang.org/x/net 的最新版本
    • 請求 golang.org/x 的最新版本
    • 請求 golang.org 的最新版本

找到合適的模組後,go 命令將在主模組的 go.mod 檔案中新增一個新的 要求,其中包含新模組的路徑和版本。這可確保將來載入同一包時,將使用相同版本的同一模組。如果解析後的包未被主模組中的包匯入,則新要求將帶有 // indirect 註釋。

go.mod 檔案

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

module example.com/my/thing

go 1.23.0

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 可以執行低階編輯。golang.org/x/mod/modfile 包可以由 Go 程式用於以程式設計方式進行相同的更改。

主模組 和任何指定本地檔案路徑的 替換模組 都需要 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 檔案中的大多數識別符號和字串要麼是模組路徑,要麼是版本。

模組路徑必須滿足以下要求

  • 路徑必須由一個或多個用斜槓(/,U+002F)分隔的路徑元素組成。它不能以斜槓開頭或結尾。
  • 每個路徑元素都是一個非空字串,由 ASCII 字母、ASCII 數字和有限的 ASCII 標點符號(-._~)組成。
  • 路徑元素不能以點(.,U+002E)開頭或結尾。
  • 元素字首直到第一個點不得是 Windows 上保留的檔名,無論大小寫(例如 CONcom1NuL 等)。
  • 元素字首直到第一個點不得以波浪號後跟一個或多個數字結尾(例如 EXAMPL~1.COM)。

如果模組路徑出現在 require 指令中且未被替換,或者如果模組路徑出現在 replace 指令的右側,則 go 命令可能需要下載具有該路徑的模組,並且必須滿足一些附加要求。

  • 按照慣例,開頭的路徑元素(直到第一個斜槓,如果有的話),域名,必須只包含小寫 ASCII 字母、ASCII 數字、點(.,U+002E)和破折號(-,U+002D);它必須包含至少一個點,並且不能以破折號開頭。
  • 對於形如 /vN 的最終路徑元素,其中 N 看起來是數字(ASCII 數字和點),N 不能以零開頭,不能是 /v1,並且不能包含任何點。
    • 對於以 gopkg.in/ 開頭的路徑,此要求被替換為路徑遵循 gopkg.in 服務的約定。

go.mod 檔案中的版本可以是 規範版本 或非規範版本。

規範版本以字母 v 開頭,後跟遵循 語義化版本 2.0.0 規範的語義版本。有關更多資訊,請參閱 版本

大多數其他識別符號和字串可以用作非規範版本,儘管有一些限制,以避免檔案系統、倉庫和 模組代理 的問題。非規範版本僅允許出現在主模組的 go.mod 檔案中。當 go 命令自動 更新 go.mod 檔案時,它會嘗試將每個非規範版本替換為等效的規範版本。

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

語法

go.mod 語法使用擴充套件巴克斯-諾爾正規化 (EBNF) 在下面指定。有關 EBNF 語法的詳細資訊,請參閱 Go 語言規範中的表示法部分

GoMod = { Directive } .
Directive = ModuleDirective |
            GoDirective |
            ToolDirective |
            IgnoreDirective |
            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.141.21rc11.23.0

go 指令設定使用此模組所需的最低 Go 版本。在 Go 1.21 之前,此指令僅是建議性的;現在它是一個強制性要求:Go toolchain 拒絕使用聲明瞭更新 Go 版本的模組。

go 指令是選擇要執行的 Go toolchain 的輸入。有關詳細資訊,請參閱“Go toolchain”。

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

  • 對於模組內的包,編譯器會拒絕使用在 go 指令指定版本之後引入的語言功能。例如,如果模組具有指令 go 1.12,則其包不能使用像 1_000_000 這樣的數字文字,這些數字文字是在 Go 1.13 中引入的。
  • 如果一個較舊的 Go 版本構建模組的某個包並遇到編譯錯誤,則錯誤會指出該模組是為較新的 Go 版本編寫的。例如,假設一個模組有 go 1.13 並且一個包使用了數字文字 1_000_000。如果該包使用 Go 1.12 構建,編譯器會指出該程式碼是為 Go 1.13 編寫的。

go 指令還會影響 go 命令的行為

  • go 1.14 或更高版本中,可能會啟用自動 vendoring。如果檔案 vendor/modules.txt 存在且與 go.mod 一致,則無需顯式使用 -mod=vendor 標誌。
  • go 1.16 或更高版本中,all 包模式僅匹配由 主模組 中的包和測試傳遞匯入的包。這與自模組引入以來 go mod vendor 保留的包集相同。在較低版本中,all 還包括由主模組中的包匯入的包的測試,以及這些包的測試,等等。
  • go 1.17 或更高版本中
    • go.mod 檔案包含一個顯式的 require 指令,用於提供主模組中包或測試(甚至 間接)傳遞匯入的任何包的每個模組。(在 go 1.16 及更低版本中,僅當 最小版本選擇 會選擇不同版本時,才會包含間接依賴項。)這些額外資訊支援 模組圖修剪惰性模組載入
    • 因為 // indirect 依賴項可能比以前的 go 版本多得多,所以間接依賴項記錄在 go.mod 檔案中的單獨塊中。
    • go mod vendor 會省略 vendored 依賴項的 go.modgo.sum 檔案。(這允許在 vendor 的子目錄中呼叫 go 命令來識別正確的主模組。)
    • go mod vendor 將每個依賴項的 go.mod 檔案中的 go 版本記錄在 vendor/modules.txt 中。
  • go 1.21 或更高版本中
    • go 行聲明瞭使用此模組所需的最低 Go 版本。
    • go 行必須大於或等於所有依賴項的 go 行。
    • go 命令不再嘗試保持與以前舊版 Go 的相容性。
    • go 命令更謹慎地維護 go.sum 檔案中 go.mod 檔案的校驗和。

一個 go.mod 檔案最多包含一個 go 指令。如果不存在 go 指令,大多數命令都會新增一個帶有當前 Go 版本的 go 指令。

如果缺少 go 指令,則假定為 go 1.16

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

示例

go 1.23.0

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

godebug 指令

godebug 指令宣告一個要在此模組作為主模組時應用的 GODEBUG 設定。可以有多個這樣的行,並且它們可以被分解。主模組命名不存在的 GODEBUG 鍵是一個錯誤。godebug key=value 的效果就像每個正在編譯的主包都包含一個原始檔,其中列出了 //go:debug key=value

GodebugDirective = "godebug" ( GodebugSpec | "(" newline { GodebugSpec } ")" newline ) .
GodebugSpec = GodebugKey "=" GodebugValue newline.
GodebugKey = GodebugChar { GodebugChar }.
GodebugValue = GodebugChar { GodebugChar }.
GodebugChar = any non-space character except , " ` ' (comma and quotes).

示例

godebug default=go1.21
godebug (
    panicnil=1
    asynctimerchan=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
)

tool 指令

tool 指令將一個包新增為當前模組的依賴項。噹噹前工作目錄位於此模組內,或者位於包含此模組的工作區內時,它還可以透過 go tool 執行。

如果工具包不在當前模組中,則必須存在一個 require 指令來指定要使用的工具版本。

tool 元模式解析為當前模組的 go.mod 中定義的工具列表,或者在工作區模式下解析為工作區中所有模組中定義的所有工具的並集。

ToolDirective = "tool" ( ToolSpec | "(" newline { ToolSpec } ")" newline ) .
ToolSpec = ModulePath newline .

示例

tool golang.org/x/tools/cmd/stringer

tool (
    example.com/module/cmd/a
    example.com/module/cmd/b
)

ignore 指令

ignore 指令將導致 go 命令在匹配包模式時忽略斜槓分隔的目錄路徑以及其中遞迴包含的任何檔案或目錄。

如果路徑以 ./ 開頭,則路徑被解釋為相對於模組根目錄,並且在匹配包模式時將忽略該目錄以及其中遞迴包含的任何目錄或檔案。

否則,模組中任何深度下具有該路徑的任何目錄,以及其中遞迴包含的任何目錄或檔案都將被忽略。

IgnoreDirective = "ignore" ( IgnoreSpec | "(" newline { IgnoreSpec } ")" newline ) .
IgnoreSpec = RelativeFilePath newline .
RelativeFilePath = /* slash-separated relative file path */ .

示例

ignore ./node_modules

ignore (
    static
    content/html
    ./third_party/javascript
)

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 中刪除或覆蓋。

請注意,單獨的 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 更新相關模組時會收到撤回通知。

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

撤回的版本不會顯示在 go list -m -versions 列印的版本列表中,除非使用 -retracted 標誌。在解析諸如 @>=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.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 .

示例

  • 撤回 v1.0.0v1.9.9 之間的所有版本
retract v1.0.0
retract [v1.0.0, v1.9.9]
retract (
    v1.0.0
    [v1.0.0, v1.9.9]
)
  • 在過早釋出 v1.0.0 版本後恢復到未版本化
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.

Go 1.16 中添加了 retract 指令。Go 1.15 及更低版本如果主模組的 go.mod 檔案中包含 retract 指令,則會報告錯誤,並忽略依賴項的 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.23.0

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 觸發的更新將非規範版本識別符號重寫為 規範 語義版本形式,因此 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 在每個支援模組的命令開始時用於計算它。

考慮下圖中的示例。主模組要求模組 A 的版本為 1.2 或更高,模組 B 的版本為 1.2 或更高。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.17go.mod 檔案包含一個 require 指令,用於構建該模組中任何包或測試所需的所有依賴項,因此修剪後的模組圖包含構建或測試 主模組 顯式要求的任何依賴項中的包所需的所有依賴項。一個不需要構建給定模組中任何包或測試的模組不會影響其包的執行時行為,因此從模組圖中修剪掉的依賴項只會導致否則不相關的模組之間發生干擾。

其要求已被修剪掉的模組仍然出現在模組圖中,並且仍然由 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 檔案,並檢查它們的要求是否與主模組的要求區域性一致。(由於版本控制合併、手動編輯以及使用本地檔案系統路徑 替換 的模組更改,可能會出現不一致。)

工作區

工作區 (workspace) 是磁碟上模組的集合,當執行 最小版本選擇 (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.23.0

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 執行低階編輯。golang.org/x/mod/modfile 包可以由 Go 程式用於以程式設計方式進行相同的更改。

go 命令將維護一個 go.work.sum 檔案,用於跟蹤工作區使用的、未包含在集體工作區模組的 go.sum 檔案中的雜湊值。

通常不建議將 go.work 檔案提交到版本控制系統,原因有兩個

  • 已簽入的 go.work 檔案可能會覆蓋開發人員從父目錄中自己的 go.work 檔案,導致他們的 use 指令不適用時產生混淆。
  • 已簽入的 go.work 檔案可能會導致持續整合 (CI) 系統選擇並因此測試模組依賴項的錯誤版本。CI 系統通常不應被允許使用 go.work 檔案,以便它們可以測試模組在被其他模組需要時的行為,其中模組內的 go.work 檔案無效。

話雖如此,在某些情況下提交 go.work 檔案是有意義的。例如,當倉庫中的模組僅相互開發,而不與外部模組一起開發時,開發人員可能沒有理由希望在工作區中使用不同組合的模組。在這種情況下,模組作者應確保單獨的模組得到正確測試和釋出。

詞法元素

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.23.0

toolchain 指令

toolchain 指令聲明瞭在工作區中使用的建議 Go 工具鏈。它僅在預設工具鏈比建議工具鏈舊時才有效。

有關詳細資訊,請參閱“Go 工具鏈”。

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

示例

toolchain go1.21.0

godebug 指令

godebug 指令宣告一個要在此工作區中工作時應用的 GODEBUG 設定。其語法和效果與 go.mod 檔案的 godebug 指令 相同。當使用工作區時,go.mod 檔案中的 godebug 指令將被忽略。

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 命令會將 +incompatible 字尾新增到沒有 go.mod 檔案的主版本為 2 或更高版本的版本。+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 模式下解析為目錄時

  • 當解析形式為 $modpath/$vn/$dir 的匯入時,其中
    • $modpath 是有效的模組路徑,
    • $vn 是主版本字尾,
    • $dir 是可能為空的子目錄,
  • 如果以下所有條件都為真
    • $modpath/$vn/$dir 不存在於任何相關的vendor 目錄中。
    • 一個 go.mod 檔案存在於匯入檔案所在的目錄或其父目錄中,直到 $GOPATH/src 根目錄,
    • 不存在 $GOPATH[i]/src/$modpath/$vn/$suffix 目錄(對於任何根目錄 $GOPATH[i]),
    • 檔案 $GOPATH[d]/src/$modpath/go.mod 存在(對於某些根目錄 $GOPATH[d])並宣告模組路徑為 $modpath/$vn
  • 那麼 $modpath/$vn/$dir 的匯入將被解析到目錄 $GOPATH[d]/src/$modpath/$dir

這些規則允許已遷移到模組的包,在 GOPATH 模式下構建時,即使未使用主版本子目錄,也能匯入已遷移到模組的其他包。

模組感知命令

大多數 go 命令可以在模組感知模式GOPATH 模式下執行。在模組感知模式下,go 命令使用 go.mod 檔案查詢版本化的依賴項,並且它通常從模組快取中載入包,如果模組缺失則會下載。在 GOPATH 模式下,go 命令忽略模組;它會在vendor 目錄GOPATH 中查詢依賴項。

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

模組感知模式可以透過 GO111MODULE 環境變數控制,該變數可以設定為 onoffauto

  • 如果 GO111MODULE=offgo 命令會忽略 go.mod 檔案,並以 GOPATH 模式執行。
  • 如果 GO111MODULE=on 或未設定,go 命令將以模組感知模式執行,即使不存在 go.mod 檔案。並非所有命令在沒有 go.mod 檔案的情況下都能工作:請參閱模組外部的模組命令
  • 如果 GO111MODULE=auto,噹噹前目錄或任何父目錄中存在 go.mod 檔案時,go 命令將以模組感知模式執行。在 Go 1.15 及更低版本中,這是預設行為。go mod 子命令和帶有版本查詢go install 命令即使沒有 go.mod 檔案也會以模組感知模式執行。

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

構建命令

所有載入包資訊的命令都支援模組。這包括

  • go build
  • go fix
  • go generate
  • go install
  • go list
  • go run
  • go test
  • go vet

當在模組感知模式下執行時,這些命令使用 go.mod 檔案來解釋命令列上列出或 Go 原始檔中寫入的匯入路徑。這些命令接受以下所有模組命令通用的標誌。

  • -mod 標誌控制 go.mod 是否可以自動更新以及是否使用 vendor 目錄。
    • -mod=mod 指示 go 命令忽略 vendor 目錄並自動更新 go.mod,例如,當匯入的包沒有由任何已知模組提供時。
    • -mod=readonly 告訴 go 命令忽略 vendor 目錄,並在 go.mod 需要更新時報告錯誤。
    • -mod=vendor 告訴 go 命令使用 vendor 目錄。在此模式下,go 命令將不使用網路或模組快取。
    • 預設情況下,如果 go.mod 中的 go 版本1.14 或更高版本並且存在 vendor 目錄,則 go 命令的行為與使用 -mod=vendor 相同。否則,go 命令的行為與使用 -mod=readonly 相同。
    • go get 拒絕此標誌,因為此命令的目的是修改依賴項,這隻能透過 -mod=mod 允許。
  • -modcacherw 標誌指示 go 命令在模組快取中建立具有讀寫許可權的新目錄,而不是將它們設定為只讀。當一致地使用此標誌時(通常透過在環境變數中設定 GOFLAGS=-modcacherw 或執行 go env -w GOFLAGS=-modcacherw),可以使用 rm -r 等命令刪除模組快取,而無需先更改許可權。go clean -modcache 命令可用於刪除模組快取,無論是否使用了 -modcacherw
  • -modfile=file.mod 標誌指示 go 命令讀取(並可能寫入)一個備用檔案,而不是模組根目錄中的 go.mod。檔名必須以 .mod 結尾。仍必須存在名為 go.mod 的檔案才能確定模組根目錄,但不會訪問它。指定 -modfile 時,也會使用備用 go.sum 檔案:其路徑透過從 -modfile 標誌中刪除 .mod 副檔名並附加 .sum 派生。

Vendoring(供應商化)

使用模組時,go 命令通常透過從源下載模組到模組快取中來滿足依賴項,然後從這些下載的副本中載入包。Vendoring 可用於與 Go 的舊版本進行互操作,或確保構建使用的所有檔案都儲存在單個檔案樹中。

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

go mod vendor 還會建立檔案 vendor/modules.txt,其中包含 vendored 包的列表以及它們從中複製的模組版本。啟用 vendoring 時,此清單用作模組版本資訊的來源,如 go list -mgo version -m 所報告。當 go 命令讀取 vendor/modules.txt 時,它會檢查模組版本是否與 go.mod 一致。如果自生成 vendor/modules.txt 以來 go.mod 已更改,go 命令將報告錯誤。應再次執行 go mod vendor 以更新 vendor 目錄。

如果 vendor 目錄存在於主模組的根目錄中,並且主模組的 go.mod 檔案中的 go 版本1.14 或更高,它將自動使用。要顯式啟用 vendoring,請使用 -mod=vendor 標誌呼叫 go 命令。要停用 vendoring,請使用 -mod=readonly-mod=mod 標誌。

啟用 vendoring 後,構建命令(如 go buildgo test)會從 vendor 目錄載入包,而不是訪問網路或本地模組快取。go list -m 命令只打印 go.mod 中列出的模組資訊。go mod 命令(如go mod downloadgo mod tidy)在啟用 vendoring 時不會有不同的工作方式,仍會下載模組並訪問模組快取。go get 在啟用 vendoring 時也不會有不同的工作方式。

GOPATH 模式下的 vendoring 不同,go 命令會忽略主模組根目錄以外位置的 vendor 目錄。此外,由於不使用其他模組中的 vendor 目錄,go 命令在構建模組 zip 檔案時不會包含 vendor 目錄(但請參閱已知 bug #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.0,則 go 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 支援以下標誌

  • -d 標誌告訴 go get 不要構建或安裝包。當使用 -d 時,go get 只管理 go.mod 中的依賴項。不帶 -d 使用 go get 來構建和安裝包已被棄用(從 Go 1.17 開始)。在 Go 1.18 中,-d 將始終啟用。
  • -u 標誌告訴 go get 升級提供命令列上命名包直接或間接匯入的模組。透過 -u 選擇的每個模組都將升級到其最新版本,除非它已被更高版本(預釋出版本)要求。
  • -u=patch 標誌(不是 -u patch)也指示 go get 升級依賴項,但 go get 會將每個依賴項升級到最新的補丁版本(類似於 @patch 版本查詢)。
  • -t 標誌告訴 go get 考慮構建命令列上命名包的測試所需的模組。當 -t-u 一起使用時,go get 也會更新測試依賴項。
  • -insecure 標誌不應再使用。它允許 go get 解析自定義匯入路徑並使用不安全的方案(如 HTTP)從倉庫和模組代理獲取。GOINSECURE 環境變數提供了更精細的控制,應改用它。

從 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 檔案(如果存在)。這對於安裝可執行檔案而不會影響主模組的依賴項非常有用。

為了消除構建中使用的模組版本的歧義,引數必須滿足以下約束

  • 引數必須是包路徑或包模式(帶有“...”萬用字元)。它們不能是標準包(如 fmt)、元模式(stdcmdallworktool),或相對或絕對檔案路徑。
  • 所有引數必須具有相同的版本字尾。不允許使用不同的查詢,即使它們指向相同的版本。
  • 所有引數必須指同一模組的同一版本中的包。
  • 包路徑引數必須指向 main 包。模式引數將只匹配 main 包。
  • 不將任何模組視為主模組。
    • 如果包含命令列上命名包的模組有 go.mod 檔案,則它不能包含(replaceexclude)指令,否則如果它作為主模組,則會被不同地解釋。
    • 該模組不能要求其自身的更高版本。
    • 在任何模組中都不使用 Vendor 目錄。(Vendor 目錄不包含在模組 zip 檔案中,因此 go install 不會下載它們。)

有關支援的版本查詢語法,請參閱版本查詢。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 非空,則 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 結構體。如果發生錯誤,結果將是一個 Module 結構體,其 Error 欄位非空。

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 檔案,但可以在編輯標誌之後指定不同的目標檔案。

編輯標誌指定了一系列編輯操作。

  • -module 標誌更改模組的路徑(go.mod 檔案的模組行)。
  • -go=version 標誌設定預期的 Go 語言版本。
  • -require=path@version-droprequire=path 標誌新增和刪除對給定模組路徑和版本的依賴。請注意,-require 會覆蓋對 path 的任何現有依賴。這些標誌主要用於理解模組圖的工具。使用者應首選 go get path@versiongo get path@none,它們會根據需要進行其他 go.mod 調整以滿足其他模組施加的約束。請參閱go get
  • -exclude=path@version-dropexclude=path@version 標誌新增和刪除對給定模組路徑和版本的排除項。請注意,如果該排除項已存在,-exclude=path@version 將不執行任何操作。
  • -replace=old[@v]=new[@v] 標誌新增給定模組路徑和版本對的替換。如果 old@v 中的 @v 被省略,則新增一個左側沒有版本的替換,它適用於舊模組路徑的所有版本。如果 new@v 中的 @v 被省略,則新路徑應為本地模組根目錄,而不是模組路徑。請注意,-replace 會覆蓋 old[@v] 的任何冗餘替換,因此省略 @v 將刪除特定版本的替換。
  • -dropreplace=old[@v] 標誌刪除給定模組路徑和版本對的替換。如果提供了 @v,則刪除具有給定版本的替換。左側沒有版本的現有替換仍可能替換模組。如果省略了 @v,則刪除沒有版本的替換。
  • -retract=version-dropretract=version 標誌新增和刪除給定版本的撤回,該版本可以是單個版本(如 v1.2.3)或一個區間(如 [v1.1.0,v1.2.0])。請注意,-retract 標誌無法為 retract 指令新增理由註釋。推薦使用理由註釋,並且它們可能會由 go list -m -u 和其他命令顯示。
  • -tool=path-droptool=path 標誌新增和刪除給定路徑的 tool 指令。請注意,這不會向構建圖新增必要的依賴項。使用者應首選 go get -tool path 來新增工具,或 go get -tool path@none 來刪除工具。

編輯標誌可以重複。更改按給定順序應用。

go mod edit 還有控制其輸出的附加標誌。

  • -fmt 標誌重新格式化 go.mod 檔案而不進行其他更改。此重新格式化也由任何其他使用或重寫 go.mod 檔案的修改所隱含。此標誌僅在未指定其他標誌時才需要,例如 go mod edit -fmt
  • -print 標誌以文字格式列印最終的 go.mod,而不是將其寫回磁碟。
  • -json 標誌以 JSON 格式列印最終的 go.mod,而不是以文字格式寫回磁碟。JSON 輸出對應於這些 Go 型別
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
}

type Tool struct {
    Path      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 中)推斷模組路徑。

go mod tidy

用法

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

go mod tidy 確保 go.mod 檔案與模組中的原始碼匹配。它新增構建當前模組的包和依賴項所需的任何缺失模組依賴項,並刪除對不提供任何相關包的模組的依賴項。它還向 go.sum 新增任何缺失條目並刪除不必要的條目。

-e 標誌(Go 1.16 中新增)使 go mod tidy 嘗試在載入包時遇到錯誤的情況下繼續進行。

-v 標誌使 go mod tidy 將有關已刪除模組的資訊列印到標準錯誤。

-x 標誌使 go mod tidy 列印 tidy 執行的命令。

-diff 標誌使 go mod tidy 不修改 go.mod 或 go.sum,而是將必要的更改列印為統一的 diff。如果 diff 不為空,則以非零程式碼退出。

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 註釋表示一個不提供主模組中包匯入的包的模組。(有關何時新增 // indirect 依賴項和註釋的更多詳細資訊,請參閱require 指令。)

如果設定了 -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 之外的構建約束

啟用 vendoring 後,go 命令將從 vendor 目錄載入包,而不是從其源下載模組到模組快取並使用那些下載的包。有關更多資訊,請參閱Vendoring

go mod vendor 還會建立檔案 vendor/modules.txt,其中包含 vendored 包的列表以及它們從中複製的模組版本。啟用 vendoring 時,此清單用作模組版本資訊的來源,如 go list -mgo version -m 所報告。當 go 命令讀取 vendor/modules.txt 時,它會檢查模組版本是否與 go.mod 一致。如果自生成 vendor/modules.txt 以來 go.mod 已更改,應再次執行 go mod vendor

請注意,如果 vendor 目錄存在,go mod vendor 會在重新構建之前刪除它。不應對 vendored 包進行本地更改。go 命令不檢查 vendor 目錄中的包是否已修改,但可以透過執行 go mod vendor 並檢查是否未進行任何更改來驗證 vendor 目錄的完整性。

-e 標誌(Go 1.16 中新增)使 go mod vendor 嘗試在載入包時遇到錯誤的情況下繼續進行。

-v 標誌使 go mod vendor 將 vendored 模組和包的名稱列印到標準錯誤。

-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 會列印“all modules verified”。否則,它會報告哪些模組已更改並以非零狀態退出。

請注意,所有模組感知命令都會驗證主模組 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 會列印一個包含製表符分隔列的表格,如下所示。

$ 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 獲得。

表中每行的含義由第一列中的單詞確定。

  • path: 用於構建可執行檔案的 main 包的路徑。
  • mod: 包含 main 包的模組。列分別是模組路徑、版本和校驗和。主模組的版本為 (devel),沒有校驗和。
  • dep: 提供一個或多個連結到可執行檔案中的包的模組。格式與 mod 相同。
  • =>: 上一行的模組的替換。如果替換是本地目錄,則只列出目錄路徑(無版本或校驗和)。如果替換是模組版本,則列出路徑、版本和校驗和,與 moddep 相同。被替換的模組沒有校驗和。

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

版本查詢可以是以下之一

  • 一個完全指定的語義版本,例如 v1.2.3,它選擇一個特定版本。有關語法,請參閱版本
  • 語義版本字首,例如 v1v1.2,它選擇具有該字首的最高可用版本。
  • 語義版本比較,例如 <v1.2.3>=v1.5.6,它選擇最接近比較目標的可用版本(>>= 的最低版本,<<= 的最高版本)。
  • 底層原始碼倉庫的修訂識別符號,例如提交雜湊字首、修訂標籤或分支名稱。如果修訂用語義版本標記,則此查詢選擇該版本。否則,此查詢選擇底層提交的偽版本。請注意,名稱與其他版本查詢匹配的分支和標籤不能以這種方式選擇。例如,查詢 v2 選擇以 v2 開頭的最新版本,而不是名為 v2 的分支。
  • 字串 latest,它選擇可用的最高發布版本。如果沒有釋出版本,latest 會選擇最高的預釋出版本。如果沒有標記版本,latest 會選擇倉庫預設分支尖端提交的偽版本。
  • 字串 upgrade,與 latest 類似,但如果模組當前要求的版本高於 latest 將選擇的版本(例如,預釋出版本),upgrade 將選擇當前版本。
  • 字串 patch,它選擇與當前所需版本具有相同主版本和次版本號的最新可用版本。如果當前未要求任何版本,則 patch 等同於 latest。自 Go 1.16 以來,go get 在使用 patch 時需要當前版本(但 -u=patch 標誌沒有此要求)。

除了針對特定命名版本或修訂的查詢外,所有查詢都考慮 go list -m -versions 報告的可用版本(請參閱go list -m)。此列表僅包含標記版本,不包含偽版本。主模組的go.mod 檔案exclude 指令不允許的模組版本不予考慮。同一模組的 latest 版本的 go.mod 檔案中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 檔案中的 use 指令。當前的 go 版本也將列在 go.work 檔案中。

go work edit

用法

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

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

編輯標誌指定了一系列編輯操作。

  • -fmt 標誌重新格式化 go.work 檔案而不進行其他更改。這種重新格式化也由任何其他使用或重寫 go.work 檔案的修改所隱含。此標誌僅在未指定其他標誌時才需要,例如“go work edit -fmt”。
  • -use=path-dropuse=path 標誌從 go.work 檔案的模組目錄集中新增和刪除 use 指令。
  • -replace=old[@v]=new[@v] 標誌新增給定模組路徑和版本對的替換。如果 old@v 中的 @v 被省略,則新增一個左側沒有版本的替換,它適用於舊模組路徑的所有版本。如果 new@v 中的 @v 被省略,則新路徑應為本地模組根目錄,而不是模組路徑。請注意,-replace 會覆蓋 old[@v] 的任何冗餘替換,因此省略 @v 將刪除特定版本的現有替換。
  • -dropreplace=old[@v] 標誌刪除給定模組路徑和版本對的替換。如果省略 @v,則刪除左側沒有版本的替換。
  • -go=version 標誌設定預期的 Go 語言版本。

編輯標誌可以重複。更改按給定順序應用。

go work edit 還有控制其輸出的附加標誌

  • -print 標誌以其文字格式列印最終的 go.work,而不是將其寫回 go.mod。
  • -json 標誌以 JSON 格式列印最終的 go.work 檔案,而不是以文字格式寫回 go.mod。JSON 輸出對應於這些 Go 型別
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 檔案。

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

-r 標誌在引數目錄中遞迴搜尋模組,並且 use 命令的操作就像每個目錄都已指定為引數一樣。

go work sync

用法

go work sync

go work sync 命令將工作區的構建列表同步回工作區的模組。

工作區的構建列表是工作區中用於構建的所有(傳遞)依賴模組的版本集。go work sync 使用最小版本選擇 (MVS) 演算法生成該構建列表,然後將這些版本同步回工作區中指定的每個模組(透過 use 指令)。

一旦計算出工作區構建列表,工作區中每個模組的 go.mod 檔案都會被重寫,其中與該模組相關的依賴項升級以匹配工作區構建列表。請注意,最小版本選擇保證每個模組的構建列表版本始終與每個工作區模組中的版本相同或更高。

模組代理

GOPROXY 協議

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

成功的 HTTP 響應必須具有狀態碼 200 (OK)。重定向 (3xx) 會被跟蹤。狀態碼 4xx 和 5xx 的響應被視為錯誤。錯誤碼 404 (Not Found) 和 410 (Gone) 表示請求的模組或版本在代理上不可用,但可能在其他地方找到。錯誤響應的內容型別應為 text/plain,字元集為 utf-8us-ascii

go 命令可以配置為使用 GOPROXY 環境變數聯絡代理或原始碼管理伺服器,該變數接受代理 URL 列表。該列表可以包含關鍵字 directoff(有關詳細資訊,請參閱環境變數)。列表元素可以透過逗號 (,) 或管道 (|) 分隔,這決定了錯誤回退行為。當 URL 後跟逗號時,go 命令僅在收到 404 (Not Found) 或 410 (Gone) 響應後才會回退到後續來源。當 URL 後跟管道時,go 命令會在任何錯誤(包括超時等非 HTTP 錯誤)後回退到後續來源。這種錯誤處理行為允許代理充當未知模組的看門人。例如,代理可以對不在批准列表上的模組響應錯誤 403 (Forbidden)(請參閱為私有模組提供服務的私有代理)。

下表指定了模組代理必須響應的查詢。對於每個路徑,$base 是代理 URL 的路徑部分,$module 是模組路徑,$version 是版本。例如,如果代理 URL 是 https://example.com/mod,並且客戶端正在請求模組 golang.org/x/text 版本 v0.3.2go.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 相同。最新版本應該是 go 命令在 $base/$module/@v/list 為空或沒有列出的版本合適時應使用的模組版本。此端點是可選的,模組代理不需要實現它。

在解析模組的最新版本時,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.mod 檔案並執行最小版本選擇 (MVS) 計算構建列表
  • 讀取命令列上命名的包及其匯入的包。
  • 如果包未由構建列表中的任何模組提供,則查詢提供該包的模組。在 go.mod 中新增對其最新版本的模組要求,然後重新開始。
  • 所有內容載入後構建包。

go 命令計算構建列表時,它會載入模組圖中每個模組的 go.mod 檔案。如果 go.mod 檔案不在快取中,go 命令將使用 $module/@v/$version.mod 請求從代理下載它(其中 $module 是模組路徑,$version 是版本)。這些請求可以使用 curl 等工具進行測試。例如,以下命令下載 golang.org/x/mod 版本 v0.2.0go.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 命令嘗試下載版本 v1.0.0 的模組 example.com/gopher。它會向 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 處的倉庫,預期會在 bar 子目錄中找到該模組。go 命令將根據版本控制工具支援的協議猜測要使用的協議。

如果模組路徑沒有限定符,go 命令會向從模組路徑派生的 URL 傳送 HTTP GET 請求,並帶有一個 ?go-get=1 查詢字串。例如,對於模組 golang.org/x/modgo 命令可能會發送以下請求

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

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

伺服器必須響應一個包含 <head><meta> 標籤的 HTML 文件。<meta> 標籤應在文件早期出現,以避免混淆 go 命令的受限解析器。特別是,它應出現在任何原始 JavaScript 或 CSS 之前。<meta> 標籤必須採用以下形式

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

root-path 是倉庫根路徑,即模組路徑中對應於倉庫根目錄的部分,如果存在 subdirectory 且使用 Go 1.25 或更高版本(請參閱下面的 subdirectory 部分),則對應於 subdirectory。它必須是請求模組路徑的字首或精確匹配。如果不是精確匹配,則會為該字首發出另一個請求以驗證 <meta> 標籤是否匹配。

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

repo-url 是倉庫的 URL。如果 URL 不包含方案(要麼是因為模組路徑具有 VCS 限定符,要麼是因為 <meta> 標籤缺少方案),go 命令將嘗試版本控制系統支援的每種協議。例如,對於 Git,go 命令將嘗試 https://,然後是 git+ssh://。不安全協議(如 http://git://)只能在模組路徑與 GOINSECURE 環境變數匹配時使用。

如果存在 subdirectory,它是倉庫的斜槓分隔的子目錄,root-path 對應於該子目錄,覆蓋了倉庫根目錄的預設值。提供 subdirectorygo-import meta 標籤僅由 Go 1.25 及更高版本識別。在早期 Go 版本上嘗試獲取解析模組將忽略 meta 標籤,如果模組無法在其他地方解析,則會導致解析失敗。

名稱 命令 GOVCS 預設值 安全方案
Bazaar bzr 僅限私有 https, bzr+ssh
Fossil fossil 僅限私有 https
Git git 公共和私有 https, git+ssh, ssh
Mercurial hg 公共和私有 https, ssh
Subversion svn 僅限私有 https, svn+ssh

再次以 golang.org/x/mod 為例。go 命令會向 https://golang.org.tw/x/mod?go-get=1 傳送請求。伺服器響應的 HTML 文件包含標籤

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

根據此響應,go 命令將使用遠端 URL 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 定義在根路徑為 golang.org/x/tools 的倉庫的 gopls 子目錄中。該模組的 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.2 之前的 v1.3.1)是否對應於作為提交祖先的語義版本標籤。這些檢查確保模組作者完全控制偽版本如何與其他已釋出版本進行比較。

有關更多資訊,請參閱 偽版本

將分支和提交對映到版本

可以使用 版本查詢簽出特定分支、標籤或修訂版處的模組。

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 檔案時,如果模組的根目錄(與 go.mod 並列)中沒有名為 LICENSE 的檔案,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),並且僅在私有模組或映象拒絕提供公共包(通常出於法律原因)時才回退到版本控制。因此,客戶端仍然可以透過 Go 模組映象預設訪問從 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 檔案及其在模組快取中提取內容的 location。

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

檔案路徑和大小限制

模組 zip 檔案的內容有許多限制。這些約束確保 zip 檔案可以在各種平臺上安全一致地提取。

  • 模組 zip 檔案大小不得超過 500 MiB。其檔案的總未壓縮大小也限制為 500 MiB。go.mod 檔案限制為 16 MiB。LICENSE 檔案也限制為 16 MiB。這些限制旨在減輕對使用者、代理和模組生態系統其他部分的拒絕服務攻擊。在模組目錄樹中包含超過 500 MiB 檔案的倉庫應在僅包含構建模組包所需檔案的提交處標記模組版本;影片、模型和其他大型資產通常不需要用於構建。
  • 模組 zip 檔案中的每個檔案都必須以 $module@$version/ 字首開頭,其中 $module 是模組路徑,$version 是版本,例如 golang.org/x/mod@v0.3.0/。模組路徑必須有效,版本必須有效且規範,並且版本必須與模組路徑的主要版本字尾匹配。有關具體定義和限制,請參閱 模組路徑和版本
  • 檔案模式、時間戳和其他元資料將被忽略。
  • 空目錄(路徑以斜槓結尾的條目)可以包含在模組 zip 檔案中,但不會被提取。go 命令在建立 zip 檔案時不包含空目錄。
  • 在建立 zip 檔案時,符號連結和其他不規則檔案將被忽略,因為它們不能跨作業系統和檔案系統移植,並且在 zip 檔案格式中沒有可移植的方式來表示它們。
  • 在建立 zip 檔案時,vendor 目錄中的檔案將被忽略,因為主模組之外的 vendor 目錄從不使用。
  • 在建立 zip 檔案時,除了模組根目錄之外,包含 go.mod 檔案的目錄中的檔案將被忽略,因為它們不屬於該模組。go 命令在提取 zip 檔案時會忽略包含 go.mod 檔案的子目錄。
  • zip 檔案中沒有兩個檔案的路徑在 Unicode 大小寫摺疊下相等(請參閱 strings.EqualFold)。這確保 zip 檔案可以在不區分大小寫的檔案系統上提取而不會發生衝突。
  • go.mod 檔案可能出現在頂級目錄($module@$version/go.mod)中,也可能不出現。如果存在,它必須命名為 go.mod(全部小寫)。其他任何目錄中都不允許名為 go.mod 的檔案。
  • 模組中的檔案和目錄名可以由 Unicode 字母、ASCII 數字、ASCII 空格字元 (U+0020) 以及 ASCII 標點符號 !#$%&()+,-.=@[]^_{}~ 組成。請注意,包路徑可能不包含所有這些字元。有關差異,請參閱 module.CheckFilePathmodule.CheckImportPath
  • 檔案或目錄名直到第一個點必須不是 Windows 上的保留檔名,無論大小寫(例如 CONcom1NuL 等)。

私有模組

Go 模組經常在公共網際網路上不可用的版本控制伺服器和模組代理上開發和分發。go 命令可以從私有源下載和構建模組,儘管通常需要一些配置。

下面的環境變數可用於配置對私有模組的訪問。有關詳細資訊,請參閱 環境變數。另請參閱 隱私,瞭解有關控制傳送到公共伺服器的資訊。

  • GOPROXY — 模組代理 URL 列表。go 命令將嘗試按順序從列表中的每個伺服器下載模組。關鍵字 direct 指示 go 命令從它們開發的版本控制倉庫下載模組,而不是使用代理。
  • GOPRIVATE — glob 模式的模組路徑字首列表,應被視為私有。作為 GONOPROXYGONOSUMDB 的預設值。
  • GONOPROXY — glob 模式的模組路徑字首列表,不應從代理下載。go 命令將從它們開發的版本控制倉庫下載匹配的模組,無論 GOPROXY 如何。
  • GONOSUMDB — glob 模式的模組路徑字首列表,不應使用公共校驗和資料庫 sum.golang.org 檢查。
  • GOINSECURE — glob 模式的模組路徑字首列表,可以透過 HTTP 和其他不安全協議檢索。

這些變數可以在開發環境中設定(例如,在 .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 時,它將向 https://corp.example.com/mod?go-get=1 傳送 GET 請求,並將在響應中查詢倉庫 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,並且版本控制工具不需要互動式輸入密碼。除非在 查詢倉庫 URL 時指定了方案,否則 go 命令傾向於 https:// URL 而不是其他方案(如 ssh://)。對於 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.sum 中,否則 go 命令不會驗證它們。請參閱 驗證模組

模組快取

模組快取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 引用時用作代理。
cache/download/$module/@v/list 已知版本列表(請參閱 GOPROXY 協議)。這可能會隨時間變化,因此 go 命令通常會獲取新副本而不是重用此檔案。
cache/download/$module/@v/$version.info 有關版本的 JSON 元資料。(請參閱 GOPROXY 協議)。這可能會隨時間變化,因此 go 命令通常會獲取新副本而不是重用此檔案。
cache/download/$module/@v/$version.mod 此版本的 go.mod 檔案(請參閱 GOPROXY 協議)。如果原始模組沒有 go.mod 檔案,這是一個沒有要求的合成檔案。
cache/download/$module/@v/$version.zip 模組的壓縮內容(請參閱 GOPROXY 協議模組 zip 檔案)。
cache/download/$module/@v/$version.ziphash .zip 檔案中檔案的加密雜湊。請注意,.zip 檔案本身未進行雜湊處理,因此檔案順序、壓縮、對齊和元資料不會影響雜湊。使用模組時,go 命令會驗證此雜湊是否與 go.sum 中的相應行匹配。go mod verify 命令會檢查模組 .zip 檔案和提取目錄的雜湊是否與這些檔案匹配。
cache/download/sumdb/ 包含從 校驗和資料庫下載的檔案的目錄(通常是 sum.golang.org)。
cache/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.mod 結尾,則雜湊僅適用於模組的 go.mod 檔案;否則,雜湊適用於模組 .zip 檔案中的檔案。
  • 雜湊列由演算法名稱(如 h1)和 base64 編碼的加密雜湊組成,用冒號 (:) 分隔。目前,SHA-256 (h1) 是唯一支援的雜湊演算法。如果將來發現 SHA-256 的漏洞,將新增對另一種演算法(命名為 h2 等)的支援。

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

校驗和資料庫

校驗和資料庫是 go.sum 行的全球來源。go 命令在許多情況下都可以使用它來檢測代理或源伺服器的惡意行為。

校驗和資料庫為所有公共可用模組版本提供全球一致性和可靠性。它使得不受信任的代理成為可能,因為它們無法在不被注意的情況下提供錯誤的程式碼。它還確保與特定版本關聯的位不會日復一日地更改,即使模組的作者隨後更改了其倉庫中的標籤。

校驗和資料庫由 sum.golang.org 提供服務,該服務由 Google 運營。它是 go.sum 行雜湊的 透明日誌(或“Merkle 樹”),並由 Trillian 支援。Merkle 樹的主要優點是獨立審計員可以驗證它是否未被篡改,因此它比簡單的資料庫更值得信賴。

go 命令使用最初在 提案:保護公共 Go 模組生態系統中概述的協議與校驗和資料庫互動。

下表指定了校驗和資料庫必須響應的查詢。對於每個路徑,$base 是校驗和資料庫 URL 的路徑部分,$module 是模組路徑,$version 是版本。例如,如果校驗和資料庫 URL 是 https://sum.golang.org,並且客戶端請求模組 golang.org/x/text 版本 v0.3.2 的記錄,客戶端將傳送 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 返回最新日誌的簽名、編碼樹描述。此簽名描述採用 note 的形式,即由一個或多個伺服器金鑰簽名並可使用伺服器的公鑰驗證的文字。樹描述提供樹的大小和該大小下樹頭部的雜湊。此編碼在 golang.org/x/mod/sumdb/tlog#FormatTree 中描述。
$base/lookup/$module@$version 返回有關 $module$version 處的條目的日誌記錄號,後跟記錄資料(即 $module$version 處的 go.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 命令識別的所有環境變數的列表,請參閱 go help environment

變數 描述
GO111MODULE

控制 go 命令是在模組感知模式還是 GOPATH 模式下執行。識別三個值

  • offgo 命令忽略 go.mod 檔案並在 GOPATH 模式下執行。
  • on(或未設定):go 命令在模組感知模式下執行,即使不存在 go.mod 檔案。
  • 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

模組代理 URL 列表,用逗號 (,) 或管道 (|) 分隔。當 go 命令查詢有關模組的資訊時,它會按順序聯絡列表中的每個代理,直到收到成功的響應或終端錯誤。代理可以響應 404(未找到)或 410(已移除)狀態,以指示模組在該伺服器上不可用。

go 命令的錯誤回退行為由 URL 之間的分隔符字元決定。如果代理 URL 後跟逗號,則 go 命令在出現 404 或 410 錯誤後回退到下一個 URL;所有其他錯誤都被視為終端錯誤。如果代理 URL 後跟管道,則 go 命令在出現任何錯誤(包括超時等非 HTTP 錯誤)後回退到下一個源。

GOPROXY URL 可以具有 httpshttpfile 方案。如果 URL 沒有方案,則假定為 https。模組快取可以直接用作檔案代理

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

可以使用兩個關鍵字代替代理 URL

  • 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,或者如果呼叫 go get 時帶有 -insecure 標誌,則不會查詢校驗和資料庫,所有無法識別的模組都將被接受,代價是放棄所有模組經過驗證的可重複下載的安全保證。對於特定模組,更好的繞過校驗和資料庫的方法是使用 GOPRIVATEGONOSUMDB 環境變數。

有關更多資訊,請參閱認證模組隱私

GOVCS

控制 go 命令可用於下載公共和私有模組(由其路徑是否與 GOPRIVATE 中的模式匹配定義)或其他匹配全域性模式的模組的版本控制工具集。

如果未設定 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` 命令將按照 [工作區](#workspaces) 部分的描述搜尋 `go.work` 檔案。

詞彙表

構建約束: 編譯包時決定 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 檔案的最新版本中帶有一個廢棄註釋

直接依賴: 其路徑出現在import 宣告中,用於主模組中的包或測試的 .go 原始檔中的包,或包含此類包的模組。(與間接依賴比較。)

直接模式: 環境變數設定,使 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 協議的 Web 伺服器。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-prev1.2.3 之前。另請參閱釋出版本

偽版本: 編碼了修訂識別符號(例如 Git 提交雜湊)和版本控制系統時間戳的版本。例如,v0.0.0-20191109021931-daa7c04131f5。用於與非模組倉庫相容以及在沒有可用標記版本時的其他情況。

釋出版本: 沒有預釋出字尾的版本。例如,v1.2.3,而不是 v1.2.3-pre。另請參閱預釋出版本

倉庫根路徑: 模組路徑中對應版本控制倉庫根目錄的部分。請參閱模組路徑

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

語義版本標籤: 版本控制倉庫中的標籤,將版本對映到特定修訂。請參閱將版本對映到提交

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

供應商目錄: 名為 vendor 的目錄,其中包含構建主模組中包所需的其他模組中的包。使用go mod vendor進行維護。請參閱供應商化

版本: 模組不可變快照的識別符號,寫為字母 v 後跟語義版本。請參閱版本部分。

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