注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用
本系列为 Go 进阶训练营 笔记,访问 博客: Go进阶训练营, 即可查看当前更新进度,部分文章篇幅较长,使用 PC 大屏浏览体验更佳。
3 月进度: 04/15 3 月开始会尝试爆更模式,争取做到两天更新一篇文章,如果感兴趣可以拉到文章最下方获取关注方式。
本文将会分为两部分,第一部分会简单介绍一下 go module 的使用,算是一个简明教程,第二部分会重点介绍一下使用 go module 使用过程当中会遇到的一些坑的解决办法。
PS: Go 的版本管理一直是一个槽点,虽然 go module 已经解决了很多问题,但是槽点还是比较多,本文会介绍一些常见的坑,如果遇到了其他的坑也不要慌,Google 可以帮助你
从 go 1.11 的初步支持,到 1.16 后的默认开启,go module 已经经历了 5 个版本,已然成为了创建 go 项目的首选包管理方式,这一趴我们就先看一下 go module 的基本使用。
1 | |
执行上述命令会在当前目录下生成一个 go.mod 文件
1 | |
执行 go get 包 添加添加对应库到 go mod 中
1 | |
这时候会在 go mod 中添加如下信息
1 | |
go get github.com/sirupsen/logrus@v1.7.0 的方式,支持@版本号 例如 @v1.7.0@分支名 例如 @master@commit tag 例如 @6cff360233dc4457f1536e4f3df4e4e740fd3410// indirect 表示,我们在代码中没有直接应用这个包执行完 go get 命令之后还会在目录下生成一个 go.sum 文件
1 | |
这个文件主要包含当前依赖的所有的包,像 go-difflib 我们没有直接依赖,但是我们依赖的 logrus 有依赖它,所以会列在这里
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 这一串是一个加密的哈希数据,用来保证这个版本一定是一致的,避免包的发布者删除了这个版本之后,修改代码重复发布
现在我们在代码中使用这个包试试
1 | |
随着我们开发,可能会有一些包,之前依赖但是后面就不再依赖了,这个时候我们如果要清理哪些不再需要的依赖可以执行下面的命令来进行清理
1 | |
go 默认使用语义化的版本来表示版本号,基本的方式
vMAJOR.MINOR.PATCHMAJOR ,例如 v1.0.0 -> v2.0.0MINOR 版本号,例如 v1.1.0 -> v1.2.0PATCH 版本号,例如 v1.1.1 -> v1.1.2- 表示一些特殊的预发布版本例如 alpha beta 版本等v1.1.1-alphav1.1.1-beta.2v0.0.0-20170915032832-14c0d48ead0c1.0 之前的版本发布非常简单,只需要做两件事情
git tag v1.0.0 加一个版本 tag 即可2.0 之后的版本发布就麻烦一些了,因为 Go Module 的限制,v2 之后的版本需要在 go.mod 中显示的指定 /v2 主版本好标识,用户在使用导入包的时候也必须加上这个版本标志,这个好处就是可以同时同时导入不同版本的包,但是在升级的时候就比较蛋疼了,必须要将所有文件的导入路径都修改一下
那么该如何发布新版本的包呢?官方推荐的操作是
v2 文件夹,应为这样可以兼容那些还在使用 GOPATH 的用户,当然这不是必须的go.mod 文件, 在包名后加上主版本号,例如module github.com/mohuishou/go-mod-example/v2git tag v2.0.0 打一个版本并发布即可Go 默认的 GOPROXY 配置是 proxy.golang.org , 默认国内无法访问,我们可以配置国内镜像,推荐 goproxy.cn 或者 goproxy.io
1 | |
1.16 之前 Go Module 并未默认开启还需要配置
1 | |
Go 获取包的时候默认会走 PROXY,这个只要你们的库没有对公网发布,那就获取不到,可以通过设置环境变量解决
1 | |
在 1.16 后, go build, go test, go get 等命令已经不会自动升级我们依赖的包了,但是在 1.16 之前,这个操作很难受。
首先,这个操作非常的反直觉,其次还有可能会导致非预期的 bug,虽然在 Go Module 的设计当中,主版本不变的情况下都应该保持向前兼容,但是很多知名的第三库都做不到这个,包括 Google 自己开发的 grpc,我们之前就出现过由于 grpc 版本自动升级导致的程序连接错误,必须要回退版本才行。
三个解决办法都可以解决:
-mod=readonly ,例如 go build -mod=readonlygo.mod 文件中使用 replace 指令指定版本这个其实在 Go Module 上还好一些,因为 Go Module 默认使用 Go Proxy 只要你使用的库的 LICENSE 和 GOPROXY 没有问题,一般都会有缓存
1 | |
现在这个错误应该比较少了,但是我们碰到过很多次了,主要的原因就是 logrus 的作者改了 github 名字,从 Sirupsen -> sirupsen 就导致了大量依赖 logrus 库的第三方库报错冲突,这个的解决方案也是使用 replace
在 go.mod 的最后加上这么一句就可以了
1 | |
其实很多包管理都有类似的问题,解决方法一般情况下 git merge 合并后再重新执行 go mod tidy 清理一下即可
举个例子,我从 go 1.15 升级到 1.16 想使用 embed,也就是静态文件打包的特性,但是我们发现升级 Go 之后执行还是会报错
1 | |
这种情况修改一下 go.mod 文件中 go 1.15 到 go 1.16 即可
关于 Go Module 的介绍就到这里了,说实话 Go 的包管理一直以来都是社区的痛点,从 GOPATH 到 Go Vendor 再到 dep 、 glide 等社区工具再到现在的 go mod 整体来说还是变得越来越好,特别是最新的 go 1.16 版本,如果没有其他问题的话还是建议升级的,仅默认 readonly 模式这一项就可以少很多事情
注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用
本系列为 Go 进阶训练营 笔记,访问 博客: Go进阶训练营, 即可查看当前更新进度,部分文章篇幅较长,使用 PC 大屏浏览体验更佳。
3 月进度: 04/15 3 月开始会尝试爆更模式,争取做到两天更新一篇文章,如果感兴趣可以拉到文章最下方获取关注方式。
本文将会分为两部分,第一部分会简单介绍一下 go module 的使用,算是一个简明教程,第二部分会重点介绍一下使用 go module 使用过程当中会遇到的一些坑的解决办法。
PS: Go 的版本管理一直是一个槽点,虽然 go module 已经解决了很多问题,但是槽点还是比较多,本文会介绍一些常见的坑,如果遇到了其他的坑也不要慌,Google 可以帮助你
从 go 1.11 的初步支持,到 1.16 后的默认开启,go module 已经经历了 5 个版本,已然成为了创建 go 项目的首选包管理方式,这一趴我们就先看一下 go module 的基本使用。
1 | |
执行上述命令会在当前目录下生成一个 go.mod 文件
1 | |
执行 go get 包 添加添加对应库到 go mod 中
1 | |
这时候会在 go mod 中添加如下信息
1 | |
go get github.com/sirupsen/logrus@v1.7.0 的方式,支持@版本号 例如 @v1.7.0@分支名 例如 @master@commit tag 例如 @6cff360233dc4457f1536e4f3df4e4e740fd3410// indirect 表示,我们在代码中没有直接应用这个包执行完 go get 命令之后还会在目录下生成一个 go.sum 文件
1 | |
这个文件主要包含当前依赖的所有的包,像 go-difflib 我们没有直接依赖,但是我们依赖的 logrus 有依赖它,所以会列在这里
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 这一串是一个加密的哈希数据,用来保证这个版本一定是一致的,避免包的发布者删除了这个版本之后,修改代码重复发布
现在我们在代码中使用这个包试试
1 | |
随着我们开发,可能会有一些包,之前依赖但是后面就不再依赖了,这个时候我们如果要清理哪些不再需要的依赖可以执行下面的命令来进行清理
1 | |
go 默认使用语义化的版本来表示版本号,基本的方式
vMAJOR.MINOR.PATCHMAJOR ,例如 v1.0.0 -> v2.0.0MINOR 版本号,例如 v1.1.0 -> v1.2.0PATCH 版本号,例如 v1.1.1 -> v1.1.2- 表示一些特殊的预发布版本例如 alpha beta 版本等v1.1.1-alphav1.1.1-beta.2v0.0.0-20170915032832-14c0d48ead0c1.0 之前的版本发布非常简单,只需要做两件事情
git tag v1.0.0 加一个版本 tag 即可2.0 之后的版本发布就麻烦一些了,因为 Go Module 的限制,v2 之后的版本需要在 go.mod 中显示的指定 /v2 主版本好标识,用户在使用导入包的时候也必须加上这个版本标志,这个好处就是可以同时同时导入不同版本的包,但是在升级的时候就比较蛋疼了,必须要将所有文件的导入路径都修改一下
那么该如何发布新版本的包呢?官方推荐的操作是
v2 文件夹,应为这样可以兼容那些还在使用 GOPATH 的用户,当然这不是必须的go.mod 文件, 在包名后加上主版本号,例如module github.com/mohuishou/go-mod-example/v2git tag v2.0.0 打一个版本并发布即可Go 默认的 GOPROXY 配置是 proxy.golang.org , 默认国内无法访问,我们可以配置国内镜像,推荐 goproxy.cn 或者 goproxy.io
1 | |
1.16 之前 Go Module 并未默认开启还需要配置
1 | |
Go 获取包的时候默认会走 PROXY,这个只要你们的库没有对公网发布,那就获取不到,可以通过设置环境变量解决
1 | |
在 1.16 后, go build, go test, go get 等命令已经不会自动升级我们依赖的包了,但是在 1.16 之前,这个操作很难受。
首先,这个操作非常的反直觉,其次还有可能会导致非预期的 bug,虽然在 Go Module 的设计当中,主版本不变的情况下都应该保持向前兼容,但是很多知名的第三库都做不到这个,包括 Google 自己开发的 grpc,我们之前就出现过由于 grpc 版本自动升级导致的程序连接错误,必须要回退版本才行。
三个解决办法都可以解决:
-mod=readonly ,例如 go build -mod=readonlygo.mod 文件中使用 replace 指令指定版本这个其实在 Go Module 上还好一些,因为 Go Module 默认使用 Go Proxy 只要你使用的库的 LICENSE 和 GOPROXY 没有问题,一般都会有缓存
1 | |
现在这个错误应该比较少了,但是我们碰到过很多次了,主要的原因就是 logrus 的作者改了 github 名字,从 Sirupsen -> sirupsen 就导致了大量依赖 logrus 库的第三方库报错冲突,这个的解决方案也是使用 replace
在 go.mod 的最后加上这么一句就可以了
1 | |
其实很多包管理都有类似的问题,解决方法一般情况下 git merge 合并后再重新执行 go mod tidy 清理一下即可
举个例子,我从 go 1.15 升级到 1.16 想使用 embed,也就是静态文件打包的特性,但是我们发现升级 Go 之后执行还是会报错
1 | |
这种情况修改一下 go.mod 文件中 go 1.15 到 go 1.16 即可
关于 Go Module 的介绍就到这里了,说实话 Go 的包管理一直以来都是社区的痛点,从 GOPATH 到 Go Vendor 再到 dep 、 glide 等社区工具再到现在的 go mod 整体来说还是变得越来越好,特别是最新的 go 1.16 版本,如果没有其他问题的话还是建议升级的,仅默认 readonly 模式这一项就可以少很多事情