管理依赖项
当您的代码使用外部包时,这些包(以模块形式分发)就变成了依赖项。随着时间的推移,您可能需要升级或替换它们。Go 提供了依赖管理工具,帮助您在使用外部依赖项时确保 Go 应用程序的安全。
本主题描述了如何执行管理代码中依赖项的任务。您可以使用 Go 工具执行大部分这些任务。本主题还描述了如何执行其他一些可能对您有用的依赖相关任务。
另请参阅
- 如果您刚开始使用模块管理依赖项,请参阅入门教程,了解简要介绍。
- 使用
go
命令管理依赖项有助于确保您的需求保持一致,并且 go.mod 文件的内容有效。有关命令的参考信息,请参阅Command go。您还可以通过在命令行输入go help
命令名称 来获取帮助,例如go help mod tidy
。 - 您用于更改依赖项的 Go 命令会编辑您的 go.mod 文件。有关该文件内容的更多信息,请参阅go.mod 文件参考。
- 让您的编辑器或 IDE 了解 Go 模块可以使管理它们的工作更容易。有关支持 Go 的编辑器的更多信息,请参阅编辑器插件和 IDE。
- 本主题不描述如何开发、发布和版本化供他人使用的模块。有关这方面的内容,请参阅开发和发布模块。
使用和管理依赖项的工作流程
您可以使用 Go 工具获取和使用有用的包。在pkg.go.dev上,您可以搜索可能对您有用的包,然后使用 go
命令将这些包导入到您自己的代码中以调用其函数。
以下列出了最常见的依赖管理步骤。有关每个步骤的更多信息,请参阅本主题中的相关部分。
- 在pkg.go.dev上查找有用的包。
- 在您的代码中导入您想要的包。
- 将您的代码添加到模块中以进行依赖跟踪(如果它尚未在模块中)。请参阅启用依赖跟踪
- 添加外部包作为依赖项,以便您可以管理它们。
- 随着时间的推移,根据需要升级或降级依赖项版本。
将依赖项作为模块管理
在 Go 中,您将依赖项作为包含您导入的包的模块进行管理。此过程得到以下支持:
- 一个分散式系统,用于发布模块和检索其代码。开发者可以将他们的模块从自己的仓库提供给其他开发者使用,并发布带有版本号的模块。
- 一个包搜索引擎和文档浏览器 (pkg.go.dev),您可以在其中找到模块。请参阅查找和导入有用的包。
- 一个模块版本号约定,帮助您了解模块的稳定性和向后兼容性保证。请参阅模块版本号。
- Go 工具,让您更容易管理依赖项,包括获取模块源代码、升级等等。有关更多信息,请参阅本主题中的相关部分。
查找和导入有用的包
您可以在pkg.go.dev上搜索,查找包含您可能觉得有用的函数的包。
当您找到了想要在代码中使用的包时,请找到页面顶部的包路径,然后单击“复制路径”按钮将路径复制到剪贴板。在您自己的代码中,将路径粘贴到导入语句中,如下例所示:
import "rsc.io/quote"
您的代码导入包后,启用依赖跟踪并获取包代码以便编译。有关更多信息,请参阅在您的代码中启用依赖跟踪和添加依赖项。
在您的代码中启用依赖跟踪
要跟踪和管理您添加的依赖项,首先要将您的代码放入自己的模块中。这会在您的源代码树根部创建一个 go.mod 文件。您添加的依赖项将列在该文件中。
要将您的代码添加到自己的模块中,请使用go mod init
命令。例如,从命令行进入代码的根目录,然后运行如下示例所示的命令:
$ go mod init example/mymodule
go mod init
命令的参数是您的模块路径。如果可能,模块路径应该是您的源代码仓库位置。
如果您一开始不知道模块最终的仓库位置,请使用一个安全的替代名称。这可能是您拥有的域名或其他您控制的名称(例如您的公司名称),以及模块名称或源目录之后的路径。有关更多信息,请参阅命名模块。
在使用 Go 工具管理依赖项时,工具会更新 go.mod 文件,以便它维护一个当前的依赖项列表。
当您添加依赖项时,Go 工具还会创建一个 go.sum 文件,其中包含您依赖的模块的校验和。Go 使用它来验证下载的模块文件的完整性,特别是对于在您的项目上工作的其他开发者。
将 go.mod 和 go.sum 文件与您的代码一起包含在您的仓库中。
有关更多信息,请参阅go.mod 参考。
命名模块
当您运行 go mod init
创建模块来跟踪依赖项时,您需要指定一个用作模块名称的模块路径。模块路径将成为模块中包的导入路径前缀。请确保指定的模块路径不会与其他模块的模块路径冲突。
至少,模块路径只需要指示一些关于其来源的信息,例如公司、作者或所有者名称。但路径也可以更具描述性地说明模块是什么或做什么。
模块路径通常采用以下形式:
<prefix>/<descriptive-text>
-
前缀通常是一个部分描述模块的字符串,例如描述其来源的字符串。这可能是:
-
Go 工具可以找到模块源代码的仓库位置(如果您要发布模块,这是必需的)。
例如,它可能是
github.com/<project-name>/
。如果您认为可能会发布此模块供他人使用,请遵循此最佳实践。有关发布的更多信息,请参阅开发和发布模块。
-
您控制的名称。
如果您不使用仓库名称,请确保选择一个您确信不会被他人使用的前缀。一个不错的选择是您公司的名称。避免使用
widgets
、utilities
或app
等常见术语。
-
-
对于描述性文本,一个不错的选择是项目名称。请记住,包名称承担了大部分描述功能的责任。模块路径为这些包名称创建了一个命名空间。
保留的模块路径前缀
Go 保证以下字符串不会在包名称中使用。
-
test
– 您可以使用test
作为模块路径前缀,用于代码设计用于本地测试另一个模块中函数的模块。为作为测试一部分创建的模块使用
test
路径前缀。例如,您的测试本身可以运行go mod init test
,然后以某种特定方式设置该模块,以便使用 Go 源代码分析工具进行测试。 -
example
– 在某些 Go 文档中用作模块路径前缀,例如在您仅为跟踪依赖项而创建模块的教程中。请注意,Go 文档也使用
example.com
来演示示例何时可能是已发布的模块。
添加依赖项
一旦您从已发布的模块导入了包,您就可以使用go get
命令将该模块添加为依赖项进行管理。
该命令执行以下操作:
-
如果需要,它会向您的 go.mod 文件添加
require
指令,以满足命令行中指定的包所需的模块。require
指令跟踪您的模块所依赖的模块的最低版本。有关更多信息,请参阅go.mod 参考。 -
如果需要,它会下载模块源代码,以便您可以编译依赖它们的包。它可以从模块代理(例如 proxy.golang.org)或直接从版本控制仓库下载模块。源代码会本地缓存。
您可以设置 Go 工具下载模块的位置。有关更多信息,请参阅指定模块代理服务器。
以下是一些示例。
-
要添加模块中包的所有依赖项,请运行类似下面的命令("." 指当前目录中的包):
$ go get .
-
要添加特定的依赖项,请将其模块路径指定为命令的参数。
$ go get example.com/theirmodule
该命令还会对下载的每个模块进行身份验证。这确保了模块自发布以来未被更改。如果模块自发布以来发生了变化——例如,开发者更改了提交的内容——Go 工具会显示一个安全错误。此身份验证检查可以保护您免受可能被篡改的模块的侵害。
获取特定依赖版本
您可以通过在 go get
命令中指定依赖模块的版本来获取其特定版本。该命令会更新您的 go.mod 文件中的 require
指令(尽管您也可以手动更新)。
您可能需要这样做的情况包括:
- 您想获取模块的特定预发布版本进行尝试。
- 您发现当前所需的版本无法正常工作,因此想获取一个您已知可靠的版本。
- 您想升级或降级一个您已经需要的模块。
以下是使用 go get
命令 的示例:
-
要获取特定的带版本号的版本,请在模块路径后附加 @ 符号,后跟您想要的版本:
$ go get example.com/theirmodule@v1.3.4
-
要获取最新版本,请在模块路径后附加
@latest
:$ go get example.com/theirmodule@latest
以下 go.mod 文件 require
指令示例(更多信息请参阅 go.mod 参考)展示了如何指定特定版本号:
require example.com/theirmodule v1.3.4
发现可用更新
您可以检查当前模块中正在使用的依赖项是否有更新版本。使用 go list
命令可以显示模块依赖项列表及其可用的最新版本。发现可用升级后,您可以在代码中尝试它们,以决定是否升级到新版本。
有关 go list
命令的更多信息,请参阅 go list -m
。
以下是几个示例:
-
列出当前模块的所有依赖模块及其各自可用的最新版本:
$ go list -m -u all
-
显示特定模块可用的最新版本:
$ go list -m -u example.com/theirmodule
升级或降级依赖项
您可以使用 Go 工具发现可用版本,然后将不同版本添加为依赖项来升级或降级依赖模块。
同步代码依赖项
您可以确保管理代码中所有导入包的依赖项,同时移除不再导入的包的依赖项。
当您对代码和依赖项进行更改时,这会非常有用,这些更改可能会导致已管理的依赖项和已下载的模块集合不再与代码中导入的包所需的确切集合匹配。
为了保持您的已管理依赖项集合整洁,请使用 go mod tidy
命令。此命令会根据代码中导入的包集合,编辑您的 go.mod 文件,添加必要但缺失的模块。它还会移除未使用的、不提供任何相关包的模块。
除了一个用于打印已移除模块信息的标志 -v 之外,该命令没有其他参数。
$ go mod tidy
针对未发布的模块代码进行开发和测试
您可以指定您的代码应使用可能尚未发布的依赖模块。这些模块的代码可能位于其各自的仓库、这些仓库的派生(fork)或与使用它们的当前模块位于同一驱动器上。
您可能希望在以下情况下这样做:
- 您想对外部模块的代码进行自己的修改,例如在 fork 或克隆之后。例如,您可能想为模块准备一个修复程序,然后将其作为拉取请求发送给模块开发者。
- 您正在构建一个新模块,但尚未发布,因此它在
go get
命令无法访问的仓库中不可用。
需要本地目录中的模块代码
您可以指定所需模块的代码与需要它的代码位于同一本地驱动器上。当您处于以下情况时,可能会发现这很有用:
- 开发您自己的独立模块并想从当前模块进行测试。
- 修复外部模块中的问题或为其添加功能,并想从当前模块进行测试。(请注意,您也可以从其仓库的您自己的派生(fork)中需要该外部模块。更多信息请参阅 需要您自己的仓库派生(fork)中的外部模块代码。)
要告知 Go 命令使用模块代码的本地副本,请在 go.mod 文件中使用 replace
指令替换 require
指令中给定的模块路径。有关指令的更多信息,请参阅 go.mod 参考。
在以下 go.mod 文件示例中,当前模块需要外部模块 example.com/theirmodule
,并使用一个不存在的版本号 (v0.0.0-unpublished
) 来确保替换正确工作。然后,replace
指令将原始模块路径替换为 ../theirmodule
,这是一个与当前模块目录处于同一级别的目录。
module example.com/mymodule
go 1.23.0
require example.com/theirmodule v0.0.0-unpublished
replace example.com/theirmodule v0.0.0-unpublished => ../theirmodule
设置 require
/replace
对时,请使用 go mod edit
和 go get
命令以确保文件描述的要求保持一致:
$ go mod edit -replace=example.com/theirmodule@v0.0.0-unpublished=../theirmodule
$ go get example.com/theirmodule@v0.0.0-unpublished
注意:当您使用 replace 指令时,Go 工具不会像 添加依赖项 中描述的那样验证外部模块。
有关版本号的更多信息,请参阅 模块版本编号。
需要您自己的仓库派生(fork)中的外部模块代码
当您派生(fork)了外部模块的仓库(例如为了修复模块代码中的问题或添加功能)后,您可以让 Go 工具使用您的派生(fork)作为模块的源。这对于从您自己的代码中测试更改非常有用。(请注意,您也可以在与需要它的模块位于同一本地驱动器上的目录中需要该模块代码。更多信息请参阅 需要本地目录中的模块代码。)
您可以通过在 go.mod 文件中使用 replace
指令来实现此目的,将外部模块的原始模块路径替换为您仓库中派生(fork)的路径。这会指示 Go 工具在编译时使用替换路径(派生(fork)的位置),例如,同时允许您保持 import
语句与原始模块路径不变。
有关 replace
指令的更多信息,请参阅 go.mod 文件参考。
在以下 go.mod 文件示例中,当前模块需要外部模块 example.com/theirmodule
。然后,replace
指令将原始模块路径替换为 example.com/myfork/theirmodule
,这是该模块自身仓库的派生(fork)。
module example.com/mymodule
go 1.23.0
require example.com/theirmodule v1.2.3
replace example.com/theirmodule v1.2.3 => example.com/myfork/theirmodule v1.2.3-fixed
设置 require
/replace
对时,使用 Go 工具命令以确保文件描述的要求保持一致。使用 go list
命令获取当前模块使用的版本。然后使用 go mod edit
命令将所需的模块替换为派生(fork):
$ go list -m example.com/theirmodule
example.com/theirmodule v1.2.3
$ go mod edit -replace=example.com/theirmodule@v1.2.3=example.com/myfork/theirmodule@v1.2.3-fixed
注意:当您使用 replace
指令时,Go 工具不会像 添加依赖项 中描述的那样验证外部模块。
有关版本号的更多信息,请参阅 模块版本编号。
使用仓库标识符获取特定提交
您可以使用 go get
命令从模块仓库中的特定提交中添加未发布的模块代码。
为此,您使用 go get
命令,用 @
符号指定您想要的代码。当您使用 go get
时,该命令将向您的 go.mod 文件添加一个 require
指令,该指令需要外部模块,并使用基于提交详细信息的伪版本号。
以下示例提供了一些说明。这些示例基于源位于 git 仓库中的模块。
-
要获取特定提交处的模块,请附加形式为 @commithash:
$ go get example.com/theirmodule@4cf76c2
-
要获取特定分支处的模块,请附加形式为 @branchname:
$ go get example.com/theirmodule@bugfixes
移除依赖项
当您的代码不再使用模块中的任何包时,您可以停止将该模块作为依赖项进行跟踪。
要停止跟踪所有未使用的模块,请运行 go mod tidy
命令。此命令也可能会添加构建模块中包所需的缺失依赖项。
$ go mod tidy
要移除特定依赖项,请使用 go get
命令,指定模块的模块路径并附加 @none
,如下例所示:
$ go get example.com/theirmodule@none
go get
命令还会降级或移除依赖于已移除模块的其他依赖项。
工具依赖项
工具依赖项允许您管理使用 Go 编写并在处理模块时使用的开发者工具。例如,您可能会将 stringer
与 go generate
一起使用,或者使用特定的 linter 或 formatter 作为准备提交更改的一部分。
在 Go 1.24 及更高版本中,您可以使用以下命令添加工具依赖项:
$ go get -tool golang.org/x/tools/cmd/stringer
这会将 tool
指令 添加到您的 go.mod
文件中,并确保存在必要的 require 指令。添加此指令后,您可以通过将工具导入路径的最后一个 非主版本 组件传递给 go tool
来运行该工具:
$ go tool stringer
如果多个工具共享最后一个路径片段,或者路径片段与 Go 分发版附带的工具之一匹配,则必须传递完整的包路径:
$ go tool golang.org/x/tools/cmd/stringer
要查看当前所有可用工具的列表,请不带任何参数运行 go tool
:
$ go tool
您可以手动将 tool
指令添加到您的 go.mod
中,但必须确保存在定义该工具的模块的 require
指令。添加任何缺失的 require
指令的最简单方法是运行:
$ go mod tidy
满足工具依赖项所需的依赖项行为与您 模块图 中的任何其他依赖项一样。它们参与 最小版本选择 并遵守 require
、replace
和 exclude
指令。由于模块修剪,当您依赖一个本身具有工具依赖项的模块时,仅为满足该工具依赖项而存在的依赖项通常不会成为您模块的依赖项。
tool
元模式 提供了一种同时对所有工具执行操作的方法。例如,您可以使用 go get -u tool
升级所有工具,或者使用 go install tool
将它们全部安装到 $GOBIN。
在 Go 1.24 之前的版本中,您可以通过在模块内的 Go 文件中添加一个空导入来实现类似于 tool
指令的功能,该文件使用 构建约束 从构建中排除。如果这样做,您就可以使用带完整包路径的 go run
来运行该工具。
指定模块代理服务器
当您使用 Go 工具处理模块时,这些工具默认从 proxy.golang.org(一个由 Google 运营的公共模块镜像)或直接从模块的仓库下载模块。您可以指定 Go 工具应改用另一个代理服务器来下载和验证模块。
如果您(或您的团队)设置或选择了您想使用的其他模块代理服务器,您可能希望这样做。例如,有些人设置模块代理服务器是为了更好地控制依赖项的使用方式。
要为 Go 工具指定其他模块代理服务器,请将 GOPROXY
环境变量设置为一个或多个服务器的 URL。Go 工具将按您指定的顺序尝试每个 URL。默认情况下,GOPROXY
首先指定一个由 Google 运营的公共模块代理,然后直接从模块仓库下载(如其模块路径中所指定):
GOPROXY="https://proxy.golang.org,direct"
有关 GOPROXY
环境变量的更多信息,包括支持其他行为的值,请参阅 go
命令参考。
您可以将该变量设置为其他模块代理服务器的 URL,使用逗号或竖线分隔 URL。
-
当您使用逗号时,Go 工具仅在当前 URL 返回 HTTP 404 或 410 时才会尝试列表中的下一个 URL。
GOPROXY="https://proxy.example.com,https://proxy2.example.com"
-
当您使用竖线时,无论 HTTP 错误代码是什么,Go 工具都会尝试列表中的下一个 URL。
GOPROXY="https://proxy.example.com|https://proxy2.example.com"
Go 模块经常在版本控制服务器和模块代理上开发和分发,这些服务器和代理在公共互联网上不可用。您可以设置 GOPRIVATE
环境变量来配置 go
命令从私有源下载和构建模块。然后 go 命令就可以从私有源下载和构建模块。
GOPRIVATE
或 GONOPROXY
环境变量可以设置为匹配私有模块前缀的 glob 模式列表,这些私有模块不应从任何代理请求。例如:
GOPRIVATE=*.corp.example.com,*.research.example.com