前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言技巧 - 5.【初探Go Module】Go语言的版本管理

Go语言技巧 - 5.【初探Go Module】Go语言的版本管理

作者头像
junedayday
发布2021-08-05 10:29:21
8550
发布2021-08-05 10:29:21
举报
文章被收录于专栏:Go编程点滴

Go Mod的官方说明

Go语言自从推出了go mod作为版本管理工具后,结束Go语言版本管理工具的纷争,实现了大一统。

相信有很多人都对这个版本管理的机制都有基础的概念、但并不深入。而官方把最核心的实现,都放在这一篇 https://golang.org/ref/mod 文档中。

今天,我们一起来读读这一篇文章。

快速入门 - 5篇介绍Go Mod系列的官方博客

新手直接阅读这篇文章的门槛有点高,我建议可以先看看下面这五篇较为通俗的官方博客,能帮助我们了解一些背景知识。

1. using-go-modules

https://blog.golang.org/using-go-modules

  1. go.mod放在项目的根目录,抛弃原来的GOPATH
  2. MAJOR.MINOR.PATCH格式管理版本,详细可参考Semantic Versioning 2.0.0
  3. go.sum保证依赖文件被完整下载(如果公司搭建私有库就会出现校验问题,需要关闭GOSUM)
  4. 项目内部的库,不再是相对路径,而用的是 go mod模块名 + 相对路径 ,定义更加清晰

第四点的价值很大,可读性大大提高,我们可以将一整个path来辅助命名,如 market/order,前者market可以帮助后者order的含义做一定补充

2. migrating-to-go-modules

https://blog.golang.org/migrating-to-go-modules

将项目迁移到go mod,主要讲的是对接老的版本管理系统,如godeps

3. publishing-go-modules

https://blog.golang.org/publishing-go-modules

版本命名规则:推荐不稳定版本用v0.x.x开始,稳定后改成v1.x.x

pseudo-version 直译为假的版本,一般是直接依赖branch,而不是按规范依赖tag

4. v2-go-modules

https://blog.golang.org/v2-go-modules

注意主版本名为v2之后的,项目里对应的要新增一个v2或者更高版本号的目录。

我个人感觉升级到v2这种方式不太友好,需要我们再维护一整个目录

5. module-compatibility

https://blog.golang.org/module-compatibility

  1. 用不定参数...的特性提高函数的入参扩展性
  2. 引入函数式的参数,也就是将具体的执行逻辑作为参数,传递进来
  3. 引入Option types模式,更详细地可以参考我的文章
  4. 用接口interface分离调用和实现
  5. 如果结构体struct明确不能对比,就用一个doNotComparefield来告诉调用者
代码语言:javascript
复制
type doNotCompare [0]func()

type Point struct {
        doNotCompare
        X int
        Y int
}

第五点非常有意思,也就是要求我们在前期设计对象时,就要考虑清楚这个对象后续的特性,比如示例中的是否可以对比

从go.mod的文件格式讲起

进入正题,我们来一起看看go.mod,它的定义简单示例如下:

代码语言:javascript
复制
module example.com/my/thing

go 1.12

require example.com/other/thing v1.0.2
require example.com/new/thing/v2 v2.3.4
exclude example.com/old/thing v1.2.3
replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5
retract [v1.9.0, v1.9.5]

IDE会帮助你格式化,记住以下关键词即可(重点为前三个)

  1. module - go mod init指令定义的库名
  2. go - 要求go语言的最低版本,会影响到后面依赖库的下载
  3. require - 必备库,也就是代码中直接import的部分
  4. replace - 替换库,在重构时挺好用(比如某个开源组件有问题,内部fork了一版,直接replace即可)
  5. retract 撤回版本,告诉调用本库的项目,部分版本有严重问题、不要引用

go mod 底层实现依赖 - MVS 最小版本选择。 这个特性很有意思,后续单独来讲讲这块,一开始就不深入到细节了

加深理解 - incompatible和indirect

在我们整理go.mod文件时,经常能看到两个奇怪的字符indirectincompatible。我们来详细地分析一下。

incompatible - 兼容v2及以上的版本号

上面我们已经讲过,如果一个库的tag为v1以上,如v2,就必须得创建一个v2的目录。例如

