Go Modules Reference

简介

模块是 Go 管理依赖项的方式。

本文档是 Go 模块系统的详细参考手册。有关创建 Go 项目的介绍,请参阅 如何编写 Go 代码。有关使用模块、将项目迁移到模块以及其他主题的信息,请参阅博客系列,从 使用 Go Modules 开始。

模块、包和版本

模块是打包在一起发布、版本化和分发的一组包。模块可以直接从版本控制仓库或模块代理服务器下载。

模块由其模块路径标识,模块路径在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 提交哈希)和版本控制系统的时间戳。例如,命令 go get golang.org/x/net@daa7c041 会将提交哈希 daa7c041 转换为伪版本 v0.0.0-20191109021931-daa7c04131f5。在主模块之外需要规范版本,如果 go.mod 文件中出现像 master 这样的非规范版本,go 命令会报告错误。

伪版本

伪版本是一种特殊格式的预发布版本,它编码了版本控制仓库中特定修订版本的信息。例如,v0.0.0-20191109021931-daa7c04131f5 就是一个伪版本。

伪版本可以引用没有可用语义版本标签的修订版本。例如,可以在开发分支上使用它们来测试提交,然后再创建版本标签。

每个伪版本包含三部分

每个伪版本可以采用三种形式之一,具体取决于基础版本。这些形式确保伪版本比其基础版本排序更高,但低于下一个带有标签的版本。

多个伪版本可以通过使用不同的基础版本来引用相同的提交。这自然发生在伪版本写入后,较低版本被标记时。

这些形式赋予伪版本两个有用的特性

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 环境变量,该变量是一个以逗号分隔的代理 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 命令可能会发出以下请求

找到合适的模块后,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 文件时,其内容被分解成一系列 token。有几种类型的 token:空白、注释、标点符号、关键字、标识符和字符串。

空白包括空格(U+0020)、制表符(U+0009)、回车(U+000D)和换行符(U+000A)。除换行符以外的空白字符没有作用,仅用于分隔否则会组合在一起的 token。换行符是重要的 token。

注释// 开头,并持续到行尾。不允许使用 /* */ 注释。

标点符号 token 包括 ()=>

关键字用于区分 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 语言规范中的 Notation 部分

GoMod = { Directive } .
Directive = ModuleDirective |
            GoDirective |
            ToolDirective |
            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 工具链拒绝使用声明了较新 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.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
)

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 .

示例

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 中添加的。如果 retract 指令写入到 主模块go.mod 文件中,Go 1.15 及更低版本会报告错误;它们会忽略依赖项的 go.mod 文件中的 retract 指令。

自动更新

如果 go.mod 缺少信息或未能准确反映实际情况,大多数命令会报告错误。go getgo mod tidy 命令可用于解决这些问题的大部分。此外,可以在大多数模块感知的命令(如 go buildgo test 等)中使用 -mod=mod 标志,指示 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 触发的更新会将非规范版本标识符重写为 规范的 SemVer 形式,因此 example.com/Av1 变成 v1.0.0example.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/A 需要 v1.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 的 Minimal Version Selection 中有详细描述。

从概念上讲,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 文件,并将其要求与主模块的要求进行对照检查,以确保它们在本地是一致的。(不一致可能由于版本控制合并、手动编辑以及使用本地文件系统路径 替换 的模块发生更改而引起。)

工作空间

