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
命令不会尝试从网络服务器解析此类路径。路径 example
和 test
保留给用户:它们不会在标准库中使用,适用于自包含模块,例如教程或示例代码中定义的模块,或作为测试的一部分创建和操作的模块。
版本
版本 (version) 标识模块的不可变快照,可以是 发布版本 (release) 或 预发布版本 (pre-release)。每个版本都以字母 v
开头,后跟一个语义版本。有关版本如何格式化、解释和比较的详细信息,请参阅 语义化版本 2.0.0。
总而言之,语义版本由三个非负整数(主版本、次版本和补丁版本,从左到右)组成,用点分隔。补丁版本后可能跟一个以连字符开头的可选预发布字符串。预发布字符串或补丁版本后可能跟一个以加号开头的构建元数据字符串。例如,v0.0.0
、v1.12.134
、v8.0.5-pre
和 v2.0.9+meta
都是有效版本。
版本的每个部分都表示该版本是否稳定以及是否与以前的版本兼容。
- 在对模块的公共接口或文档功能进行向后不兼容更改后,例如删除包后,必须增加 主版本 (major version),并将次版本和补丁版本设置为零。
- 在向后兼容更改后,例如添加新函数后,必须增加 次版本 (minor version),并将补丁版本设置为零。
- 在不影响模块公共接口的更改(例如错误修复或优化)后,必须增加 补丁版本 (patch version)。
- 预发布后缀表示版本是 预发布版本。预发布版本在相应的发布版本之前排序。例如,
v1.2.3-pre
在v1.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.0
或vX.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
开始,包需要新的导入路径。这通过向模块路径添加主版本后缀来实现。由于模块路径是模块中每个包的导入路径的前缀,因此向模块路径添加主版本后缀为每个不兼容版本提供了不同的导入路径。
主版本后缀不允许用于主版本 v0
或 v1
。v0
和 v1
之间无需更改模块路径,因为 v0
版本不稳定,没有兼容性保证。此外,对于大多数模块,v1
与最后一个 v0
版本向后兼容;v1
版本作为对兼容性的承诺,而不是与 v0
相比不兼容更改的指示。
作为特例,以 gopkg.in/
开头的模块路径必须始终具有主版本后缀,即使在 v0
和 v1
版本。后缀必须以点而不是斜杠开头(例如,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.mod
和 go.sum
。 go get
和 go mod tidy
命令会自动执行此操作。
当 go
命令为包路径查找新模块时,它会检查 GOPROXY
环境变量,该变量是一个逗号分隔的代理 URL 列表或关键字 direct
或 off
。代理 URL 表示 go
命令应使用 GOPROXY
协议 联系 模块代理。direct
表示 go
命令应 与版本控制系统通信。off
表示不应尝试通信。GOPRIVATE
和 GONOPROXY
环境变量 也可用于控制此行为。
对于 GOPROXY
列表中的每个条目,go
命令会请求每个可能提供该包的模块路径的最新版本(即,包路径的每个前缀)。对于每个成功请求的模块路径,go
命令将下载最新版本的模块并检查该模块是否包含请求的包。如果一个或多个模块包含请求的包,则使用路径最长的模块。如果找到一个或多个模块但都不包含请求的包,则报告错误。如果没有找到模块,go
命令会尝试 GOPROXY
列表中的下一个条目。如果没有剩余条目,则报告错误。
例如,假设 go
命令正在寻找提供包 golang.org/x/net/html
的模块,并且 GOPROXY
设置为 https://corp.example.com,https://proxy.golang.org
。go
命令可能会发出以下请求
- 并行请求
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.mod
。go mod edit
可以执行低级编辑。golang.org/x/mod/modfile
包可以由 Go 程序用于以编程方式进行相同的更改。
主模块 和任何指定本地文件路径的 替换模块 都需要 go.mod
文件。但是,缺少显式 go.mod
文件的模块仍然可以被 请求 作为依赖项,或者用模块路径和版本指定作为替换项;请参阅 与非模块仓库的兼容性。
词法元素
解析 go.mod
文件时,其内容会分解为一系列标记。标记有几种类型:空白、注释、标点符号、关键字、标识符和字符串。
空白 由空格 (U+0020)、制表符 (U+0009)、回车符 (U+000D) 和换行符 (U+000A) 组成。除换行符以外的空白字符没有效果,只是分隔否则会合并的标记。换行符是重要的标记。
注释 以 //
开头,并延伸到行尾。不允许使用 /* */
注释。
标点符号 标记包括 (
、)
和 =>
。
关键字 区分 go.mod
文件中不同类型的指令。允许的关键字有 module
、go
、require
、replace
、exclude
和 retract
。
标识符 是非空白字符序列,例如模块路径或语义版本。
字符串 是带引号的字符序列。有两种类型的字符串:以引号("
,U+0022)开头和结尾的解释字符串,以及以重音符(`
,U+0060)开头和结尾的原始字符串。解释字符串可能包含由反斜杠(\
,U+005C)后跟另一个字符组成的转义序列。转义的引号(\"
)不会终止解释字符串。解释字符串的未加引号的值是引号之间的字符序列,其中每个转义序列被反斜杠后面的字符替换(例如,\"
被替换为 "
,\n
被替换为 n
)。相比之下,原始字符串的未加引号的值仅仅是重音符之间的字符序列;反斜杠在原始字符串中没有特殊含义。
标识符和字符串在 go.mod
语法中可以互换。
模块路径和版本
go.mod
文件中的大多数标识符和字符串要么是模块路径,要么是版本。
模块路径必须满足以下要求
- 路径必须由一个或多个用斜杠(
/
,U+002F)分隔的路径元素组成。它不能以斜杠开头或结尾。 - 每个路径元素都是一个非空字符串,由 ASCII 字母、ASCII 数字和有限的 ASCII 标点符号(
-
、.
、_
和~
)组成。 - 路径元素不能以点(
.
,U+002E)开头或结尾。 - 元素前缀直到第一个点不得是 Windows 上保留的文件名,无论大小写(例如
CON
、com1
、NuL
等)。 - 元素前缀直到第一个点不得以波浪号后跟一个或多个数字结尾(例如
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
文件时,它会尝试将每个非规范版本替换为等效的规范版本。
在模块路径与版本关联的地方(如 require
、replace
和 exclude
指令中),最终路径元素必须与版本一致。请参阅 主版本后缀。
语法
go.mod
语法使用扩展巴克斯-诺尔范式 (EBNF) 在下面指定。有关 EBNF 语法的详细信息,请参阅 Go 语言规范中的表示法部分。
GoMod = { Directive } .
Directive = ModuleDirective |
GoDirective |
ToolDirective |
IgnoreDirective |
RequireDirective |
ExcludeDirective |
ReplaceDirective |
RetractDirective .
换行符、标识符和字符串分别用 newline
、ident
和 string
表示。
模块路径和版本分别用 ModulePath
和 Version
表示。
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.14
、1.21rc1
或 1.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.mod
和go.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 get
和 go 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 get
、go 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.0
和 v1.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.0
和v1.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 get
和 go mod tidy
命令可以用于解决这些问题。此外,-mod=mod
标志可以与大多数支持模块的命令(go build
、go test
等)一起使用,以指示 go
命令自动修复 go.mod
和 go.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/A
的 v1
变为 v1.0.0
,而 example.com/E
的 dev
变为 dev
分支上最新提交的伪版本,可能是 v0.0.0-20180523231146-b3f5c0f6e5f1
。
更新会修改要求以遵守排除项,因此对排除的 example.com/D v1.2.3
的要求会更新为使用 example.com/D
的下一个可用版本,可能是 v1.2.4
或 v1.3.0
。
更新会删除冗余或误导性要求。例如,如果 example.com/A v1.0.0
本身需要 example.com/B v1.2.0
和 example.com/C v1.0.0
,那么 go.mod
对 example.com/B v1.0.0
的要求是误导性的(被 example.com/A
对 v1.2.0
的需求取代),而它对 example.com/C v1.0.0
的要求是冗余的(被 example.com/A
对相同版本的需求隐含),因此两者都将被删除。如果主模块包含直接从 example.com/B
或 example.com/C
导入包的包,则要求将被保留但更新为实际使用的版本。
最后,更新会以规范格式重新格式化 go.mod
,以便未来的机械更改只会导致最小的差异。如果只需要格式更改,go
命令将不会更新 go.mod
。
由于模块图定义了导入语句的含义,任何加载包的命令也会使用 go.mod
,因此可以更新它,包括 go build
、go get
、go install
、go list
、go test
、go 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
文件中的 exclude
和 replace
指令以及 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。
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。
排除
也可以使用主模块 go.mod
文件中的 exclude
指令 在特定版本排除模块。
排除也会改变模块图。当一个版本被排除时,它会从模块图中移除,对其的要求也会重定向到下一个更高版本。
考虑下面的例子。C 1.3 已被排除。MVS 将如同 A 1.2 要求 C 1.4(下一个更高版本)而不是 C 1.3 一样操作。
升级
可以使用 go get
命令升级一组模块。要执行升级,go
命令通过从已访问版本到已升级版本添加边来在运行 MVS 之前更改模块图。
考虑下面的示例。模块 B 可以从 1.2 升级到 1.3,C 可以从 1.3 升级到 1.4,D 可以从 1.2 升级到 1.3。
升级(和降级)可能会添加或删除间接依赖项。在这种情况下,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。
go get
还可以完全删除依赖项,在参数后使用 @none
后缀。这类似于降级。指定模块的所有版本都将从模块图中移除。
模块图修剪
如果主模块在 go 1.17
或更高版本,用于 最小版本选择 的 模块图 仅包含每个模块依赖项的直接要求,这些依赖项在其自己的 go.mod
文件中指定 go 1.17
或更高版本,除非该模块版本也(传递地)被其他 go 1.16
或更低版本的依赖项所需要。(go 1.17
依赖项的传递依赖项被从模块图中修剪掉。)
由于 go 1.17
的 go.mod
文件包含一个 require 指令,用于构建该模块中任何包或测试所需的所有依赖项,因此修剪后的模块图包含构建或测试 主模块 显式要求的任何依赖项中的包所需的所有依赖项。一个不需要构建给定模块中任何包或测试的模块不会影响其包的运行时行为,因此从模块图中修剪掉的依赖项只会导致否则不相关的模块之间发生干扰。
其要求已被修剪掉的模块仍然出现在模块图中,并且仍然由 go list -m all
报告:它们的 选定版本 是已知且明确定义的,并且可以从这些模块加载包(例如,作为从其他模块加载的测试的传递依赖项)。但是,由于 go
命令无法轻松识别这些模块的哪些依赖项已满足,因此 go build
和 go test
的参数不能包含来自其要求已被修剪掉的模块的包。go get
将包含每个命名包的模块提升为显式依赖项,允许在该包上调用 go build
或 go 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 init
、go mod why
、go mod edit
、go mod tidy
、go mod vendor
和 go 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 .
换行符、标识符和字符串分别用 newline
、ident
和 string
表示。
模块路径和版本分别用 ModulePath
和 Version
表示。模块路径和版本的指定方式与 go.mod
文件完全相同。
ModulePath = ident | string . /* see restrictions above */
Version = ident | string . /* see restrictions above */
go
指令
有效的 go.work
文件中需要 go
指令。版本必须是有效的 Go 发布版本:一个正整数后跟一个点和一个非负整数(例如,1.18
,1.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
环境变量控制,该变量可以设置为 on
、off
或 auto
。
- 如果
GO111MODULE=off
,go
命令会忽略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 -m
和 go 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 build
和 go test
)会从 vendor
目录加载包,而不是访问网络或本地模块缓存。go list -m
命令只打印 go.mod
中列出的模块信息。go mod
命令(如go mod download
和go 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
),或特殊查询 latest
、upgrade
、patch
或 none
之一。如果未给出版本,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
。
当命令行上命名的模块被降级或移除时,其他模块可能会被降级。继续上面的例子,假设模块 example.com/b
被降级到 v1.1.0
。模块 example.com/a
也将降级到需要 example.com/b
版本 v1.1.0
或更低的版本。
可以使用版本后缀 @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
)、元模式(std
、cmd
、all
、work
、tool
),或相对或绝对文件路径。 - 所有参数必须具有相同的版本后缀。不允许使用不同的查询,即使它们指向相同的版本。
- 所有参数必须指同一模块的同一版本中的包。
- 包路径参数必须指向
main
包。模式参数将只匹配main
包。 - 不将任何模块视为主模块。
- 如果包含命令行上命名包的模块有
go.mod
文件,则它不能包含(replace
和exclude
)指令,否则如果它作为主模块,则会被不同地解释。 - 该模块不能要求其自身的更高版本。
- 在任何模块中都不使用 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
标志使 download
将 download
执行的命令打印到标准错误。
-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@version
或go 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 -m
和 go 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
命令会使用校验和数据库验证其哈希(除非模块路径与 GOPRIVATE
或 GONOSUMDB
匹配)。有关详细信息,请参阅验证模块。
相比之下,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
将打印到每个模块中任何包的路径。请注意,即使使用 -m
,go 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
相同。=>
: 上一行的模块的替换。如果替换是本地目录,则只列出目录路径(无版本或校验和)。如果替换是模块版本,则列出路径、版本和校验和,与mod
和dep
相同。被替换的模块没有校验和。
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
,它选择一个特定版本。有关语法,请参阅版本。 - 语义版本前缀,例如
v1
或v1.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.2
和 v1.2.3-pre
版本可用,latest
查询将选择 v1.2.2
,即使 v1.2.3-pre
更高。<v1.2.4
查询也将选择 v1.2.2
,即使 v1.2.3-pre
更接近 v1.2.4
。如果没有发布或预发布版本可用,latest
、upgrade
和 patch
查询将选择仓库默认分支尖端提交的伪版本。其他查询将报告错误。
模块外部的模块命令
模块感知 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 时没有主模块,因此不应用 replace 和 exclude 指令。 |
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-8
或 us-ascii
。
go
命令可以配置为使用 GOPROXY
环境变量联系代理或源代码管理服务器,该变量接受代理 URL 列表。该列表可以包含关键字 direct
或 off
(有关详细信息,请参阅环境变量)。列表元素可以通过逗号 (,
) 或管道 (|
) 分隔,这决定了错误回退行为。当 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.2
的 go.mod
文件,客户端将发送 GET
请求 https://example.com/mod/golang.org/x/text/@v/v0.3.2.mod
。
为了避免在从不区分大小写的文件系统提供服务时产生歧义,$module
和 $version
元素通过将每个大写字母替换为感叹号后跟相应的小写字母进行大小写编码。这允许模块 example.com/M
和 example.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 }
将来可能会添加更多字段,因此其他名称已保留。 |
$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/@latest
。go
命令优先选择顺序为:语义上最高的发布版本、语义上最高的预发布版本,以及时间上最新的伪版本。在 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
命令也会合成显式 info
、mod
和 zip
文件,并将其存储在此目录中,就像直接从代理下载一样。缓存布局与代理 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.0
的 go.mod
文件
$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.mod
module golang.org/x/mod
go 1.12
require (
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
)
为了加载一个包,go
命令需要提供该包的模块的源代码。模块源代码以 .zip
文件的形式分发,并解压到模块缓存中。如果模块 .zip
文件不在缓存中,go
命令将使用 $module/@v/$version.zip
请求下载它。
$ curl -O https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.zip
$ unzip -l v0.2.0.zip | head
Archive: v0.2.0.zip
Length Date Time Name
--------- ---------- ----- ----
1479 00-00-1980 00:00 golang.org/x/mod@v0.2.0/LICENSE
1303 00-00-1980 00:00 golang.org/x/mod@v0.2.0/PATENTS
559 00-00-1980 00:00 golang.org/x/mod@v0.2.0/README
21 00-00-1980 00:00 golang.org/x/mod@v0.2.0/codereview.cfg
214 00-00-1980 00:00 golang.org/x/mod@v0.2.0/go.mod
1476 00-00-1980 00:00 golang.org/x/mod@v0.2.0/go.sum
5224 00-00-1980 00:00 golang.org/x/mod@v0.2.0/gosumcheck/main.go
请注意,.mod
和 .zip
请求是分开的,即使 go.mod
文件通常包含在 .zip
文件中。go
命令可能需要下载许多不同模块的 go.mod
文件,而 .mod
文件比 .zip
文件小得多。此外,如果 Go 项目没有 go.mod
文件,代理将提供一个只包含 module
指令的合成 go.mod
文件。合成的 go.mod
文件是在从 版本控制系统下载时由 go
命令生成的。
如果 go
命令需要加载构建列表中任何模块未提供的包,它将尝试查找提供该包的新模块。 将包解析为模块部分描述了此过程。简而言之,go
命令请求有关可能包含该包的每个模块路径的最新版本的信息。例如,对于包 golang.org/x/net/html
,go
命令将尝试查找模块 golang.org/x/net/html
、golang.org/x/net
、golang.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
命令会报告安全错误,并且不会将文件安装到模块缓存中。GOPRIVATE
和 GONOSUMDB
环境变量可用于禁用对特定模块的校验和数据库请求。GOSUMDB
环境变量也可以设置为 off
以完全禁用校验和数据库请求。有关更多信息,请参阅 验证模块。请注意,为 .info
请求返回的版本列表和版本元数据未经验证,并且可能会随时间变化。
直接从代理提供模块
大多数模块都是从版本控制仓库开发和提供的。在 直接模式下,go
命令使用版本控制工具下载此类模块(请参阅 版本控制系统)。也可以直接从模块代理提供模块。这对于希望提供模块而不暴露其版本控制服务器的组织以及使用 go
命令不支持的版本控制工具的组织很有用。
当 go
命令以直接模式下载模块时,它首先根据模块路径通过 HTTP GET 请求查找模块服务器的 URL。它在 HTML 响应中查找带有名称 go-import
的 <meta>
标签。该标签的内容必须包含 仓库根路径、版本控制系统和 URL,并用空格分隔。有关详细信息,请参阅 为模块路径查找仓库。
如果版本控制系统是 mod
,go
命令将使用 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.info
、v1.0.0.mod
和 v1.0.0.zip
的请求来下载模块。
请注意,直接从代理提供的模块无法在 GOPATH 模式下使用 go get
下载。
版本控制系统
go
命令可以直接从版本控制仓库下载模块源代码和元数据。从 代理下载模块通常更快,但如果代理不可用或模块的仓库无法访问代理(对于私有仓库通常如此),则需要直接连接到仓库。支持 Git、Subversion、Mercurial、Bazaar 和 Fossil。版本控制工具必须安装在 PATH
中的目录中,go
命令才能使用它。
要从源仓库而不是代理下载特定模块,请设置 GOPRIVATE
或 GONOPROXY
环境变量。要将 go
命令配置为直接从源仓库下载所有模块,请将 GOPROXY
设置为 direct
。有关更多信息,请参阅 环境变量。
为模块路径查找仓库
当 go
命令以 direct
模式下载模块时,它首先定位包含该模块的仓库。
如果模块路径的路径组件末尾带有 VCS 限定符(.bzr
、.fossil
、.git
、.hg
、.svn
之一),go
命令将使用该路径限定符之前的所有内容作为仓库 URL。例如,对于模块 example.com/foo.git/bar
,go
命令使用 git 下载 example.com/foo
处的仓库,预期会在 bar
子目录中找到该模块。go
命令将根据版本控制工具支持的协议猜测要使用的协议。
如果模块路径没有限定符,go
命令会向从模块路径派生的 URL 发送 HTTP GET
请求,并带有一个 ?go-get=1
查询字符串。例如,对于模块 golang.org/x/mod
,go
命令可能会发送以下请求
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 [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
对应于该子目录,覆盖了仓库根目录的默认值。提供 subdirectory
的 go-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.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.3
、v2.4.0-beta
或 v3.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/bar
或 foo/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
命令默认只使用 git
和 hg
从公共服务器下载代码。它将使用任何 已知版本控制系统从私有服务器下载代码,私有服务器定义为托管与 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/
开头的代码只能使用 git
;evil.com
上的路径不能使用任何版本控制命令,所有其他路径(*
匹配所有内容)只能使用 git
或 hg
。
特殊模式 public
和 private
匹配公共和私有模块或导入路径。如果路径与 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.CheckFilePath
和module.CheckImportPath
。 - 文件或目录名直到第一个点必须不是 Windows 上的保留文件名,无论大小写(例如
CON
、com1
、NuL
等)。
私有模块
Go 模块经常在公共互联网上不可用的版本控制服务器和模块代理上开发和分发。go
命令可以从私有源下载和构建模块,尽管通常需要一些配置。
下面的环境变量可用于配置对私有模块的访问。有关详细信息,请参阅 环境变量。另请参阅 隐私,了解有关控制发送到公共服务器的信息。
GOPROXY
— 模块代理 URL 列表。go
命令将尝试按顺序从列表中的每个服务器下载模块。关键字direct
指示go
命令从它们开发的版本控制仓库下载模块,而不是使用代理。GOPRIVATE
— glob 模式的模块路径前缀列表,应被视为私有。作为GONOPROXY
和GONOSUMDB
的默认值。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.git
或 ssh://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
环境变量设置。如果未设置 NETRC
,go
命令将在类 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
控制使用哪些服务器。环境变量 GOPRIVATE
和 GONOPROXY
控制从代理获取哪些模块。
GOPROXY
的默认值为
https://proxy.golang.org,direct
在此设置下,当 go
命令下载模块或模块元数据时,它将首先向 proxy.golang.org
发送请求,这是一个由 Google 运营的公共模块代理(隐私政策)。有关每个请求中发送哪些信息的详细信息,请参阅 GOPROXY
协议。go
命令不传输个人身份信息,但它确实传输所请求的完整模块路径。如果代理响应 404(未找到)或 410(已删除)状态,go
命令将尝试直接连接到提供模块的版本控制系统。有关详细信息,请参阅 版本控制系统。
GOPRIVATE
或 GONOPROXY
环境变量可以设置为 glob 模式列表,匹配被视为私有且不应从任何代理请求的模块前缀。例如
GOPRIVATE=*.corp.example.com,*.research.example.com
GOPRIVATE
只是作为 GONOPROXY
和 GONOSUMDB
的默认值,因此除非 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
作为 GONOSUMDB
和 GONOPROXY
的默认值,因此除非 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
并将下载的文件添加到模块缓存中。如果模块是私有的(与 GOPRIVATE
或 GONOSUMDB
环境变量匹配)或者校验和数据库已禁用(通过设置 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/M
和 example.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
,则不查询校验和数据库,并且接受所有无法识别的模块,代价是放弃了所有模块验证可重复下载的安全保证。对于特定模块绕过校验和数据库的更好方法是使用 GOPRIVATE
或 GONOSUMDB
环境变量。有关详细信息,请参阅 私有模块。
go env -w
命令可用于为将来的 go
命令调用 设置这些变量。
环境变量
Go 命令中的模块行为可以使用下面列出的环境变量进行配置。此列表仅包含与模块相关的环境变量。有关 go
命令识别的所有环境变量的列表,请参阅 go help environment
。
变量 | 描述 |
---|---|
GO111MODULE |
控制
有关更多信息,请参阅 模块感知命令。 |
GOMODCACHE |
如果未设置 |
GOINSECURE |
逗号分隔的 glob 模式列表(使用 Go 的 与 |
GONOPROXY |
逗号分隔的 glob 模式列表(使用 Go 的 如果未设置 |
GONOSUMDB |
逗号分隔的 glob 模式列表(使用 Go 的 如果未设置 |
GOPATH |
在 在模块感知模式下,模块缓存存储在第一个 如果未设置 |
GOPRIVATE |
逗号分隔的 glob 模式列表(使用 Go 的 path.Match 语法),表示应被视为私有的模块路径前缀。GOPRIVATE 是 GONOPROXY 和 GONOSUMDB 的默认值。请参阅 隐私。GOPRIVATE 还决定模块是否被视为 GOVCS 的私有模块。 |
GOPROXY |
模块代理 URL 列表,用逗号 (
GOPROXY=file://$(go env GOMODCACHE)/cache/download 可以使用两个关键字代替代理 URL
|
GOSUMDB |
识别要使用的校验和数据库的名称,并可选择其公钥和 URL。例如 GOSUMDB="sum.golang.org" GOSUMDB="sum.golang.org+<publickey>" GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"
如果 |
GOVCS |
控制 如果未设置 public:git|hg,private:all 有关完整解释,请参阅使用 |
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 build
、go list
或 go test
等构建命令的模块版本列表。构建列表由主模块的go.mod
文件和使用最小版本选择传递依赖的模块中的 go.mod
文件确定。构建列表包含模块图中所有模块的版本,而不仅仅是与特定命令相关的模块。
规范版本: 格式正确的版本,除了 +incompatible
之外不带构建元数据后缀。例如,v1.2.3
是一个规范版本,但 v1.2.3+meta
不是。
当前模块: 主模块的同义词。
已废弃模块: 作者不再支持的模块(为此目的,主要版本被视为不同的模块)。已废弃模块在其go.mod
文件的最新版本中带有一个废弃注释。
直接依赖: 其路径出现在import
声明中,用于主模块中的包或测试的 .go
源文件中的包,或包含此类包的模块。(与间接依赖比较。)
直接模式: 环境变量设置,使 go
命令直接从版本控制系统下载模块,而不是从模块代理下载。GOPROXY=direct
对所有模块都这样做。GOPRIVATE
和 GONOPROXY
对匹配模式列表的模块都这样做。
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
文件中 replace
和 exclude
语句的影响)。
模块图修剪: Go 1.17 中的一项更改,通过省略指定 go 1.17
或更高版本的模块的传递依赖来减小模块图的大小。请参阅模块图修剪。
模块路径: 标识模块并作为模块内包导入路径前缀的路径。例如,"golang.org/x/net"
。
模块代理: 实现GOPROXY
协议的 Web 服务器。go
命令从模块代理下载版本信息、go.mod
文件和模块 zip 文件。
模块子目录: 模块路径中仓库根路径之后的部分,指示模块定义的子目录。当非空时,模块子目录也是语义版本标签的前缀。模块子目录不包括主要版本后缀(如果有),即使模块位于主要版本子目录中。请参阅模块路径。
包: 同一目录中编译在一起的源文件集合。请参阅 Go 语言规范中的包部分。
包路径: 唯一标识包的路径。包路径是模块路径与模块内子目录的结合。例如,"golang.org/x/net/html"
是模块 "golang.org/x/net"
中 "html"
子目录中包的包路径。导入路径的同义词。
补丁版本: 语义版本中的第三个数字(v1.2.3
中的 3
)。在模块公共接口没有更改的版本中,补丁版本必须递增。
预发布版本: 补丁版本之后带有破折号,后跟一系列由点分隔的标识符的版本,例如 v1.2.3-beta4
。预发布版本被认为是不稳定的,并且不假定与其他版本兼容。预发布版本在相应的发布版本之前排序:v1.2.3-pre
在 v1.2.3
之前。另请参阅发布版本。
伪版本: 编码了修订标识符(例如 Git 提交哈希)和版本控制系统时间戳的版本。例如,v0.0.0-20191109021931-daa7c04131f5
。用于与非模块仓库兼容以及在没有可用标记版本时的其他情况。
发布版本: 没有预发布后缀的版本。例如,v1.2.3
,而不是 v1.2.3-pre
。另请参阅预发布版本。
仓库根路径: 模块路径中对应版本控制仓库根目录的部分。请参阅模块路径。
撤回版本: 不应依赖的版本,原因可能是发布过早,或发布后发现了严重问题。请参阅retract
指令。
语义版本标签: 版本控制仓库中的标签,将版本映射到特定修订。请参阅将版本映射到提交。
选中版本: 最小版本选择选择的给定模块的版本。选中版本是模块图中找到的模块路径的最高版本。
供应商目录: 名为 vendor
的目录,其中包含构建主模块中包所需的其他模块中的包。使用go mod vendor
进行维护。请参阅供应商化。
版本: 模块不可变快照的标识符,写为字母 v
后跟语义版本。请参阅版本部分。
工作区: 磁盘上的一组模块,在运行最小版本选择 (MVS) 时用作主模块。请参阅工作区部分。