Go 模块参考
介绍
模块是 Go 管理依赖项的方式。
本文档是 Go 模块系统的详细参考手册。有关创建 Go 项目的介绍,请参阅 如何编写 Go 代码。有关使用模块、将项目迁移到模块以及其他主题的信息,请参阅从 使用 Go 模块 开始的博客系列。
模块、包和版本
一个 模块 是一个包的集合,它们一起发布、版本化和分发。模块可以从版本控制存储库或模块代理服务器直接下载。
模块由 模块路径 标识,该路径在 go.mod
文件 中声明,以及有关模块的依赖项的信息。 模块根目录 是包含 go.mod
文件的目录。 主模块 是包含调用 go
命令的目录的模块。
模块中的每个 包 都是同一个目录中一起编译的源文件的集合。 包路径 是模块路径与包含包的子目录(相对于模块根目录)相连接。例如,模块 "golang.org/x/net"
在 "html"
目录中包含一个包。该包的路径是 "golang.org/x/net/html"
。
模块路径
一个 模块路径 是模块的规范名称,由模块的 go.mod
文件 中的 module
指令 声明。模块的路径是模块中包路径的前缀。
模块路径应该描述模块的功能和位置。通常,模块路径包含一个存储库根路径、存储库中的一个目录(通常为空)和一个主版本后缀(仅限于主版本 2 或更高)。
- 存储库根路径 是模块路径中对应于开发模块的版本控制存储库的根目录的部分。大多数模块都在其存储库的根目录中定义,因此这通常是整个路径。例如,
golang.org/x/net
是同名模块的存储库根路径。有关go
命令如何使用从模块路径派生的 HTTP 请求来查找存储库的信息,请参阅 查找模块路径的存储库。 - 如果模块未在存储库的根目录中定义,则 模块子目录 是模块路径中命名目录的部分,不包括主版本后缀。这也用作语义版本标签的前缀。例如,模块
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
为用户保留:它们不会在标准库中使用,适合用于自包含模块,例如教程或示例代码中定义的模块,或作为测试的一部分创建和操作的模块。
版本
一个 版本 标识模块的不可变快照,可以是 发布版 或 预发布版。每个版本都以字母 v
开头,后跟一个语义版本。有关版本如何格式化、解释和比较的详细信息,请参阅 语义版本控制 2.0.0。
总而言之,语义版本由三个非负整数(主版本、次版本和修订版本,从左到右)组成,用点隔开。修订版本后面可以接一个可选的预发布字符串,该字符串以连字符开头。预发布字符串或修订版本后面可以接一个以加号开头的构建元数据字符串。例如,v0.0.0
、v1.12.134
、v8.0.5-pre
和 v2.0.9+meta
是有效的版本。
版本的每个部分都指示版本是否稳定以及它是否与以前的版本兼容。
- 主版本 必须在对模块的公共接口或文档化功能进行向后不兼容的更改后递增,并且次版本和修订版本必须设置为零,例如,在删除包后。
- 次版本 必须在进行向后兼容的更改后递增,并且修订版本设置为零,例如,在添加新函数后。
- 修订版本 必须在不影响模块公共接口的更改后递增,例如,在修复错误或优化后。
- 预发布后缀表示版本是 预发布版。预发布版本在相应的发布版本之前排序。例如,
v1.2.3-pre
在v1.2.3
之前。 - 构建元数据后缀在比较版本时被忽略。
go
命令接受带有构建元数据的后缀的版本并将它们转换为伪版本以维护版本之间的总排序。特殊后缀+incompatible
表示在迁移到模块版本主版本 2 或更高版本之前发布的版本(请参阅 与非模块存储库的兼容性)。
如果版本的版本号为 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
是一个伪版本。
伪版本可能引用没有可用的 语义版本标签 的修订版。例如,它们可以用于在创建版本标签之前测试提交,例如,在开发分支上。
每个伪版本都有三个部分
- 一个基本版本前缀 (
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.0.yyyymmddhhmmss-abcdefabcdef
在基准版本是预发布版本(如vX.Y.Z-pre
)时使用。vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef
在基准版本是发布版本(如vX.Y.Z
)时使用。例如,如果基准版本是v1.2.3
,伪版本可能是v1.2.4-0.20191109021931-daa7c04131f5
。
多个伪版本可以使用不同的基准版本引用同一个提交。当较低版本在写入伪版本后被标记时,这种情况自然发生。
这些形式赋予伪版本两个有用的属性
- 具有已知基准版本的伪版本,排序高于这些版本,但低于后续版本的其他预发布版本。
- 具有相同基准版本前缀的伪版本按时间顺序排序。
go
命令执行一些检查,以确保模块作者能够控制伪版本与其他版本的比较方式,并且伪版本引用的是实际属于模块提交历史的修订。
- 如果指定了基准版本,则必须存在一个对应的语义版本标签,该标签是伪版本描述的修订的祖先。这可以防止开发人员使用比所有标记版本都高的伪版本(如
v1.999.999-99999999999999-daa7c04131f5
)绕过 最小版本选择。 - 时间戳必须与修订的时间戳相匹配。这可以防止攻击者使用无限数量的相同伪版本来淹没 模块代理。这也防止模块使用者更改版本的相对排序。
- 修订必须是模块存储库的某个分支或标签的祖先。这可以防止攻击者引用未经批准的更改或拉取请求。
伪版本永远不需要手动输入。许多命令接受提交哈希或分支名称,并将其自动转换为伪版本(或如果可用则为标记版本)。例如
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
开始,包需要新的导入路径。这是通过在模块路径中添加主版本后缀来实现的。由于模块路径是模块中每个包导入路径的前缀,因此在模块路径中添加主版本后缀为每个不兼容版本提供了不同的导入路径。
主版本后缀不允许在主版本 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://proxy.golang.org/
,如果所有对https://corp.example.com/
的请求都失败了,返回 404 或 410- 请求
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.12
require example.com/other/thing v1.0.2
require example.com/new/thing/v2 v2.3.4
exclude example.com/old/thing v1.2.3
replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5
retract [v1.9.0, v1.9.5]
可以将前面的关键字从相邻行中分解出来,形成一个块,就像 Go 导入一样。
require (
example.com/new/thing/v2 v2.3.4
example.com/old/thing v1.2.3
)
go.mod
文件旨在可读且可写。go
命令提供了一些子命令,可以更改 go.mod
文件。例如,go get
可以升级或降级特定依赖项。加载模块图的命令会在需要时 自动更新 go.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 |
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.9
、1.14
或 1.21rc1
。
go
指令设置了使用该模块所需的 Go 的最低版本。在 Go 1.21 之前,该指令只是建议性的;现在它是强制性的要求:Go 工具链拒绝使用声明了更新版本的 Go 的模块。
go
指令是选择要运行的 Go 工具链的输入。有关详细信息,请参见“Go 工具链”。
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
或更高版本中,可以启用自动 供应商管理。如果文件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
会省略供应商依赖项的go.mod
和go.sum
文件。(这允许在vendor
的子目录中调用go
命令来识别正确的主模块。)go mod vendor
会在vendor/modules.txt
中记录每个依赖项的go.mod
文件中的go
版本。
- 在
go 1.21
或更高版本中go
行声明了与该模块一起使用的 Go 的最低所需版本。go
行必须大于或等于所有依赖项的go
行。go
命令不再尝试维护与之前的旧版本的 Go 的兼容性。go
命令在go.sum
文件中更谨慎地保存go.mod
文件的校验和。
go.mod
文件最多只能包含一个 go
指令。大多数命令会在没有指令的情况下添加一个带有当前 Go 版本的 go
指令。
如果缺少 go
指令,则假设为 go 1.16
。
GoDirective = "go" GoVersion newline .
GoVersion = string | ident . /* valid release version; see above */
示例
go 1.14
toolchain
指令
toolchain
指令声明了一个建议的 Go 工具链,与模块一起使用。建议的 Go 工具链的版本不能低于 go
指令中声明的所需 Go 版本。toolchain
指令只有在模块为主模块,并且默认工具链的版本低于建议的工具链的版本时才有效。
为了可重现性,go
命令在任何时候都会在 toolchain
行中写入它自己的工具链名称,只要它在 go.mod
文件中更新 go
版本(通常是在 go get
期间)即可。
有关详细信息,请参见“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
)
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
指令不会将模块添加到模块图中。还需要一个引用被替换模块版本的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
指令非常有用。被撤回的版本应保留在版本控制库和模块代理中,以确保依赖它们的构建不会出现问题。术语“撤回”借鉴于学术文献:被撤回的研究论文仍然可用,但存在问题,不应作为未来工作的基础。
当某个模块版本被撤回时,用户将不会使用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.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.
retract
指令是在 Go 1.16 中添加的。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.16
require (
example.com/A v1
example.com/B v1.0.0
example.com/C v1.0.0
example.com/D v1.2.3
example.com/E dev
)
exclude example.com/D v1.2.3
使用-mod=mod
触发的更新会将非规范版本标识符重写为规范 的语义版本格式,因此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 用于在每个模块感知命令开始时计算它。
考虑下面图表中的示例。主模块需要版本 1.2 或更高版本的模块 A 和版本 1.2 或更高版本的模块 B。A 1.2 和 B 1.2 分别需要 C 1.3 和 C 1.4。C 1.3 和 C 1.4 都需要 D 1.2。
MVS 访问并加载以蓝色突出显示的每个模块版本的 go.mod
文件。在图遍历结束时,MVS 返回一个包含加粗版本的构建列表:A 1.2、B 1.2、C 1.4 和 D 1.2。请注意,B 和 D 的更高版本可用,但 MVS 不会选择它们,因为没有东西需要它们。
替换
可以使用主模块的 go.mod
文件或工作区的 go.work
文件中的 replace
指令 替换模块的内容(包括其 go.mod
文件)。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 出现在升级后的构建列表中,因为 E 1.1 是 B 1.3 所需的。
为了保留升级,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
文件,并将其要求与主模块的要求进行比较,以确保它们在本地一致。(由于版本控制合并、手动编辑以及已被 替换 的模块的更改(使用本地文件系统路径),可能会出现不一致。)
工作区
一个 工作区 是磁盘上的一组模块,在运行 最小版本选择(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.18
use ./my/first/thing
use ./my/second/thing
replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5
与 go.mod
文件一样,可以将相邻行的前导关键字分解出来以创建一个块。
use (
./my/first/thing
./my/second/thing
)
go
命令提供了几个用于操作 go.work
文件的子命令。go work init
创建新的 go.work
文件。go work use
将模块目录添加到 go.work
文件中。go work edit
执行低级编辑。可以使用 golang.org/x/mod/modfile
包以编程方式进行相同的更改。
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 文件
完全相同。
语法
以下是使用扩展巴科斯-诺尔范式 (EBNF) 指定的 go.work
语法。有关 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.18
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
命令会向主版本为 2 或更高且没有 go.mod
文件的版本添加 +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
模式下解析为目录时
- 在解析形式为
$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
命令将在当前目录或任何父目录中存在go.mod
文件时以模块感知模式运行。在 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` 来得到。
供应商
在使用模块时,`go` 命令通常通过从其源代码下载模块到模块缓存来满足依赖关系,然后从这些下载的副本中加载包。`供应商` 可用于允许与旧版本的 Go 交互,或确保用于构建的所有文件都存储在单个文件树中。
`go mod vendor` 命令在 `主模块` 根目录中构建一个名为 `vendor` 的目录,其中包含构建和测试 `主模块` 中的包所需的所有包的副本。仅由 `主模块` 外部的包的测试导入的包将不会被包含在内。与 `go mod tidy` 和其他模块命令一样,在构建 `vendor` 目录时,除了 `ignore` 之外的构建约束都不会被考虑在内。
`go mod vendor` 还创建了文件 `vendor/modules.txt`,其中包含一个供应商包列表以及它们复制的模块版本。当启用供应商功能时,此清单将用作模块版本信息的来源,如 `go list -m` 和 `go version -m` 所报告的那样。当 `go` 命令读取 `vendor/modules.txt` 时,它会检查模块版本是否与 `go.mod` 一致。如果 `go.mod` 自 `vendor/modules.txt` 生成后发生了更改,则 `go` 命令将报错。应该再次运行 `go mod vendor` 来更新 `vendor` 目录。
如果 `vendor` 目录存在于 `主模块` 根目录中,并且 `主模块` 的 `go.mod` 文件中的 `go` 版本为 `1.14` 或更高版本,则该目录将自动使用。要显式启用供应商功能,请使用标志 `-mod=vendor` 调用 `go` 命令。要禁用供应商功能,请使用标志 `-mod=readonly` 或 `-mod=mod`。
当启用供应商功能时,`构建命令`(例如 `go build` 和 `go test`)会从 `vendor` 目录中加载包,而不是访问网络或本地模块缓存。`go list -m` 命令只打印有关 `go.mod` 中列出的模块的信息。当启用供应商功能时,`go mod` 命令(如 `go mod download` 和 `go mod tidy`)的行为不会有所不同,它们仍然会下载模块并访问模块缓存。`go get` 在启用供应商功能时也不会有什么不同。
与 `GOPATH` 模式下的供应商功能不同,`go` 命令会忽略 `主模块` 根目录以外位置的供应商目录。此外,由于不会使用其他模块中的供应商目录,因此 `go` 命令在构建 `模块 zip 文件` 时不会包含供应商目录(但请参阅已知错误 #31562 和 #37397)。
go get
用法
go get [-d] [-t] [-u] [build flags] [packages]
示例
# Upgrade a specific module.
$ go get golang.org/x/net
# Upgrade modules that provide packages imported by packages in the main module.
$ go get -u ./...
# Upgrade or downgrade to a specific version of a module.
$ go get golang.org/x/[email protected]
# 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/[email protected]`。版本查询后缀由 `@` 符号后跟一个 `版本查询` 组成,该查询可以表示一个特定版本 ( `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/[email protected]` 也会将 `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/bin` 或 `$HOME/go/bin`(如果未设置 `GOPATH` 环境变量)。
`go get` 支持以下标志
- `-d` 标志告诉 `go get` 不要构建或安装包。当使用 `-d` 时,`go get` 将只管理 `go.mod` 中的依赖项。使用 `go get` 而不使用 `-d` 来构建和安装包已被弃用(从 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/[email protected]
# 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/bin
或 $HOME/go/bin
(如果未设置 GOPATH
环境变量)。$GOROOT
中的可执行文件安装在 $GOROOT/bin
或 $GOTOOLDIR
中,而不是 $GOBIN
。非可执行包将被构建并缓存,但不会安装。
自 Go 1.16 起,如果参数具有版本后缀(如 @latest
或 @v1.0.0
),go install
以模块感知模式构建包,忽略当前目录或任何父目录中的 go.mod
文件(如果有)。这对于在不影响主模块的依赖项的情况下安装可执行文件很有用。
为了消除对构建中使用哪些模块版本存在歧义,参数必须满足以下约束
- 参数必须是包路径或包模式(使用“
...
”通配符)。它们不能是标准包(如fmt
)、元模式(std
、cmd
、all
)或相对或绝对文件路径。 - 所有参数必须具有相同的版本后缀。不允许不同的查询,即使它们引用的是同一个版本。
- 所有参数必须引用同一模块中的相同版本的包。
- 包路径参数必须引用
main
包。模式参数只会匹配main
包。 - 没有模块被认为是 主模块。
- 如果包含命令行中命名的包的模块具有
go.mod
文件,则它不能包含指令(replace
和exclude
),这些指令会导致它在被解释为主模块时被不同地解释。 - 模块不能要求更高版本的自身。
- 任何模块都不使用供应商目录。(供应商目录不包含在 模块 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
的最高发布版本或预发布版本,即使该版本已撤回。从该版本的 go.mod
文件中加载 retract
指令 和 弃用。-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/[email protected]
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/[email protected]=./a
# Remove a replace directive.
$ go mod edit -dropreplace example.com/[email protected]
# 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/[email protected] -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
和其他命令显示。
编辑标志可以重复使用。更改按给定的顺序应用。
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
}
请注意,这仅描述 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
命令以文本形式打印 模块依赖关系图(应用了替换)。例如
example.com/main example.com/[email protected]
example.com/main example.com/[email protected]
example.com/[email protected] example.com/[email protected]
example.com/[email protected] example.com/[email protected]
example.com/[email protected] example.com/[email protected]
example.com/[email protected] example.com/[email protected]
模块图中的每个顶点代表模块的特定版本。图中的每条边代表对依赖项的最小版本的依赖关系。
go mod graph
打印图的边,每行一条。每行有两个空格分隔的字段:模块版本和它的一个依赖项。每个模块版本都用 path@version
格式的字符串标识。主模块没有 @version
后缀,因为它没有版本。
-go
标志使 go mod graph
报告由给定 Go 版本加载的模块图,而不是由 go.mod
文件中的 go
指令 指示的版本。
有关如何选择版本的更多信息,请参见 最小版本选择 (MVS)。还请参见 go list -m
以打印选定的版本,以及 go mod why
以了解为什么需要某个模块。
go mod init
用法
go mod init [module-path]
示例
go mod init
go mod init example.com/m
go mod init
命令在当前目录中初始化并写入一个新的 go.mod
文件,实际上是在当前目录中创建了一个新的模块。go.mod
文件必须不存在。
init
接受一个可选参数,即新模块的 模块路径。有关选择模块路径的说明,请参见 模块路径。如果省略了模块路径参数,init
将尝试使用 .go
文件中的导入注释、供应商工具配置文件和当前目录(如果在 GOPATH
中)来推断模块路径。
如果存在供应商工具的配置文件,init
将尝试从中导入模块依赖关系。init
支持以下配置文件。
GLOCKFILE
(Glock)Godeps/Godeps.json
(Godeps)Gopkg.lock
(dep)dependencies.tsv
(godeps)glide.lock
(glide)vendor.conf
(trash)vendor.yml
(govend)vendor/manifest
(gvt)vendor/vendor.json
(govendor)
供应商工具配置文件不能始终如一地进行完全忠实的转换。例如,如果同一个存储库中的多个包在不同的版本中导入,而存储库只包含一个模块,那么导入的 go.mod
只能要求模块处于一个版本。您可能希望运行 go list -m all
来检查 构建列表 中的所有版本,并运行 go mod tidy
来添加缺少的依赖关系并删除未使用的依赖关系。
go mod tidy
用法
go mod tidy [-e] [-v] [-go=version] [-compat=version]
go mod tidy
确保 go.mod
文件与模块中的源代码匹配。它添加了构建当前模块的包及其依赖项所需的任何缺少的模块依赖关系,并删除了对不提供任何相关包的模块的依赖关系。它还会将任何缺少的条目添加到 go.sum
中,并删除不必要的条目。
-e
标志(在 Go 1.16 中添加)会导致 go mod tidy
在加载包时遇到错误时尝试继续执行。
-v
标志会导致 go mod tidy
将有关已删除模块的信息打印到标准错误。
go mod tidy
的工作原理是加载 主模块 中的所有包以及它们导入的所有包(递归地)。这包括由测试导入的包(包括其他模块中的测试)。go mod tidy
的行为就像所有构建标签都被启用一样,因此它将考虑特定于平台的源文件和需要自定义构建标签的文件,即使这些源文件通常不会被构建。有一个例外:ignore
构建标签没有启用,因此具有 // +build ignore
构建约束的文件将不会被考虑。请注意,go mod tidy
不会考虑主模块中名为 testdata
的目录或以 .
或 _
开头的目录中的包,除非这些包被其他包显式导入。
go mod tidy
加载完这组包后,它将确保每个提供一个或多个包的模块在主模块的 go.mod
文件中都具有 require
指令,或者(如果主模块的版本为 go 1.16
或更低)被另一个必需的模块所要求。go mod tidy
将为每个缺少的模块添加一个对最新版本的依赖关系(有关 latest
版本的定义,请参见 版本查询)。go mod tidy
将删除对不提供上述集合中任何包的模块的 require
指令。
go mod tidy
还可以添加或删除 require
指令上的 // indirect
注释。// indirect
注释表示一个不提供主模块的包导入的包的模块。(有关何时添加 // 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
之外的 构建约束。
当启用供应商时,go
命令将从 vendor
目录中加载包,而不是从其源中下载模块到模块缓存并使用这些下载副本中的包。有关更多信息,请参见 供应商。
go mod vendor
还创建了 vendor/modules.txt
文件,其中包含一个供应商包列表以及它们从哪个模块版本中复制而来。当启用供应商时,此清单将用作模块版本信息的来源,如 go list -m
和 go version -m
所报告的那样。当 go
命令读取 vendor/modules.txt
时,它会检查模块版本是否与 go.mod
一致。如果 go.mod
自 vendor/modules.txt
生成以来发生了更改,则应再次运行 go mod vendor
。
请注意,go mod vendor
在重新构建它之前会删除现有的 vendor
目录。不应对供应商包进行本地更改。go
命令不检查 vendor
目录中的包是否未被修改,但可以通过运行 go mod vendor
并检查是否进行了任何更改来验证 vendor
目录的完整性。
-e
标志(在 Go 1.16 中添加)会导致 go mod vendor
在加载包时遇到错误时尝试继续执行。
-v
标志会导致 go mod vendor
将供应商模块和包的名称打印到标准错误。
-o
标志(在 Go 1.18 中添加)会导致 go mod vendor
在指定的目录中输出供应商树,而不是 vendor
。参数可以是绝对路径,也可以是相对于模块根目录的路径。
go mod verify
用法
go mod verify
go mod verify
检查存储在 模块缓存 中的 主模块 的依赖关系自下载以来是否被修改。为了执行此检查,go mod verify
会对每个下载的模块 .zip
文件 和解压缩的目录进行哈希处理,然后将这些哈希值与模块首次下载时记录的哈希值进行比较。go mod verify
检查 构建列表 中的每个模块(可以使用 go list -m all
打印)。
如果所有模块都未被修改,go mod verify
将打印“所有模块已验证”。否则,它会报告哪些模块已更改并以非零状态退出。
请注意,所有支持模块的命令都会验证主模块的 go.sum
文件中的哈希值是否与为下载到模块缓存中的模块记录的哈希值匹配。如果 go.sum
中缺少哈希值(例如,因为该模块是首次使用),则 go
命令将使用 校验和数据库 来验证其哈希值(除非模块路径与 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 1.16
或更高版本(使用 go
指令 在 go.mod
中)的模块没有影响,因为 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
指令 禁止的模块版本不予考虑。go.mod
文件中来自相同模块的 latest
版本的 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 get 在没有 go.mod 文件的情况下运行时,没有主模块,因此不会应用 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
文件上列出的每个参数目录在 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(未找到)和 410(已消失)表示请求的模块或版本在代理上不可用,但可能在其他地方找到。错误响应应具有内容类型 text/plain
,charset
为 utf-8
或 us-ascii
。
go
命令可以使用 GOPROXY
环境变量配置为联系代理或源代码控制服务器,该变量接受代理 URL 列表。该列表可能包括关键字 direct
或 off
(有关详细信息,请参阅 环境变量)。列表元素可以用逗号 (,
) 或管道 (|
) 分隔,它们决定错误回退行为。当一个 URL 后面跟着一个逗号时,go
命令只有在收到 404(未找到)或 410(已消失)响应后才会回退到后面的来源。当一个 URL 后面跟着一个管道时,go
命令会在任何错误后(包括非 HTTP 错误,如超时)回退到后面的来源。这种错误处理行为使代理能够充当未知模块的门卫。例如,代理可以对未在批准列表中的模块响应错误 403(禁止)(请参阅 提供私有模块的私有代理)。
下表指定了模块代理必须响应的查询。对于每个路径,$base
是代理 URL 的路径部分,$module
是模块路径,$version
是版本。例如,如果代理 URL 是 https://example.com/mod
,并且客户端请求模块 golang.org/x/text
在版本 v0.3.2
处的 go.mod
文件,则客户端会发送对 https://example.com/mod/golang.org/x/text/@v/v0.3.2.mod
的 GET
请求。
为了避免在不区分大小写的文件系统中提供服务时出现歧义,$module
和 $version
元素通过将每个大写字母替换为感叹号加上对应的小写字母来进行大小写编码。这样可以使模块 example.com/M
和 example.com/m
都存储在磁盘上,因为前者被编码为 example.com/!m
。
路径 | 描述 |
---|---|
$base/$module/@v/list |
以纯文本形式返回给定模块的已知版本的列表,每行一个。此列表不应包含伪版本。 |
$base/$module/@v/$version.info |
返回有关模块的特定版本的 JSON 格式的元数据。响应必须是与以下 Go 数据结构相对应的 JSON 对象。 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/[email protected]/LICENSE
1303 00-00-1980 00:00 golang.org/x/[email protected]/PATENTS
559 00-00-1980 00:00 golang.org/x/[email protected]/README
21 00-00-1980 00:00 golang.org/x/[email protected]/codereview.cfg
214 00-00-1980 00:00 golang.org/x/[email protected]/go.mod
1476 00-00-1980 00:00 golang.org/x/[email protected]/go.sum
5224 00-00-1980 00:00 golang.org/x/[email protected]/gosumcheck/main.go
请注意,.mod
和 .zip
请求是分开的,即使 go.mod
文件通常包含在 .zip
文件中。go
命令可能需要为许多不同的模块下载 go.mod
文件,而 .mod
文件远小于 .zip
文件。此外,如果 Go 项目没有 go.mod
文件,则代理将提供一个合成 go.mod
文件,该文件只包含一个 module
指令。从 版本控制系统 下载时,go
命令会生成合成 go.mod
文件。
如果 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 响应中查找名为 <meta>
且名称为 go-import
的标记。该标记的内容必须包含存储库根路径、版本控制系统和 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.git
的存储库,并期望在 bar
子目录中找到该模块。go
命令将根据版本控制工具支持的协议猜测要使用的协议。
如果模块路径没有限定符,则 go
命令会向从模块路径派生的 URL 发送 HTTP GET
请求,该 URL 带有 ?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">
root-path
是存储库根路径,是对应于存储库根目录的模块路径的一部分。它必须是请求的模块路径的前缀或完全匹配。如果它不是完全匹配,则会针对前缀发出另一个请求以验证 <meta>
标记是否匹配。
vcs
是版本控制系统。它必须是下面表格中列出的工具之一,或者关键字 mod
,它指示 go
命令使用GOPROXY
协议从给定 URL 下载模块。有关详细信息,请参见直接从代理服务器提供模块。
repo-url
是存储库的 URL。如果 URL 不包含方案(因为模块路径具有 VCS 限定符,或者因为 <meta>
标记缺少方案),则 go
命令将尝试版本控制系统支持的每种协议。例如,对于 Git,go
命令将尝试 https://
然后 git+ssh://
。不安全的协议(如 http://
和 git://
)只能在模块路径与 GOINSECURE
环境变量匹配时使用。
名称 | 命令 | 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
,example.com/mod/v2
将具有 v2.0.0
等标签。
如果模块没有 go.mod
文件,并且模块位于存储库根目录,则主版本为 v2
或更高的标签可以属于没有主版本后缀的模块。这种类型的版本用后缀 +incompatible
表示。版本标签本身不应具有后缀。请参见与非模块存储库的兼容性。
创建标签后,不应删除或更改为不同的修订版本。版本经过身份验证,以确保安全、可重复的构建。如果修改了标签,客户机在下载时可能会看到安全错误。即使标签被删除后,其内容也可能保留在模块代理服务器上。
将伪版本映射到提交
go
命令可能会在存储库中以特定修订版本检出模块,该修订版本编码为伪版本,例如 v1.3.2-0.20191109021931-daa7c04131f5
。
伪版本的最后 12 个字符(上面示例中的 daa7c04131f5
)表示要检出的存储库中的修订版本。此修订版本的含义取决于版本控制系统。对于 Git 和 Mercurial,这是提交哈希的前缀。对于 Subversion,这是一个零填充的修订版本号。
在检出提交之前,go
命令会验证时间戳(上面的 20191109021931
)是否与提交日期匹配。它还会验证基本版本(v1.3.1
,上面示例中 v1.3.2
之前的版本)是否对应于该提交的祖先的语义版本标签。这些检查确保模块作者对伪版本如何与其他发布版本进行比较具有完全控制权。
有关更多信息,请参见伪版本。
将分支和提交映射到版本
可以使用 版本查询 在特定分支、标签或修订版中检出模块。
go get example.com/mod@master
go
命令将这些名称转换为 规范版本,可用于 最小版本选择 (MVS)。MVS 依赖于能够明确地对版本进行排序。分支名称和修订版无法随着时间的推移可靠地进行比较,因为它们依赖于可能发生变化的存储库结构。
如果修订版被标记为一个或多个语义版本标签(例如 v1.2.3
),则将使用最高有效版本的标签。go
命令仅考虑可能属于目标模块的语义版本标签;例如,标签 v1.5.2
不会被考虑用于 example.com/mod/v2
,因为主版本与模块路径的后缀不匹配。
如果修订版未被标记为有效的语义版本标签,go
命令将生成一个 伪版本。如果修订版具有带有有效语义版本标签的祖先,则将使用最高祖先版本作为伪版本基础。请参阅 伪版本。
存储库中的模块目录
在特定修订版中检出模块的存储库后,go
命令必须找到包含模块 go.mod
文件的目录(模块的根目录)。
回想一下,模块路径 由三个部分组成:存储库根路径(对应于存储库根目录)、模块子目录和主版本后缀(仅适用于在 v2
或更高版本发布的模块)。
对于大多数模块,模块路径等于存储库根路径,因此模块的根目录是存储库的根目录。
模块有时在存储库子目录中定义。这通常用于具有多个需要独立发布和版本化的组件的大型存储库。此类模块应该位于与存储库根路径之后的模块路径部分匹配的子目录中。例如,假设模块 example.com/monorepo/foo/bar
位于根路径为 example.com/monorepo
的存储库中。其 go.mod
文件必须位于 foo/bar
子目录中。
如果模块在主版本 v2
或更高版本中发布,其路径必须具有 主版本后缀。具有主版本后缀的模块可以在两个子目录之一中定义:一个带有后缀,另一个没有。例如,假设上面模块的新版本使用路径 example.com/monorepo/foo/bar/v2
发布。其 go.mod
文件可能位于 foo/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),并且仅在私有模块或镜像拒绝提供公共包时才回退到版本控制(通常是出于法律原因)。因此,客户端仍然可以通过默认方式访问从 Bazaar、Fossil 或 Subversion 存储库提供的公共代码,因为这些下载使用 Go 模块镜像,该镜像承担着使用自定义沙箱运行版本控制命令的安全风险。
GOVCS
变量可用于更改特定模块的允许版本控制系统。GOVCS
变量在模块感知模式和 GOPATH 模式下构建包时都适用。使用模块时,模式与模块路径匹配。使用 GOPATH 时,模式与对应于版本控制存储库根部的导入路径匹配。
GOVCS
变量的一般形式是逗号分隔的 pattern:vcslist
规则列表。模式是 通配符模式,必须与模块或导入路径的一个或多个前导元素匹配。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 文件的位置及其提取内容。
可以使用 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/[email protected]/
。模块路径必须有效,版本必须有效且规范,版本必须与模块路径的主版本后缀匹配。有关具体定义和限制,请参见 模块路径和版本。 - 文件模式、时间戳和其他元数据将被忽略。
- 空目录(路径以斜杠结尾的条目)可以包含在模块 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:[email protected]
使用这种方法时要谨慎:环境变量可能会出现在 shell 历史记录和日志中。
将凭据传递到私有存储库
go
命令可以从版本控制存储库直接下载模块。如果未使用私有代理,则这对于私有模块是必需的。有关配置,请参见 直接访问私有模块。
go
命令在直接下载模块时会运行版本控制工具,如 git
。这些工具执行自己的身份验证,因此您可能需要在特定于工具的配置文件(如 .gitconfig
)中配置凭据。
为了确保顺利运行,请确保go
命令使用正确的仓库 URL,并且版本控制工具不需要交互式输入密码。go
命令更倾向于使用https://
URL,而不是其他方案,例如ssh://
,除非在查找仓库 URL时指定了方案。对于 GitHub 仓库,go
命令默认使用https://
。
对于大多数服务器,您可以配置客户端通过 HTTP 进行身份验证。例如,GitHub 支持使用OAuth 个人访问令牌作为 HTTP 密码。您可以在.netrc
文件中存储 HTTP 密码,就像向私有代理传递凭据时一样。
或者,您可以将https://
URL 重写为其他方案。例如,在.gitconfig
中
[url "[email protected]:"]
insteadOf = https://github.com/
有关更多信息,请参见为什么“go get”在克隆仓库时使用 HTTPS?
隐私
go
命令可能从模块代理服务器和版本控制系统下载模块和元数据。环境变量GOPROXY
控制使用哪些服务器。环境变量GOPRIVATE
和GONOPROXY
控制从代理获取哪些模块。
GOPROXY
的默认值为
https://proxy.golang.org,direct
使用此设置,当go
命令下载模块或模块元数据时,它将首先向proxy.golang.org
发送请求,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
命令不会对下载的模块进行身份验证,除非它们已经存在于go.sum
中。有关详细信息,请参见验证模块。
模块缓存
模块缓存是go
命令存储下载的模块文件的位置。模块缓存与构建缓存不同,构建缓存包含已编译的包和其他构建工件。
模块缓存的默认位置是$GOPATH/pkg/mod
。要使用其他位置,请设置GOMODCACHE
环境变量。
模块缓存没有最大大小,go
命令不会自动删除其内容。
同一台机器上的多个 Go 项目可以共享缓存。go
命令将使用相同的缓存,无论主模块的位置如何。多个go
命令实例可以安全地同时访问同一个模块缓存。
go
命令以只读权限在缓存中创建模块源文件和目录,以防止在下载模块后意外更改它们。这具有不幸的副作用,即难以使用rm -rf
等命令删除缓存。可以使用go clean -modcache
删除缓存。或者,当使用-modcacherw
标志时,go
命令将创建新的目录,并赋予它们读写权限。这增加了编辑器、测试和其他程序修改模块缓存中文件的风险。go mod verify
命令可用于检测对主模块依赖项的修改。它扫描每个模块依赖项的提取内容,并确认它们与go.sum
中预期的哈希值匹配。
下表解释了模块缓存中大多数文件的用途。一些临时文件(锁文件、临时目录)被省略。对于每个路径,$module
是模块路径,$version
是版本。以斜杠 (/
) 结尾的路径是目录。模块路径和版本中的大写字母使用感叹号 (!
) 进行了转义 (Azure
转义为 !azure
),以避免在不区分大小写的文件系统上发生冲突。
路径 | 描述 |
---|---|
$module@$version/ |
包含已提取的模块.zip 文件内容的目录。这用作已下载模块的模块根目录。如果原始模块没有go.mod 文件,它将不会包含go.mod 文件。 |
cache/download/ |
包含从模块代理下载的文件和从版本控制系统派生的文件的目录。此目录的布局遵循GOPROXY 协议,因此,此目录可以在由 HTTP 文件服务器提供服务时或通过file:// URL 引用时用作代理。 |
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
来验证哈希值。压缩文件哈希值计算起来很昂贵,因此go
命令会检查与压缩文件一起存储的预先计算的哈希值,而不是重新哈希文件。可以使用go mod verify
命令来检查压缩文件和解压缩目录自添加到模块缓存后是否被修改。
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 运行。它是一个透明日志(或“Merkle 树”)的go.sum
行哈希值,由Trillian支持。Merkle 树的主要优势在于独立审计员可以验证它没有被篡改,因此它比简单的数据库更可信。
go
命令使用最初在Proposal: Secure the Public Go Module Ecosystem中概述的协议与校验和数据库交互。
下表指定了校验和数据库必须响应的查询。对于每个路径,$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/[email protected]
。
为了避免在从不区分大小写的文件系统中提供服务时出现歧义,$module
和$version
元素通过将每个大写字母替换为感叹号后跟相应的小写字母来进行大小写编码。这使得模块example.com/M
和example.com/m
都可以在磁盘上存储,因为前者被编码为example.com/!m
。
路径中用方括号包围的部分,例如[.p/$W]
,表示可选值。
路径 | 描述 |
---|---|
$base/latest |
返回最新日志的已签名编码树描述。此签名描述采用注释的形式,它是由一个或多个服务器密钥签名的文本,可以使用服务器的公钥进行验证。树描述提供了树的大小和该大小下树头的哈希值。此编码在 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
,或如果go get
使用-insecure
标志调用,则不会咨询校验和数据库,并且所有无法识别的模块都被接受,但代价是放弃对所有模块的已验证可重复下载的安全保证。绕过特定模块的校验和数据库的更好方法是使用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 |
|
术语表
构建约束:确定编译包时是否使用 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 目录:一个名为 vendor
的目录,它包含构建主模块中的包所需的其他模块的包。使用 go mod vendor
进行维护。参见 供应商管理。
版本:模块的不可变快照的标识符,写为字母 v
后跟语义版本。参见关于 版本 的部分。
工作区:磁盘上的一组模块,它们在运行 最小版本选择 (MVS) 时用作主模块。参见关于 工作区 的部分。