一个 工作空间 是磁盘上的模块集合,在运行 最小版本选择 (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 执行低级编辑。Go 程序可以使用 golang.org/x/mod/modfile 包以编程方式进行相同的更改。

go 命令将维护一个 go.work.sum 文件,该文件跟踪工作区使用的哈希值,这些哈希值不包含在集体工作区模块的 go.sum 文件中。

通常不建议将 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 命令会在模块缓存中合成一个只包含 module 指令go.mod 文件。由于合成的 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 源文件中写入的导入路径。这些命令接受以下标志,这些标志对所有模块命令都通用。

依赖 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 中列出的模块信息。启用 vendoring 时,go mod downloadgo mod tidygo mod 命令的工作方式没有区别,它们仍然会下载模块并访问模块缓存。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 支持以下标志

自 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 可能会根据 GO111MODULE 环境变量和 go.mod 文件是否存在,在模块感知模式或 GOPATH 模式下运行。详细信息请参阅模块感知命令。如果启用了模块感知模式,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 struct 的格式模板,但现在应用于 Module struct

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 struct 有一个 String 方法,用于格式化此行输出,因此默认格式等同于 -f '{{.String}}'

注意,当一个模块被替换时,其 Replace 字段描述了替换模块,并且其 Dir 字段被设置为替换模块的源代码(如果存在)。(也就是说,如果 Replace 非零,则 Dir 被设置为 Replace.Dir,无法访问被替换模块的源代码。)

-u 标志添加有关可用升级的信息。当给定模块的最新版本比当前版本新时,list -u 会将模块的 Update 字段设置为有关较新模块的信息。list -u 还会打印当前选定的版本是否已撤回 (retracted) 以及该模块是否已废弃 (deprecated)。模块的 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 标志打印的列表中显示已撤回的版本,并在解析版本查询 (version queries)时考虑已撤回的版本。例如,go list -m -retracted example.com/m@latest 会显示模块 example.com/m 的最高发布版本或预发布版本,即使该版本已被撤回。retract 指令 (retract directives)废弃 (deprecations)是从此版本中的 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 命令将指定的模块下载到模块缓存 (module cache)中。参数可以是模块路径,或选择主模块依赖项的模块模式,或形式为 path@version版本查询 (version queries)。不带参数时,download 应用于主模块 (main module)的所有依赖项。

go 命令在正常执行期间会按需自动下载模块。go mod download 命令主要用于预填充模块缓存,或加载由模块代理 (module proxy)提供的数据。

默认情况下,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
}

type Tool struct {
    Path      string
}

注意,这仅描述 go.mod 文件本身,不描述间接引用的其他模块。要获取可用于构建的完整模块集合,请使用 go list -m -json all。参见 go list -m

例如,工具可以通过解析 go mod edit -json 的输出将 go.mod 文件获取为数据结构,然后通过调用 go mod edit 并带上 -require-exclude 等标志进行更改。

工具还可以使用包 golang.org/x/mod/modfile 来解析、编辑和格式化 go.mod 文件。

go mod graph

用法

go mod graph [-go=version]

