发布于 2026-01-06 1 阅读
0

Go 语言中的包管理

Go 语言中的包管理

包管理一直是 Go 语言的短板之一。之前的版本(1.11 之前)的主要缺陷之一go get是缺乏对依赖版本管理和可复现构建的支持。社区已经开发了 Glide、dep 等包管理器和工具,它们已成为事实上的依赖版本控制解决方案。

“我在生产环境中构建时使用 go get。”——从来没有人这么说过。

Go 的包管理实现可以追溯到 Google(它拥有一个庞大的单体代码仓库来存放所有源代码)。让我们来分析一下“go 模块出现之前”的包管理工具存在哪些问题。

  1. 版本控制依赖项
  2. 供应商依赖项
  3. 必要性GOPATH

版本控制依赖项

go get默认情况下不支持模块版本控制。Go 包管理的第一个版本背后的理念是——无需模块版本控制,无需第三方模块仓库,所有内容都从当前分支构建。

在 Go 1.11 之前,添加依赖项意味着克隆该依赖项的源代码仓库到你的项目中GOPATH。仅此而已。当时没有版本的概念。它始终指向克隆时当前的 master 分支。另一个主要问题是,当不同的项目需要不同版本的依赖项时——这在当时也是无法实现的。

供应商依赖项

包管理通常是指将依赖包存储在与项目相同的位置。这通常意味着依赖项会被提交到源代码管理系统(例如 Git)中。

考虑以下情况:A 使用了依赖项 B,而 B 又使用了依赖项 C 在 1.5 版本中引入的一个特性。因此,B 必须确保 A 的构建使用的是 C 1.5 或更高版本。在 Go 1.5 之前,没有机制可以在不重写导入路径的情况下,将依赖项代码与命令一起传递。

必要性GOPATH

GOPATH存在的原因主要有两个:

  1. 在 Go 语言中,import声明通过包的完全限定导入路径来引用它。GOPATH这样,GOPATH/srcgo 工具就可以从任何目录中计算出相关包的绝对导入路径。
  2. 用于存储从……获取的依赖项的位置go get.

这有什么问题?

  1. GOPATH它不允许像其他语言那样,在选定的目录中检出项目的源代码。
  2. 此外,GOPATH它不允许开发者同时检出多个项目(或其依赖项)副本。

Go 模块简介

Go 1.11 引入了对 Go 模块的初步支持。摘自 Go Wiki:

模块是一组相关的 Go 包的集合,这些包作为一个整体进行版本控制。模块记录精确的依赖关系,并创建可复现的构建

Go模块内置了三个重要功能,

1)go.mod文件类似于package.jsonPipfile

2) 机器生成的传递依赖关系描述 - go.sum

3)不再有GOPATH限制。模块可以位于任何路径中。

$ go help mod
Go mod provides access to operations on modules.

Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.

Usage:

    go mod <command> [arguments]

The commands are:

    download    download modules to local cache
    edit        edit go.mod from tools or scripts
    graph       print module requirement graph
    init        initialize new module in current directory
    tidy        add missing and remove unused modules
    vendor      make vendored copy of dependencies
    verify      verify dependencies have expected content
    why         explain why packages or modules are needed

Use "go help mod <command>" for more information about a command.

相关讨论帖

迁移到 Go Modules

要使用 Go 模块,请将 Go 更新到最新版本>= 1.11。由于GOPATH旧版本即将弃用,可以通过以下两种方式之一启用模块支持:

  • go在目录树之外的目录中调用该命令,并使用当前目录中的GOPATH/src有效文件。go.mod
  • 如果源代码位于 `<source>` 目录下,Go 模块将无法正常工作GOPATH。要覆盖此行为,请调用go命令并GO111MODULE=on设置环境变量。

让我们按照以下简单步骤开始移植:

  • 由于GOPATH不再需要,请将模块移出GOPATH

  • 从项目根目录创建初始模块定义go mod init github.com/username/repository。最棒的是,go mod它会自动转换来自现有包管理器(例如、和其他六个)的依赖项depGopkg创建一个名为的文件,glide其中包含模块名称、依赖项及其版本。go.mod

