扫码订阅《 》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go友会
  • 城市
  • 校园
Go学院
  • Go小课
  • Go小考
  • Go实战
  • 精品课
Go求职
  • 求职辅导🔥
  • Offer收割社群
  • 企业题库
  • 面试宝典
Go宝典
  • 在线宝典
  • B站精选
  • 推荐图书
  • 每日博文
Go仓库
实验区
  • Go周边
  • Go下载
  • Go月刊
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go友会
  • 城市
  • 校园
Go学院
  • Go小课
  • Go小考
  • Go实战
  • 精品课
Go求职
  • 求职辅导🔥
  • Offer收割社群
  • 企业题库
  • 面试宝典
Go宝典
  • 在线宝典
  • B站精选
  • 推荐图书
  • 每日博文
Go仓库
实验区
  • Go周边
  • Go下载
  • Go月刊
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • Go Modules指南

    • 什么是Go Modules
    • GOPATH
    • Go Modules基本使用
    • Go Modules下的go get行为
    • Go Modules的导入路径说明
    • Go Modules的语义化版本控制
    • Go Modules的最小版本选择
    • go.sum文件要不要提交
    • 总结

扫码订阅《 》或入驻星球,即可阅读文章!

Go Modules下的go get行为


煎鱼

在拉取项目依赖时,你会发现拉取的过程总共分为了三大步,分别是 finding(发现)、downloading(下载)以及 extracting(提取), 并且在拉取信息上一共分为了三段内容:

需要注意的是,所拉取版本的 commit 时间是以UTC时区为准,而并非本地时区,同时我们会发现我们 go get 命令所拉取到的版本是 v0.0.0,这是因为我们是直接执行 go get -u 获取的,并没有指定任何的版本信息,由 Go modules 自行按照内部规则进行选择。

# 1️⃣ go get 的拉取行为

刚刚我们用 go get 命令拉取了新的依赖,那么 go get 又提供了哪些功能呢,常用的拉取命令如下:

命令 作用
go get 拉取依赖,会进行指定性拉取(更新),并不会更新所依赖的其它模块。
go get -u 更新现有的依赖,会强制更新它所依赖的其它全部模块,不包括自身。
go get -u -t ./... 更新所有直接依赖和间接依赖的模块版本,包括单元测试中用到的。

那么我想选择具体版本应当如何执行呢,如下:

命令 作用
go get golang.org/x/text@latest 拉取最新的版本,若存在tag,则优先使用。
go get golang.org/x/text@master 拉取 master 分支的最新 commit。
go get golang.org/x/text@v0.3.2 拉取 tag 为 v0.3.2 的 commit。
go get golang.org/x/text@342b2e 拉取 hash 为 342b231 的 commit,最终会被转换为 v0.3.2。

# 2️⃣ go get 的版本选择

我们回顾一下我们拉取的 go get github.com/eddycjy/mquote,其结果是 v0.0.0-20200220041913-e066a990ce6f,对照着上面所提到的 go get 行为来看,你可能还会有一些疑惑,那就是在 go get 没有指定任何版本的情况下,它的版本选择规则是怎么样的,也就是为什么 go get 拉取的是 v0.0.0,它什么时候会拉取正常带版本号的 tags 呢。实际上这需要区分两种情况,如下:

  • 所拉取的模块有发布 tags:
    • 如果只有单个模块,那么就取主版本号最大的那个tag。
    • 如果有多个模块,则推算相应的模块路径,取主版本号最大的那个tag(子模块的tag的模块路径会有前缀要求)
  • 所拉取的模块没有发布过 tags:
    • 默认取主分支最新一次 commit 的 commithash。

没有发布过 tags

那么为什么会拉取的是 v0.0.0 呢,是因为 github.com/eddycjy/mquote 没有发布任何的tag,如下:

因此它默认取的是主分支最新一次 commit 的 commit 时间和 commithash,也就是 20200220041913-e066a990ce6f,属于第二种情况。

有发布 tags

在项目有发布 tags 的情况下,还存在着多种模式,也就是只有单个模块和多个模块,我们统一以多个模块来进行展示,因为多个模块的情况下就已经包含了单个模块的使用了,如下图:

在这个项目中,我们一共打了两个tag,分别是:v0.0.1 和 module/tour/v0.0.1。这时候你可能会奇怪,为什么要打 module/tour/v0.0.1 这么“奇怪”的tag,这有什么用意吗?

其实是 Go modules 在同一个项目下多个模块的tag表现方式,其主要目录结构为:

mquote
├── go.mod
├── module
│   └── tour
│       ├── go.mod
│       └── tour.go
└── quote.go
1
2
3
4
5
6
7

可以看到在 mquote 这个项目的根目录有一个 go.mod 文件,而在 module/tour 目录下也有一个 go.mod 文件,其模块导入和版本信息的对应关系如下:

tag 模块导入路径 含义
v0.0.1 github.com/eddycjy/mquote mquote 项目的v 0.0.1 版本
module/tour/v0.01 github.com/eddycjy/mquote/module/tour mquote 项目下的子模块 module/tour 的 v0.0.1 版本

导入主模块和子模块

结合上述内容,拉取主模块的话,还是照旧执行如下命令:

$ go get github.com/eddycjy/mquote@v0.0.1
go: finding github.com/eddycjy/mquote v0.0.1
go: downloading github.com/eddycjy/mquote v0.0.1
go: extracting github.com/eddycjy/mquote v0.0.1
1
2
3
4

如果是想拉取子模块,执行如下命令:

$ go get github.com/eddycjy/mquote/module/tour@v0.0.1
go: finding github.com/eddycjy/mquote/module v0.0.1
go: finding github.com/eddycjy/mquote/module/tour v0.0.1
go: downloading github.com/eddycjy/mquote/module/tour v0.0.1
go: extracting github.com/eddycjy/mquote/module/tour v0.0.1
1
2
3
4
5

我们将主模块和子模块的拉取进行对比,你会发现子模块的拉取会多出一步,它会先发现 github.com/eddycjy/mquote/module,再继续推算,最终拉取到 module/tour。

  • 1️⃣ go get 的拉取行为
  • 2️⃣ go get 的版本选择