go mod graph 命令以文本形式打印模块依赖图 (module requirement 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 指令 (go directive)指示的版本。

有关如何选择版本的更多信息,请参见最小版本选择 (Minimal version selection, 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 接受一个可选参数,即新模块的模块路径 (module path)。有关如何选择模块路径的说明,请参见模块路径 (Module paths)。如果省略模块路径参数,init 将尝试使用 .go 文件中的导入注释、vendoring 工具配置文件和当前目录(如果在 GOPATH 中)来推断模块路径。

如果存在 vendoring 工具的配置文件,init 将尝试从中导入模块依赖项。init 支持以下配置文件。

Vendoring 工具配置文件并非总是能完美地转换。例如,如果在同一个仓库中有多个包以不同版本导入,并且该仓库只包含一个模块,则导入的 go.mod 只能依赖于该模块的一个版本。您可能希望运行go list -m all 来检查构建列表 (build list)中的所有版本,并运行go mod tidy 以添加缺失的依赖项并删除未使用的依赖项。

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 tidytidy 执行的命令打印到标准错误。

-diff 标志使 go mod tidy 不修改 go.mod 或 go.sum,而是将必要的更改打印为统一的 diff。如果 diff 不为空,则退出时返回非零代码。

go mod tidy 的工作原理是递归加载主模块 (main module)中的所有包、其所有工具以及它们导入的所有包。这包括测试导入的包(包括其他模块中的测试)。go mod tidy 的行为就像所有构建标签都已启用,因此它会考虑平台特定的源文件以及需要自定义构建标签的文件,即使这些源文件通常不会被构建。有一个例外:ignore 构建标签未启用,因此具有构建约束 // +build ignore 的文件将不被考虑。注意,go mod tidy 不会考虑主模块中名为 testdata 或以 ._ 开头的目录中的包,除非这些包被其他包显式导入。

一旦 go mod tidy 加载了这组包,它会确保每个提供一个或多个包的模块在主模块的 go.mod 文件中有一个 require 指令,或者(如果主模块的版本在 Go 1.16 或以下)被另一个必需模块所依赖。go mod tidy 会添加对每个缺失模块的最新版本的依赖项(有关 latest 版本的定义,请参见版本查询 (Version queries))。go mod tidy 将删除对上述集合中未提供任何包的模块的 require 指令。

go mod tidy 还可能在 require 指令上添加或删除 // indirect 注释。// indirect 注释表示该模块未提供主模块中的包所导入的包。(有关何时添加 // indirect 依赖项和注释的更多详细信息,请参见require 指令 (require directive)。)

如果设置了 -go 标志,go mod tidy 将根据指示的版本更新go 指令 (go directive),启用或禁用模块图剪枝 (module graph pruning)惰性模块加载 (lazy module loading)(并根据需要添加或删除间接依赖项)。

默认情况下,go mod tidy 会检查当模块图由 go 指令中指示版本紧 preceding 前的 Go 版本加载时,模块的选定版本 (selected versions)是否发生变化。检查兼容性的版本也可以通过 -compat 标志显式指定。

go mod vendor

用法

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

go mod vendor 命令在主模块 (main module)的根目录中构建一个名为 vendor 的目录,其中包含支持主模块中包的构建和测试所需的所有包的副本。不包括仅由主模块外部包的测试导入的包。与go mod tidy 和其他模块命令一样,在构建 vendor 目录时,不考虑除 ignore 外的构建约束 (build constraints)

启用 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

请注意,go mod vendor 在重新构建之前会删除现有的 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 树输出到指定的目录,而不是 vendor。参数可以是绝对路径或相对于模块根目录的路径。

go mod verify

用法

go mod verify

go mod verify 检查存储在模块缓存 (module cache)中的主模块 (main module)依赖项自下载以来是否已被修改。为了执行此检查,go mod verify 对每个下载的模块 .zip 文件和提取的目录进行哈希计算,然后将这些哈希值与首次下载模块时记录的哈希值进行比较。go mod verify 检查构建列表 (build list)中的每个模块(可以使用go list -m all 打印)。

如果所有模块均未修改,go mod verify 会打印“all modules verified”。否则,它会报告哪些模块已更改并退出,返回非零状态码。

注意,所有模块感知的命令都会验证主模块的 go.sum 文件中的哈希值是否与下载到模块缓存中的模块记录的哈希值匹配。如果 go.sum 中缺少某个哈希值(例如,因为该模块是首次使用),go 命令会使用校验和数据库 (checksum database)验证其哈希值(除非模块路径与 GOPRIVATEGONOSUMDB 匹配)。有关详细信息,请参见模块认证 (Authenticating modules)

相比之下,go mod verify 检查模块的 .zip 文件及其提取的目录的哈希值是否与首次下载时在模块缓存中记录的哈希值匹配。这对于检测模块下载并验证后模块缓存中文件的更改非常有用。go mod verify 不会下载缓存中不存在的模块内容,并且不使用 go.sum 文件来验证模块内容。但是,go mod verify 可能会下载 go.mod 文件以执行最小版本选择 (minimal version selection)。它将使用 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 directive)),此标志在 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.ReadBuildBuildInfo 获取。

表格中每一行的含义由第一列的单词决定。

go clean -modcache

用法

go clean [-modcache]

-modcache 标志使 go clean 删除整个模块缓存 (module cache),包括带版本依赖项的解压缩源代码。

这通常是删除模块缓存的最佳方法。默认情况下,模块缓存中的大多数文件和目录是只读的,以防止测试和编辑器在文件认证 (authenticated)后无意中更改它们。不幸的是,这会导致像 rm -r 这样的命令失败,因为如果不先使其父目录可写,就无法删除文件。