$ cat go.mod
module github.com/deepsourcelabs/cli

go 1.12

require (
    github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e
    github.com/getsentry/raven-go v0.2.0
    github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9
  • 运行此命令go build以创建一个go.sum文件,其中包含特定模块版本内容的预期加密校验和。这是为了确保将来下载这些模块时,能够获取与首次下载相同的数据。请注意,go.sum 不是锁定文件。
$ cat go.sum
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e h1:9574pc8MX6rF/QyO14SPHhM5KKIOo9fkb/1ifuYMTKU=
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9 h1:dIsTcVF0w9viTLHXUEkDI7cXITMe+M/MRRM2MwisVow=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

版本说明:为了保持向后兼容性,如果模块版本为 v2 或更高版本,则必须/vN在文件中使用的模块路径末尾添加模块的主版本号go.mod(例如,`--main`)。module github.com/username/repository/v2

日常指令

列出依赖项

go list -m all列出当前模块及其所有依赖项。

$ go list -m all
github.com/deepsourcelabs/cli
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e
github.com/getsentry/raven-go v0.2.0
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9

go list输出中,当前模块(也称为主模块)始终是第一行,后面是按模块路径排序的依赖项。

列出软件包的可用版本

go list -m -versions github.com/username/repository列出软件包的可用版本。

$ go list -m -versions github.com/getsentry/raven-go
github.com/getsentry/raven-go v0.1.0 v0.1.1 v0.1.2 v0.2.0

添加依赖项

添加依赖项是隐式的。在代码中导入依赖项后,运行 `import`go build或 ` go testadd` 命令会自动获取模块的最新版本并将其添加到go.mod文件中。如果您想显式地添加依赖项,请运行 `add` 命令go get github.com/username/repository

升级/降级依赖项

go get github.com/username/repository@vx.x.x下载并设置依赖项的特定版本,并更新go.mod文件。

$ go get github.com/getsentry/raven-go@v0.1.2
go: finding github.com/getsentry/raven-go v0.1.2
go: downloading github.com/getsentry/raven-go v0.1.2
go: extracting github.com/getsentry/raven-go v0.1.2
$ cat go.mod 
module github.com/deepsourcelabs/marvin-go

go 1.12

require (
    github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e
    github.com/getsentry/raven-go v0.1.2
    github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9
)
$ cat go.sum
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e h1:9574pc8MX6rF/QyO14SPHhM5KKIOo9fkb/1ifuYMTKU=
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/getsentry/raven-go v0.1.2 h1:4V0z512S5mZXiBvmW2RbuZBSIY1sEdMNsPjpx2zwtSE=
github.com/getsentry/raven-go v0.1.2/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9 h1:dIsTcVF0w9viTLHXUEkDI7cXITMe+M/MRRM2MwisVow=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

供应商依赖项

使用模块时,go 命令会完全忽略 vendor 目录。为了向后兼容旧版本的 Go,或者确保构建所需的所有文件都存储在同一个文件树中,请运行go mod vendor.

这会vendor在主模块的根目录中创建一个名为 `<directory_name>` 的目录,并将所有依赖模块的包存储在该目录中。

注意:要使用主模块的顶级 vendor 目录进行构建,请运行“go build -mod=vendor”。

移除未使用的依赖项

go mod tidy删除未使用的依赖项并更新go.mod文件。

常见问题解答

不再GOPATH需要了吗?

不,再见GOPATH

默认情况下会拉取哪个版本?

go.mod 文件以及更普遍的 go 命令都使用语义版本作为描述模块版本的标准形式,以便比较不同版本,从而确定哪个版本应该被视为更早或更晚。模块版本(例如 `<version>`)v1.2.3是通过在底层源代码仓库中标记修订版本来引入的。未标记的修订版本可以使用类似 `<version>` 的“伪版本”来引用v0.0.0-yyyymmddhhmmss-abcdefabcdef,其中时间是 UTC 时间的提交时间,最后一个后缀是提交哈希值的前缀。

是否应该go.sum纳入版本控制系统?

是的。

文章来源:https://dev.to/deepsource/package-management-in-go-4dhj