字节笔记本

2026年2月22日

GO 依赖管理工具 Go Modules 完全指南(官方推荐)

以前写过一篇关于go管理依赖包工具 dep的文章,当时认为dep将会成为官方依赖工具,现在看来是自己图样图斯内幕破了,正如官方一直提到dep是"official experiment"官方实验项目的那样,随着go modules 在go1.11版推出,go1.12版功能不断改进,再到go1.13版完善优化,正式扶正。预计dep将来也只能定格在"official experiment"了。

Go Modules有哪些特点:

  • 使用简单
  • 管理版本依赖
  • 可以运行在GOPATH之外
  • 可以重命名、删除、升级依赖包
  • 支持版本管理
  • 支持K/V数据库,存储版本依赖信息

如果你的版本是go1.12或更早版本,这里建议升级到go1.13,来体验一把go modules,看它能给你带来哪些方面身心的愉悦。

本文将介绍使用Go Modules相关操作

1、安装Go 1.13或升级到Go 1.13

安装

2、配置环境变量

bash
#修改 GOBIN 路径(可选)
go env -w GOBIN=$HOME/bin
#打开 Go modules
go env -w GO111MODULE=on
#设置 GOPROXY
go env -w GOPROXY=https://goproxy.cn,direct

go env -w: Go1.13 新增了 go env -w 用于写入环境变量,而写入的地方是 os.UserConfigDir 所返回的路径,需要注意的是 go env -w 不会覆写。需要指出,它不会覆盖系统环境变量。

GO111MODULE:

这个环境变量主要是 Go modules 的开关,主要有以下参数:

  • auto:只在项目包含了 go.mod 文件时启用 Go modules,在 Go 1.13 中仍然是默认值,详见 :golang.org/issue/31857。
  • on:无脑启用 Go modules,推荐设置,未来版本中的默认值,让 GOPATH 从此成为历史。
  • off:禁用 Go modules。

GOPROXY:

这个环境变量主要是用于设置 Go 模块代理,它的值是一个以英文逗号 "," 分割的 Go module proxy 列表,默认是proxy.golang.org,国内访问不了。这里要感谢七牛、阿里、goproxy为中国乃至全世界的 Go 语言开发者提供免费、可靠的、持续在线的且经过CDN加速Go module proxy(以七牛为例:goproxy.cn)。

其实值列表中的 "direct" 为特殊指示符,用于指示 Go 回源到模块版本的源地址去抓取(比如 GitHub 等),当值列表中上一个 Go module proxy 返回 404 或 410 错误时,Go 自动尝试列表中的下一个,遇见 "direct" 时回源,遇见 EOF 时终止并抛出类似 "invalid version: unknown revision..." 的错误。

3、创建你的项目

这里我们在 $GOPATH/src 外,创建 /var/www/demo实例

bash
mkdir /var/www/demo
cd /var/www/demo

新建main.go

go
package main

import (
    "github.com/gin-gonic/gin"
    "fmt"
)

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        fmt.Println("hello world!")
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    r.Run() // listen and serve on 0.0.0.0:8080
}

4、在/var/www/demo根目录下

bash
#生成go.mod文件
go mod init demo

打开go.mod文件,内容

text
module demo

go 1.13

go.mod 是启用了 Go moduels 的项目所必须的最重要的文件,它描述了当前项目(也就是当前模块)的元信息,每一行都以一个动词开头,目前有以下 5 个动词:

  • module:用于定义当前项目的模块路径。
  • go:用于设置预期的 Go 版本。
  • require:用于设置一个特定的模块版本。
  • exclude:用于从使用中排除一个特定的模块版本。
  • replace:用于将一个模块版本替换为另外一个模块版本。

这里的填写格式基本为包引用路径+版本号,另外比较特殊的是 go $version,目前从 Go1.13 的代码里来看,还只是个标识作用,暂时未知未来是否有更大的作用。

5、在/var/www/demo根目录下,执行 go build

bash
go build

完成后项目

text
├── demo
├── go.mod
├── go.sum
└── main.go

项目中增加了go.sum、demo文件

go.sum文件内容

text
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
...

go.sum类似于比如 dep 的 Gopkg.lock 的一类文件,它详细罗列了当前项目直接或间接依赖的所有模块版本,并写明了那些模块版本的 SHA-256 哈希值以备 Go在今后的操作中保证项目所依赖的那些模块版本不会被篡改。

我们可以看到一个模块路径可能有如下两种:

text
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=

前者为 Go modules 打包整个模块包文件 zip 后再进行 hash 值,而后者为针对 go.mod 的 hash 值。他们两者,要不就是同时存在,要不就是只存在 go.mod hash。

那什么情况下会不存在 zip hash 呢,就是当 Go 认为肯定用不到某个模块版本的时候就会省略它的 zip hash,就会出现不存在 zip hash,只存在 go.mod hash 的情况。

go.mod文件内容发生了变化,增加了

require github.com/gin-gonic/gin v1.4.0

默认使用最新版本的package。

更换依赖版本

查看gin所有历史版本

bash
go list -m -versions github.com/gin-gonic/gin
github.com/gin-gonic/gin v1.1.1 v1.1.2 v1.1.3 v1.1.4 v1.3.0 v1.4.0

如果想更换依赖版本,比如v1.3.0,怎么办?

只需执行如下命令

bash
go mod edit -require="github.com/gin-gonic/gin@v1.3.0"
go tidy #更新现有依赖

"@后跟版本号,这个时候go.mod已经修改好了

require github.com/gin-gonic/gin v1.3.0

查看所有项目依赖的包

bash
go list -m all
text
github.com/davecgh/go-spew v1.1.0
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3
github.com/gin-gonic/gin v1.4.0
github.com/golang/protobuf v1.3.1
github.com/json-iterator/go v1.1.6
github.com/mattn/go-isatty v0.0.7
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
github.com/modern-go/reflect2 v1.0.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.1.0
github.com/stretchr/testify v1.3.0
github.com/ugorji/go v1.1.4
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
golang.org/x/text v0.3.0
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/go-playground/assert.v1 v1.2.1
gopkg.in/go-playground/validator.v8 v8.18.2
gopkg.in/yaml.v2 v2.2.2

注意

使用go.mod管理依赖会对go get命令产生一定影响,

  • 使用 go modules 时,go get 命令会将包下载到 GOPATH/pkg/mod 目录下
  • 使用 go modules 后,项目可以放在 GOPATH 之外

快速迁移项目至 Go Modules

  • 进入项目目录,执行 go mod init [module] 生成 go.mod 文件
  • 执行 go mod tidy 更新整理现有的依赖,删除未使用的依赖。

go mod 相关命令

  • go mod download - 下载 go.mod 文件中指明的所有依赖
  • go mod tidy - 整理现有的依赖,删除未使用的依赖。
  • go mod graph - 查看现有的依赖结构
  • go mod init [module] - module为项目目录名,生成 go.mod 文件 (Go 1.13 中唯一一个可以生成 go.mod 文件的子命令)
  • go mod edit - 编辑 go.mod 文件
  • go mod vendor - 导出现有的所有依赖 (事实上 Go modules 正在淡化 Vendor 的概念)
  • go mod verify - 校验一个模块是否被篡改过
  • go clean -modcache - 清理所有已缓存的模块版本数据。
  • go mod - 查看所有 go mod的使用命令。

参考资料:

分享: