管理依赖项
当您的代码使用外部包时,这些包(作为模块分发)成为依赖项。随着时间的推移,您可能需要升级或更换它们。Go 提供了依赖管理工具,可帮助您在合并外部依赖项时确保 Go 应用程序的安全.
本主题介绍如何执行任务以管理您在代码中采用的依赖项。您可以使用 Go 工具执行其中的大部分操作。本主题还介绍了如何执行其他一些您可能会觉得有用的依赖相关任务.
另请参见
- 如果您不熟悉将依赖项作为模块使用,请查看 入门教程 以获得简要介绍。
- 使用
go
命令管理依赖项有助于确保您的需求保持一致,并且您的 go.mod 文件的内容是有效的。有关命令的参考,请参阅Command go。您还可以通过键入go help
command-name 从命令行获取帮助,如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
命令 将该模块添加为依赖项进行管理.
该命令执行以下操作:
-
如果需要,它会将
require
指令添加到 go.mod 文件中,用于构建命令行上指定的包所需的模块。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)中,或者在具有使用它们的当前模块的驱动器上。
您可能希望在以下情况下执行此操作:
- 您想对外部模块的代码进行自己的更改,例如在forking和/或克隆它之后。例如,您可能想要准备对模块进行修复,然后将其作为拉取请求发送给模块的开发人员。
- 您正在构建一个新模块并且尚未发布它,因此它在
go get
命令可以访问它的存储库上不可用.
在本地目录中Requiring模块代码
您可以指定所需模块的代码与需要它的代码位于同一本地驱动器上。在以下情况下,您可能会发现这很有用:
- 开发自己的单独模块并希望从当前模块进行测试.
- 修复外部模块中的问题或向外部模块添加功能,并希望从当前模块进行测试。(请注意,您也可以从其存储库的自己的fork中require外部模块。有关详细信息,请参阅从您自己的存储库fork中Requiring外部模块代码。)
若要告诉 Go 命令使用模块代码的本地副本,请使用 go.mod 文件中的 replace
指令替换 require
指令中给定的模块路径.有关指令的更多信息,请参阅 go.mod 参考.
在以下 go.mod 文件示例中,当前模块需要外部模块 example.com/theirmodule
,并使用不存在的版本号(v0.0.0-unpublished
)来确保替换正常工作。然后,replace
指令将原始模块路径替换为../theirmodule
,与当前模块的目录处于同一级别的目录.
module example.com/mymodule
go 1.16
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 -d example.com/theirmodule@v0.0.0-unpublished
注意: 使用 replace 指令时,Go 工具不会对外部模块进行身份验证,如添加依赖项中所述.
有关版本号的更多信息,请参阅模块版本编号.
Requiring来自您自己的存储库fork的外部模块代码
当您对外部模块的存储库进行了 fork (例如修复模块代码中的问题或添加功能)时,您可以让 Go 工具将您的 fork 用于模块的源代码。这对于测试您自己的代码中的更改非常有用。(请注意,您还可以要求将模块代码与需要它的模块一起放在本地驱动器上的目录中。有关详细信息,请参阅在本地目录中Requiring模块代码。)
为此,请在 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.16
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 工具处理模块时,这些工具默认从 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"
-
当您使用管道时,Go 工具将尝试列表中的下一个 URL,而不管 HTTP 错误代码如何。
GOPROXY="https://proxy.example.com|https://proxy2.example.com"
Go 模块经常在不是公网上的版本控制服务器和模块代理上开发和分发。您可以设置 GOPRIVATE
环境变量。您可以设置GOPRIVATE
环境变量来配置go
命令以从私有源下载和构建模块。然后 go 命令可以从私有源下载和构建模块。
GOPRIVATE
或 GONOPROXY
环境变量可以设置为与模块前缀匹配的 glob 模式列表,这些模块前缀是私有的,不应从任何代理请求。例如:
GOPRIVATE=*.corp.example.com,*.research.example.com