-modcacherw 标志(由go build 和其他模块感知的命令接受)使模块缓存中的新目录可写。要将 -modcacherw 传递给所有模块感知的命令,请将其添加到 GOFLAGS 变量中。GOFLAGS 可以在环境变量中设置,或使用go env -w 设置。例如,以下命令会永久设置它

go env -w GOFLAGS=-modcacherw

应谨慎使用 -modcacherw;开发人员应注意不要更改模块缓存中的文件。go mod verify 可用于检查缓存中的文件是否与主模块的 go.sum 文件中的哈希值匹配。

版本查询 (Version queries)

几个命令允许您使用版本查询 (version query) 指定模块版本,版本查询出现在命令行上模块或包路径后面的 @ 字符之后。

示例

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 文件 (go.mod file)exclude 指令 (exclude directives)不允许的模块版本不被考虑。来自同一模块的 latest 版本 go.mod 文件中retract 指令 (retract directives)涵盖的版本也会被忽略,除非在与go list -m 一起使用 -retracted 标志时,以及加载 retract 指令时。

发布版本 (Release versions)优先于预发布版本。例如,如果版本 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 查询将选择仓库默认分支顶端提交的伪版本。其他查询将报告错误。

在模块外部的模块命令 (Module commands outside a module)

模块感知的 Go 命令通常在由工作目录或父目录中的 go.mod 文件定义的主模块 (main module)的上下文中运行。一些命令可以在没有 go.mod 文件的情况下以模块感知模式运行,但大多数命令在不存在 go.mod 文件时工作方式不同或报告错误。

有关启用和禁用模块感知模式的信息,请参见模块感知命令 (Module-aware commands)

命令 (Command) 行为 (Behavior)
go build
go doc
go fix
go fmt
go generate
go install
go list
go run
go test
go vet
只能加载、导入和构建标准库中的包以及在命令行上指定为 .go 文件的包。无法构建来自其他模块的包,因为没有地方记录模块依赖项并确保确定性构建。
go get 包和可执行文件可以照常构建和安装。注意,当 go get 在没有 go.mod 文件的情况下运行时,没有主模块,因此不应用 replaceexclude 指令。
go list -m 对于大多数参数,需要显式版本查询 (version queries),除非使用 -versions 标志。
go mod download 对于大多数参数,需要显式版本查询 (version queries)
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 文件。

编辑标志指定一系列编辑操作。

编辑标志可以重复使用。更改按给定的顺序应用。

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 指令 (use directive)添加到 go.work 文件中;如果该目录不存在于磁盘上,则将其从 go.work 文件中删除。

-r 标志在参数目录中递归搜索模块,use 命令的操作就像每个目录都作为参数指定一样。

go work sync

用法

go work sync

go work sync 命令将工作区的构建列表同步回工作区的模块。

工作区的构建列表是用于在工作区中进行构建的所有(传递)依赖模块的版本集合。go work sync 使用最小版本选择 (Minimal Version Selection, MVS)算法生成该构建列表,然后将这些版本同步回工作区中指定的每个模块(通过 use 指令)。

计算出工作区构建列表后,将使用与该模块相关的依赖项重写工作区中每个模块的 go.mod 文件,这些依赖项已升级以匹配工作区构建列表。注意,最小版本选择 (Minimal Version Selection)保证构建列表中每个模块的版本总是等于或高于每个工作区模块中的版本。

模块代理 (Module proxies)

GOPROXY 协议 (GOPROXY protocol)