代码语言:javascript
复制
require example.com/new/thing/v2 v2.3.4

这就要求我们在项目example.com/new/thing下新建v2目录,再存放代码。但是,很多库往往只是升级个主版本号,并不会去新建目录、还需要迁移代码。为了兼容这个情况,就会引入+incompatible。例如

代码语言:javascript
复制
require example.com/new/thing v2.3.4+incompatible

indirect - 未在go.mod里定义、但间接调用的库

我们先聊一个简单的场景:当前项目为A,调用了项目B,B又调用了C。对A进行编译,需要B和C的相关代码

在完全规范的项目中:

  • 条件1 - A的go.mod里包含B
  • 条件2 - B的go.mod里包含C

在编译A时,会在go.mod找到B的信息,所以B是require字段;而C的信息已经被维护在B的go.mod里了,不需要在A的go.mod里维护。

而什么样的情况会发生indirect呢?它对应的是 条件2 缺失的场景

  1. B没有启用Go Module,采用的是老项目管理方式
  2. B的go.mod部分缺失,未填写模块C

最常见的部分缺失场景是:项目虽然有go.mod,但实际编译不走Go Module,而是如vendor目录等方式

用一句话总结,A库无法根据B库的go.mod找到C库

常见命令介绍

相关的指令有很多,我重点分两块来说:

先是高频使用的命令:

用go mod init初始化项目

初始化项目,保证module名称与git路径一致。

例如 go mod init github.com/example/a

用go get下载指定依赖库与版本

常见的flags

  • -d 只更新go.mod中的依赖,轻量级
  • -u 更新指定库与依赖它的库,全量

例如go get -d github.com/example/b

根据go.mod下载依赖库go mod download/vendor

其中download是下载到Go Module的缓存中,而vendor是下载到vendor依赖路径。官方推荐前者。

我经常会去手动编辑go.mod文件,然后用这个指令刷新一下依赖库

整理依赖go mod tidy

整理并更新go mod的依赖信息,保证当前的go.mod为最新。

然后是排查依赖库问题用到的:

查看库的支持版本go list

  • go list -m all 查看本项目的所有依赖库与版本
  • go list -m -versions {module名} 查看module支持的版本号
  • go list -m -json {module名}@{版本号} 用json格式查看指定module版本号的信息,如创建时间

查看当前库的依赖关系go mod graph

查看所有go mod的依赖,一般在查依赖关系时用到

查看指定库是怎么被依赖的go mod why

查指定库是怎么被依赖的

查看二进制文件的依赖信息go version -m

查看指定(go文件编译的)二进制文件的版本信息

设置GOPRXOY

大部分人使用go.mod的最大问题是无法下载代码库,也就是代理的设置,网上也有很多教程,我这边给三个我常用的:

  1. 阿里云:GOPROXY=https://mirrors.aliyun.com/goproxy,direct
  2. 七牛云:GOPROXY=https://goproxy.cn,direct
  3. 全球代理:GOPROXY=https://goproxy.io,direct

公司私有库需要私有代理。

小结

本讲的内容到这里就告一段落了,相信通过这篇文章,大家已经能应对绝大部分Go Module的场景。

下一讲,我会重点讲Go Module最核心的 Minimal version selection (MVS) 机制。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Go编程点滴 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Go Mod的官方说明
    • 快速入门 - 5篇介绍Go Mod系列的官方博客
      • 1. using-go-modules
      • 2. migrating-to-go-modules
      • 3. publishing-go-modules
      • 4. v2-go-modules
      • 5. module-compatibility
    • 从go.mod的文件格式讲起
      • 加深理解 - incompatible和indirect
        • incompatible - 兼容v2及以上的版本号
        • indirect - 未在go.mod里定义、但间接调用的库
      • 常见命令介绍
        • 用go mod init初始化项目
        • 用go get下载指定依赖库与版本
        • 根据go.mod下载依赖库go mod download/vendor
        • 整理依赖go mod tidy
        • 查看库的支持版本go list
        • 查看当前库的依赖关系go mod graph
        • 查看指定库是怎么被依赖的go mod why
        • 查看二进制文件的依赖信息go version -m
      • 设置GOPRXOY
        • 小结
        相关产品与服务
        项目管理
        CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档