一个 模块代理 (module proxy) 是一个 HTTP 服务器,可以响应对以下指定路径的 GET 请求。请求没有查询参数,也不需要特定的头部,因此即使是从固定文件系统提供服务的站点(包括 file:// URL)也可以成为模块代理。

成功的 HTTP 响应必须具有状态码 200 (OK)。会遵循重定向 (3xx)。状态码为 4xx 和 5xx 的响应被视为错误。错误码 404 (Not Found) 和 410 (Gone) 表示请求的模块或版本在代理上不可用,但在其他地方可能找到。错误响应的内容类型应为 text/plain,且 charsetutf-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 相同。最新版本应该是当 $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 空间相同,因此将 $GOPATH/pkg/mod/cache/download 服务于(或复制到) https://example.com/proxy,用户就可以通过将 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.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

请注意,尽管 go.mod 文件通常包含在 .zip 文件中,但 .mod.zip 请求是分开的。go 命令可能需要下载许多不同模块的 go.mod 文件,而 .mod 文件比 .zip 文件小得多。此外,如果 Go 项目没有 go.mod 文件,代理将提供一个合成的 go.mod 文件,该文件仅包含一个module 指令。合成的 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 下载仓库,期望在 bar 子目录中找到该模块。go 命令将根据版本控制工具支持的协议猜测要使用的协议。

如果模块路径没有限定符,go 命令会向从模块路径派生的 URL 发送 HTTP GET 请求,并附带 ?go-get=1 查询字符串。例如,对于模块 golang.org/x/modgo 命令可能会发送以下请求

https://golang.ac.cn/x/mod?go-get=1 (preferred)
https://golang.ac.cn/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">

root-path 是仓库根路径,是模块路径中对应于仓库根目录的部分。它必须是请求的模块路径的前缀或精确匹配。如果不是精确匹配,则会向该前缀发出另一个请求以验证 <meta> 标签是否匹配。

vcs 是版本控制系统。它必须是下表中列出的工具之一,或者是关键字 mod,它指示 go 命令使用GOPROXY 协议从给定的 URL 下载模块。详情请参阅直接从代理服务模块

repo-url 是仓库的 URL。如果 URL 不包含方案(无论是模块路径带有 VCS 限定符还是 <meta> 标签缺少方案),go 命令将尝试版本控制系统支持的每种协议。例如,对于 Git,go 命令将尝试 https://,然后是 git+ssh://。只有当模块路径与 GOINSECURE 环境变量匹配时,才可以使用不安全协议(如 http://git://)。

名称 命令 (Command) 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.ac.cn/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/toolsgopls 子目录中定义。该模块的 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 文件不包含 vendor 目录或任何嵌套模块(包含 go.mod 文件的子目录)的内容。这意味着模块必须注意不要引用其目录外部或在其他模块中的文件。例如,//go:embed 模式不得匹配嵌套模块中的文件。这种行为在某些情况下可能作为一个有用的变通方法,即不应将文件包含在模块中。例如,如果仓库在 testdata 目录中有大量文件,模块作者可以在 testdata 中添加一个空的 go.mod 文件,这样他们的用户就不需要下载这些文件了。当然,这可能会降低用户测试其依赖项时的覆盖率。

LICENSE 文件特殊情况

go 命令为一个不在仓库根目录中的模块创建 .zip 文件时,如果模块在其根目录中(与 go.mod 并列)没有名为 LICENSE 的文件,则如果仓库根目录在同一修订版本中存在名为 LICENSE 的文件,go 命令将复制该文件。

这个特殊情况允许同一个 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 规则列表。pattern 是一个glob 模式,必须匹配模块或导入路径的一个或多个开头元素。vcslist 是一个以竖线分隔的允许版本控制命令列表,或者 all(表示允许使用任何已知命令),或者 off(表示不允许任何命令)。请注意,如果模块匹配一个带有 off 的 vcslist 的模式,它仍然可以被下载,如果源服务器使用 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 永久设置。

本节的其余部分描述了提供对私有模块代理和版本控制仓库访问的常见模式。

serving all modules">私有代理服务所有模块

一个服务所有模块(公共和私有)的中央私有代理服务器为管理员提供了最大的控制权,并为单个开发者提供了最少的配置。

要将 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(并进行适当的配置)来检索缺失的模块。

serving private modules">私有代理服务私有模块

私有代理服务器可以在不服务公共可用模块的情况下服务私有模块。可以将 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(禁止访问)。

direct">直接访问私有模块

可以将 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 来禁用交互式提示,但它会尊重显式设置。

auth">向私有代理传递凭据

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 文件中。

或者,您可以在 .gitconfig 中重写 https:// URL 为其他方案。例如

[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 文件,则此目录不会包含一个。
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.mod 文件并行,包含一个名为 go.sum 的文本文件。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 提供服务。它是一个由 Trillian 支持的 透明日志(或“Merkle 树”)的 go.sum 行哈希。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 数据提供了此模块版本的校验和及其在日志中的位置,这会告知客户端应该获取哪些瓦片 (tiles) 来执行证明。在向主模块的 go.sum 文件添加新的 go.sum 行之前,go 命令会执行“包含”证明(证明特定记录存在于日志中)和“一致性”证明(证明树未被篡改)。重要的是,在从未签名树哈希进行认证之前,并且从未客户端签名树哈希的时间线进行认证之前,永远不应使用来自 /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 (Not Found) 或 410 (Gone) 状态,表示该模块在该服务器上不可用。

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,或者如果使用 -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 命令将按 [工作区](#workspaces) 部分所述搜索 go.work 文件。

词汇表

构建约束 (build constraint): 决定编译包时是否使用 Go 源文件的条件。构建约束可以通过文件名后缀(例如,foo_linux_amd64.go)或构建约束注释(例如,// +build linux,amd64)表示。请参阅构建约束

构建列表 (build list): 将用于构建命令(如 go buildgo listgo test)的模块版本列表。构建列表根据主模块go.mod 文件和使用最小版本选择在可传递依赖模块中的 go.mod 文件确定。构建列表包含模块图中所有模块的版本,而不仅仅是与特定命令相关的模块。

规范版本 (canonical version): 格式正确的版本,除了 +incompatible 外,没有构建元数据后缀。例如,v1.2.3 是规范版本,但 v1.2.3+meta 不是。

当前模块 (current module): 主模块的同义词。

废弃模块 (deprecated module): 作者不再支持的模块(尽管主要版本在此目的下被视为不同的模块)。废弃模块在其最新版本的go.mod 文件中用废弃注释标记。

直接依赖 (direct dependency):主模块中的包或测试的 .go 源文件中,其路径出现在 import 声明中的包,或包含此类包的模块。(比较间接依赖。)

直接模式 (direct mode): 环境变量的一种设置,导致 go 命令直接从版本控制系统下载模块,而不是从模块代理GOPROXY=direct 对所有模块执行此操作。GOPRIVATEGONOPROXY 对匹配模式列表的模块执行此操作。

go.mod 文件: 定义模块路径、需求和其他元数据的文件。出现在模块的根目录中。请参阅有关go.mod 文件的部分。

go.work 文件: 定义在工作区中使用的模块集合的文件。请参阅有关go.work 文件的部分。

导入路径 (import path): 在 Go 源文件中用于导入包的字符串。包路径的同义词。

间接依赖 (indirect dependency):主模块中的包或测试可传递导入的包,但其路径未出现在主模块的任何 import 声明中;或出现在模块图中但不提供主模块直接导入的任何包的模块。(比较直接依赖。)

惰性模块加载 (lazy module loading): Go 1.17 中的一项更改,通过避免为那些不需要模块图的命令加载模块图来减少模块图的大小,这些模块指定了 go 1.17 或更高版本。请参阅惰性模块加载

主模块 (main module): 调用 go 命令时所在的模块。主模块由当前目录或父目录中的go.mod 文件定义。请参阅模块、包和版本

主要版本 (major version): 语义版本中的第一个数字(v1.2.3 中的 1)。在包含不兼容更改的发布中,主要版本必须递增,并且次要版本和补丁版本必须设置为 0。主要版本为 0 的语义版本被视为不稳定。

主要版本子目录 (major version subdirectory): 版本控制仓库中与模块的主要版本后缀匹配的子目录,其中可以定义模块。例如,路径为 根路径 example.com/mod 的仓库中的模块 example.com/mod/v2 可以在仓库根目录或主要版本子目录 v2 中定义。请参阅仓库内的模块目录

主要版本后缀 (major version suffix): 与主要版本号匹配的模块路径后缀。例如,example.com/mod/v2 中的 /v2。在 v2.0.0 及更高版本中,主要版本后缀是必需的,在更早的版本中则不允许。请参阅有关主要版本后缀的部分。

最小版本选择 (MVS): 用于确定构建中将使用的所有模块版本的算法。有关详细信息,请参阅有关最小版本选择的部分。

次要版本 (minor version): 语义版本中的第二个数字(v1.2.3 中的 2)。在包含新的、向后兼容功能的发布中,次要版本必须递增,并且补丁版本必须设置为 0。

模块 (module): 一组一起发布、版本化和分发的包。

模块缓存 (module cache): 存储下载的模块的本地目录,位于 GOPATH/pkg/mod 中。请参阅模块缓存

模块图 (module graph):主模块为根的模块需求有向图。图中的每个顶点都是一个模块;每条边都是 go.mod 文件中 require 语句中的版本(受主模块 go.mod 文件中的 replaceexclude 语句影响)。

模块图剪枝 (module graph pruning): Go 1.17 中的一项更改,通过省略指定 go 1.17 或更高版本的模块的可传递依赖项来减小模块图的大小。请参阅模块图剪枝

模块路径 (module path): 标识模块并作为模块内包导入路径前缀的路径。例如,"golang.org/x/net"

模块代理 (module proxy): 实现GOPROXY 协议的 Web 服务器。go 命令从模块代理下载版本信息、go.mod 文件和模块 zip 文件。

模块根目录 (module root directory): 包含定义模块的 go.mod 文件的目录。

模块子目录 (module subdirectory): 模块路径中位于仓库根路径之后的部分,表示定义模块的子目录。当非空时,模块子目录也是语义版本标签的前缀。即使模块位于主要版本子目录中,模块子目录也不包含主要版本后缀(如果存在)。请参阅模块路径

包 (package): 同一目录中一起编译的一组源文件。请参阅 Go 语言规范中的包部分

包路径 (package path): 唯一标识包的路径。包路径是模块路径与模块内子目录的组合。例如,"golang.org/x/net/html" 是模块 "golang.org/x/net""html" 子目录中包的包路径。导入路径的同义词。

补丁版本 (patch version): 语义版本中的第三个数字(v1.2.3 中的 3)。在模块公共接口没有更改的发布中,补丁版本必须递增。

预发布版本 (pre-release version): 补丁版本后立即跟破折号和一系列点分隔标识符的版本,例如 v1.2.3-beta4。预发布版本被视为不稳定,并且不假定与其他版本兼容。预发布版本在相应的发布版本之前排序:v1.2.3-prev1.2.3 之前。另请参阅发布版本

伪版本 (pseudo-version): 编码了修订标识符(如 Git 提交哈希)和版本控制系统时间戳的版本。例如,v0.0.0-20191109021931-daa7c04131f5。用于与非模块仓库兼容以及没有标记版本可用的其他情况。

发布版本 (release version): 没有预发布后缀的版本。例如,v1.2.3,而不是 v1.2.3-pre。另请参阅预发布版本

仓库根路径 (repository root path): 模块路径中对应于版本控制仓库根目录的部分。请参阅模块路径

撤回版本 (retracted version): 不应依赖的版本,原因可能是发布过早,或者发布后发现了严重问题。请参阅retract 指令

语义版本标签 (semantic version tag): 版本控制仓库中将版本映射到特定修订版本的标签。请参阅将版本映射到提交

选中版本 (selected version): 通过最小版本选择为给定模块选择的版本。选中版本是模块图中为该模块路径找到的最高版本。

供应商目录 (vendor directory): 名为 vendor 的目录,包含主模块中构建包所需的其他模块中的包。通过go mod vendor维护。请参阅Vendoring

版本 (version): 模块不可变快照的标识符,写成字母 v 后跟语义版本。请参阅有关版本的部分。

工作区 (workspace): 磁盘上一组模块的集合,在运行最小版本选择 (MVS) 时用作主模块。请参阅有关工作区的部分。