Golang一直存在一个被人诟病的问题是缺少一个官方的包依赖管理工具。从我个人的角度上来看存在两个问题:
GOPATH特性对于多工程的情况下,支持不算友好。
GOPATH无法对依赖包进行有效的版本管理,没有任何地方能够表明依赖包的具体版本号,无法简单清晰获取到有效的依赖包版本信息等。
GOPATH
在 go mod 出现之前,所有的 Go 项目都需要放在同一个工作空间:$GOPATH/src 内,比如:
src/
github.com/golang/example/
.git/ # Git repository metadata
outyet/
main.go # command source
main_test.go # test source
stringutil/
reverse.go # package source
reverse_test.go # test source
相比其他语言,这个限制有些无法理解。其实,这和 Go 的一设计理念紧密相关:
包管理应该是去中心化的
所以 Go 里面没有 maven/npm 之类的包管理工具,只有一个 go get,支持从公共的代码托管平台(Bitbucket/GitHub..)下载依赖,当然也支持自己托管,具体可参考官方文档:Remote import paths。
由于没有中央仓库,所以 Go 项目位置决定了其 import path,同时为了与 go get 保持一致,所以一般来说我们的项目名称都是 github.com/user/repo 的形式。
当然也可以不是这种形式,只是不方便别人引用而已,后面会讲到如何在 go mod 中实现这种效果
vendor、dep
使用 go get 下载依赖的方式简单暴力,伴随了 Go 七年之久,直到 1.6(2016/02/17)才正式支持了 vendor,可以把所有依赖下载到当前项目中,解决可重复构建(reproducible builds)的问题,但是无法管理依赖版本。社区出现了各式各样的包管理工具,来方便开发者固化依赖版本,由于不同管理工具采用不同的元信息格式(比如:godep 的 Godeps.json、Glide 的 glide.yaml),不利于社区发展,所以 Go 官方推出了 dep。
dep 的定位是实验、探索如何管理版本,并不会直接集成到 Go 工具链,Go 核心团队会吸取 dep 使用经验与社区反馈,开发下一代包管理工具 modules,并于 2019/09/03 发布的 1.13 正式支持,并随之发布 Module Mirror, Index, Checksum,用于解决软件分发、中间人攻击等问题。
对于Go的版本管理主要用过 glide,下面介绍 Go 1.11 之后官方支持的版本管理工具 mod。
关于 mod 官方给出了三个命令 go help mod、go help modules、go help module-get 帮助了解使用。
设置 GO111MODULE
可以用环境变量 GO111MODULE 开启或关闭模块支持,它有三个可选值:off、on、auto,默认值是 auto。
GO111MODULE=off 无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包。
GO111MODULE=on 模块支持,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖。
GO111MODULE=auto 在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持。
在使用模块的时候,GOPATH 是无意义的,不过它还是会把下载的依赖储存在 𝐺𝑂𝑃𝐴𝑇𝐻/𝑝𝑘𝑔/𝑚𝑜𝑑中,也会把𝑔𝑜𝑖𝑛𝑠𝑡𝑎𝑙𝑙的结果放在GOPATH/bin 中。
Go Mod 命令
download download modules to local cache (下载依赖的module到本地cache))
edit edit go.mod from tools or scripts (编辑go.mod文件)
graph print module requirement graph (打印模块依赖图))
init initialize new module in current directory (再当前文件夹下初始化一个新的module, 创建go.mod文件))
tidy add missing and remove unused modules (增加丢失的module,去掉未用的module)
vendor make vendored copy of dependencies (将依赖复制到vendor下)
verify verify dependencies have expected content (校验依赖)
why explain why packages or modules are needed (解释为什么需要依赖)
Go Mod 使用
创建 go.mod 文件
在一个新的项目中,需要执行go mod init 来初始化创建文件go.mod,go.mod 中会列出所有依赖包的路径和版本。
module github.com/xfstart07/watcher
require (
github.com/apex/log v1.0.0
github.com/fatih/color v1.7.0 // indirect
github.com/fsnotify/fsnotify v1.4.7
github.com/go-ini/ini v1.38.2
github.com/go-kit/kit v0.7.0
github.com/go-logfmt/logfmt v0.3.0 // indirect
)
indirect 表示这个库是间接引用进来的。
go mod vendor 命令可以在项目中创建 vendor 文件夹将依赖包拷贝过来。
go mod download 命令用于将依赖包缓存到本地Cache起来。
显示所有Import库信息
go list -m -json all
-json JSON格式显示
all 显示全部库
Mod Cache 路径
默认在$GOPATH/pkg 下面:
$GOPATH/pkg/mod
我们来看看一个项目下载下来的文件形式:
➜ mod ls -lh cache/download/github.com/go-kit/kit/@v/
total 3016
-rw-r–r– 1 a1 staff 7B Sep 29 15:37 list
-rw——- 1 a1 staff 50B Sep 29 15:37 v0.7.0.info
-rw——- 1 a1 staff 29B Sep 29 15:37 v0.7.0.mod
-rw-r–r– 1 a1 staff 1.5M Sep 29 15:37 v0.7.0.zip
-rw-r–r– 1 a1 staff 47B Sep 29 15:37 v0.7.0.ziphash
可以看出项目库会对每个版本创建一个文件夹,文件夹下有对于版本的信息。
天坑来了:go mod 不能下载google包 ?
对于全世界绝大多数Gophers来说,Go module的引入带来的都是满满的幸福感,但是对于位于中国大陆地区的Gopher来说,在这种幸福感袭来的同时,也夹带了一丝“无奈”。其原因在于module-aware mode下,go tool默认不再使用传统GOPATH下或top vendor下面的包了,而是在GOPATH/pkg/mod(go 1.11中是这个位置,也许以后版本这个位置会变动)下面寻找Go module的local cache。
由于众所周知的原因,在大陆地区我们无法直接通过go get命令或git clone获取到一些第三方包,这其中最常见的就是golang.org/x下面的各种优秀的包。但是在传统的GOPATH mode下,我们可以先从golang.org/x/xxx的mirror站点github.com/golang/xxx上git clone这些包,然后将其重命名为golang.org/x/xxx。这样也能勉强通过开发者本地的编译。又或将这些包放入vendor目录并提交到repo中,也能实现正确的构建。
但是go module引入后,一旦工作在module-aware mode下,go build将不care GOPATH下或是vendor下的包,而是到GOPATH/pkg/mod查询是否有module的cache,如果没有,则会去下载某个版本的module,而对于golang.org/x/xxx下面的module,在大陆地区往往会get失败。
有朋友可能会说,可以继续通过其他mirror站点下载再改名啊?理论上是可行的。但是现实中,这样做很繁琐。我们先来看看go module的专用本地缓存目录结构:
➜ /Users/tony/go/pkg/mod $tree -L 7
.
├── cache
│ └── download
│ └── golang.org
│ └── x
│ └── text
│ └── @v
│ ├── list
│ ├── v0.1.0.info
│ ├── v0.1.0.mod
│ ├── v0.1.0.zip
│ ├── v0.1.0.ziphash
│ ├── v0.3.0.info
│ ├── v0.3.0.mod
│ ├── v0.3.0.zip
│ └── v0.3.0.ziphash
└── golang.org
└── x
├── text@v0.1.0
└── text@v0.3.0
我们看到mod下的结构是经过精心设计的。cache/download下面存储了每个module的“元信息”以及每个module不同version的zip包。比如在这里,我们看到了golang.org/x/text这个module的v0.1.0和v0.3.0两个版本的元信息和对应的源码zip;同时mod下还直接存有text module的两个版本v0.1.0和v0.3.0的源码。
如果我们还像GOPATH mode下那种通过“mirror站下载再改名”的方式来满足go build的需求,那么我们需要手工分别制作某个module的不同版本的元信息以及源码目录,制作元信息时还要了解每个文件(比如:xx.info、xxx.mod等)的内容的生成机制,这样的方法的“体验”并不好。
填坑: Go module proxy
那么问题来了:大陆Gopher如何能在go module开启的状态下享受go module带来的福利呢? “解铃还须系铃人”!答案就在go 1.11中。Go 1.11在引入go module的同时,还引入了Go module proxy(go help goproxy)的概念。
go get命令默认情况下,无论是在gopath mode还是module-aware mode,都是直接从vcs服务(比如github、gitlab等)下载module的。但是Go 1.11中,我们可以通过设置GOPROXY环境变量来做一些改变:让Go命令从其他地方下载module。比如:
export GOPROXY=https://goproxy.io
一旦如上面设置生效后,后续go命令会通过go module download protocol与proxy交互下载特定版本的module。聪明的小伙伴们一定想到了。如果我们在某个国外VPS上搭建一个go module proxy server的实现,我们将可以通过该proxy下载到类似golang.org/x下面的module。与此同时,一些诸如从github.com上get package慢等次要的问题可能也被一并fix掉了。
显然Go官方加入go proxy的初衷并非为了解决中国大陆地区的下载qiang外包的烦恼的。但不可否认的是,GOPROXY让gopher在versioned go的基础上,对module和package的获取行为上增加了一层控制和干预能力。
https://tonybai.com/2018/07/15/hello-go-module/
https://roberto.selbach.ca/intro-to-go-modules/
https://ieevee.com/tech/2018/08/28/go-modules.html
https://colobu.com/2018/08/27/learn-go-module/
https://studygolang.com/articles/13895
Go modules
Go modules机制在go 1.11中是experiment feature,按照Go的惯例,在新的experiment feature首次加入时,都会有一个特性开关,go modules也不例外,GO111MODULE这个临时的环境变量就是go module特性的experiment开关。GO111MODULE有三个值:auto、on和off,默认值为auto。GO111MODULE的值会直接影响Go compiler的“依赖管理”模式的选择(是GOPATH mode还是module-aware mode),我们详细来看一下:
当GO111MODULE的值为off时,go modules experiment feature关闭,go compiler显然会始终使用GOPATH mode,即无论要构建的源码目录是否在GOPATH路径下,go compiler都会在传统的GOPATH和vendor目录(仅支持在gopath目录下的package)下搜索目标程序依赖的go package;
当GO111MODULE的值为on时(export GO111MODULE=on),go modules experiment feature始终开启,与off相反,go compiler会始终使用module-aware mode,即无论要构建的源码目录是否在GOPATH路径下,go compiler都不会在传统的GOPATH和vendor目录下搜索目标程序依赖的go package,而是在go mod命令的缓存目录($GOPATH/pkg/mod)下搜索对应版本的依赖package;
当GO111MODULE的值为auto时(不显式设置即为auto),也就是我们在上面的例子中所展现的那样:使用GOPATH mode还是module-aware mode,取决于要构建的源码目录所在位置以及是否包含go.mod文件。如果要构建的源码目录不在以GOPATH/src为根的目录体系下,且包含go.mod文件(两个条件缺一不可),那么使用module-aware mode;否则使用传统的GOPATH mode。
Module 文件
执行命令 go build && go mod tidy ,下载依赖并整理。
项目根目录下会生成两个文件(需要加入到 git 中):
文件 go.mod:指示模块名称、go 的版本、该模块的依赖信息(依赖名称),类似 npm 生成的文件 package.json 。
文件 go.sum:该模块的所有依赖的校验和,类似 npm 生成的文件 package-lock.json
Module 是多个 package 的集合,版本管理的基本单元,使用 go.mod 文件记录依赖的 module。
go.mod 位于项目的根目录,支持 4 条命令:module、require、replace、exclude。示例:
module github.com/my/repo
require (
github.com/some/dependency v1.2.3
github.com/another/dependency/v4 v4.0.0
)
module 声明 module path,一个 module 内所有 package 的 import path 都以它为前缀
require 声明所依赖的 module,版本信息使用形如 v(major).(minor).(patch) 的语义化版本
replace/exclude 用于替换、排查指定 module path
go mod命令
golang 提供了 go mod命令来管理包。
go mod 有以下命令:
命令 说明
download download modules to local cache(下载依赖包)
edit edit go.mod from tools or scripts(编辑go.mod)
graph print module requirement graph (打印模块依赖图)
init initialize new module in current directory(在当前目录初始化mod)
tidy add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
vendor make vendored copy of dependencies(将依赖复制到vendor下)
verify verify dependencies have expected content (验证依赖是否正确)
why explain why packages or modules are needed(解释为什么需要依赖)
Go modules使用步骤:
首先将你的版本更新到最新的Go版本(>=1.11)。
通过go命令行,进入到你当前的工程目录下,在命令行设置临时环境变量set GO111MODULE=on;
export GO111MODULE=on
export GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy,direct
export GOPRIVATE=*.corp.example.com,rsc.io/private
执行命令go mod init在当前目录下生成一个go.mod文件,执行这条命令时,当前目录不能存在go.mod文件。如果之前生成过,要先删除;
如果你工程中存在一些不能确定版本的包,那么生成的go.mod文件可能就不完整,因此继续执行下面的命令;
执行go mod tidy命令,它会添加缺失的模块以及移除不需要的模块。执行后会生成go.sum文件(模块下载条目)。添加参数-v,例如go mod tidy -v可以将执行的信息,即删除和添加的包打印到命令行;
执行命令go mod verify来检查当前模块的依赖是否全部下载下来,是否下载下来被修改过。如果所有的模块都没有被修改过,那么执行这条命令之后,会打印all modules verified。
执行命令go mod vendor生成vendor文件夹,该文件夹下将会放置你go.mod文件描述的依赖包,文件夹下同时还有一个文件modules.txt,它是你整个工程的所有模块。在执行这条命令之前,如果你工程之前有vendor目录,应该先进行删除。同理go mod vendor -v会将添加到vendor中的模块打印出来;
https://www.ardanlabs.com/blog/2020/04/modules-06-vendoring.html
Introduction
It’s no secret that I am a fan of vendoring when it’s reasonable and practical to use it for your application projects. I believe vendoring gives your application projects the most durability since the project owns every line of source code it needs to build the applications. If you want a reproducible build without needing to rely on external services (like module mirrors) and being connected to the network, vendoring is the solution.
These are other benefits of vendoring:
If dependencies are removed from the VCS or somehow proxy servers lose modules, you are covered.
Upgrading dependencies can be seen by running diffs and you maintain a history.
You will have the ability to trace and debug your dependencies and test changes if necessary.
Once you run a go mod tidy and go mod vendor your changes will be replaced.
In this post, I will provide a history of Go’s support for vendoring and the changes in default behavior that have existed over time. I will also share how Go’s tooling is capable of maintaining backwards compatibility between versions. Finally, I will share how you may need to (over time) manually upgrade the version listed in the go.mod file to change the default behavior of future Go releases.
Running Different Versions Of Go
To show you the differences in default behavior between Go 1.13 and Go 1.14, I need to be able to run both versions of the tooling on my machine at the same time. I’ve already installed Go 1.14.2 on my machine at the time I published this post and I access that version using the traditional go front end. However for this post, I also need to run a Go 1.13 environment. So how can I do that without disrupting my current development environment?
Luckily, the Go team publishes version downloads that give you a specific binary for any version of Go you want to use, including Go Tip.
Figure 1
Figure 1 shows a screenshot of the Go 1.13.10 page from the download server. It shows the instructions for building a binary that can be used to build and test your Go code using Go 1.13.10.
Listing 1
$ cd $HOME
$ go get golang.org/dl/go1.13.10
OUTPUT
go: downloading golang.org/dl v0.0.0-20200408221700-d6f4cf58dce2
go: found golang.org/dl/go1.13.10 in golang.org/dl v0.0.0-20200408221700-d6f4cf58dce2
$ go1.13.10 download
OUTPUT
Downloaded 0.0% ( 14448 / 121613848 bytes) …
Downloaded 9.5% ( 11499632 / 121613848 bytes) …
Downloaded 30.8% ( 37436528 / 121613848 bytes) …
Downloaded 49.2% ( 59849840 / 121613848 bytes) …
Downloaded 69.3% ( 84262000 / 121613848 bytes) …
Downloaded 90.3% (109804656 / 121613848 bytes) …
Downloaded 100.0% (121613848 / 121613848 bytes)
Unpacking /Users/bill/sdk/go1.13.10/go1.13.10.darwin-amd64.tar.gz …
Success. You may now run ‘go1.13.10’
$ go1.13.10 version
OUTPUT
go version go1.13.10 darwin/amd64
$ go version
OUTPUT
go version go1.14.2 darwin/amd64
Listing 1 shows how after running the go get command for version 1.13.10 of Go and performing the download call, I can now use Go 1.13.10 on my machine without any disruption to my Go 1.14.2 installation.
If you want to remove any version of Go from your machine, you can find the specific binaries in your $GOPATH/bin folder and all the supporting files will be found in $HOME/sdk.
Listing 2
$ cd $GOPATH/bin
$ l
OUTPUT
-rwxr-xr-x 1 bill staff 7.0M Apr 11 10:51 go1.13.10
-rwxr-xr-x 1 bill staff 2.3M Jan 6 11:02 gotip
$ cd $HOME
$ l sdk/
OUTPUT
drwxr-xr-x 22 bill staff 704B Apr 11 10:52 go1.13.10
drwxr-xr-x 24 bill staff 768B Feb 26 01:59 gotip
Quick Vendoring Tutorial
The Go tooling did a great job minimizing the workflow impacts to manage and vendor an application project’s dependencies. It requires two commands: tidy and vendor.
Listing 3
$ go mod tidy
Listing 3 shows the tidy command that helps to keep the dependencies listed in your module files accurate. Some editors (like VS Code and GoLand) provide support to update the module files during development but that doesn’t mean the module files will be clean and accurate once you have everything working. I recommend running the tidy command before you commit and push any code back to your VCS.
If you want to vendor those dependencies as well, then run the vendor command after tidy.
Listing 4
$ go mod vendor
Listing 4 shows the vendor command. This command creates a vendor folder inside your project that contains the source code for all the dependencies (direct and indirect) that the project requires to build and test the code. This command should be run after running tidy to keep your vendor folder in sync with your module files. Make sure to commit and push the vendor folder to your VCS.
GOPATH or Module Mode
In Go 1.11, a new mode was added to the Go tooling called “module mode”. When the Go tooling is operating in module mode, the module system is used to find and build code. When the Go tooling is operating in GOPATH mode, the traditional GOPATH system continues to be used to find and build code. One of the bigger struggles I have had with the Go tooling is knowing what mode will be used by default between the different versions. Then knowing what configuration changes and flags I need to keep my builds consistent.
To understand the history and the semantic changes that have occurred over the past 4 versions of Go, it’s good to have a refresher on these modes.
Go 1.11
A new environment variable was introduced called GO111MODULE whose default was auto. This variable would determine if the Go tooling would use module mode or GOPATH mode depending on where the code was located (inside or outside of GOPATH). To force one mode or the other, you would set this variable to on or off. When it came to vendor folders, module mode would ignore a vendor folder by default and build dependencies against the module cache.
Go 1.12
The default setting for GO111MODULE remains auto and the Go tooling continues to determine module mode or GOPATH mode depending on where the code is located (inside or outside of GOPATH). When it comes to vendor folders, module mode would still ignore a vendor folder by default and build dependencies against the module cache.
Go 1.13
The default setting for GO111MODULE remains auto but the Go tooling is no longer sensitive to whether the working directory is within the GOPATH. Module mode would still ignore a vendor folder by default and build dependencies against the module cache.
Go 1.14
The default setting for GO111MODULE remains auto and the Go tooling is still no longer sensitive to whether the working directory is within the GOPATH. However, if a vendor folder exists, it will be used by default to build dependencies instead of the module cache [1]. In addition, the go command verifies that the project’s vendor/modules.txt file is consistent with its go.mod file.
Backwards Compatibility Between Versions
The change in Go 1.14 to use the vendor folder by default over the module cache is the behavior I wanted for my projects. Initially I thought I could just use Go 1.14 to build against my existing projects and it would be enough, but I was wrong. After my first build with Go 1.14 and not seeing the vendor folder being respected, I learned that the Go tooling reads the go.mod file for version information and maintains backwards compatibility with that version listed. I had no idea, but it is clearly expressed in the release notes for Go 1.14.
https://golang.org/doc/go1.14#go-command
When the main module contains a top-level vendor directory and its go.mod file specifies Go 1.14 or higher, the go command now defaults to -mod=vendor for operations that accept that flag.
In order to use the new default behavior for vendoring, I was going to need to upgrade the version information in the go.mod file from Go 1.13 to Go 1.14. This is something I quickly did.
Small Demo
To show you the behavior of Go 1.13 and Go 1.14, and how the tooling maintains backwards compatibility, I am going to use the service project. I will show you how changing the version listed in go.mod will change the default behavior of the Go tooling.
To start, I will clone the service project outside of my GOPATH.
Listing 5
$ cd $HOME/code
$ git clone https://github.com/ardanlabs/service
$ cd service
$ code .
Listing 5 shows the commands to clone the project and open the project in VS Code.
Listing 6
$ ls -l vendor/
OUTPUT
total 8
drwxr-xr-x 3 bill staff 96 Mar 26 16:01 contrib.go.opencensus.io
drwxr-xr-x 14 bill staff 448 Mar 26 16:01 github.com
drwxr-xr-x 20 bill staff 640 Mar 26 16:01 go.opencensus.io
drwxr-xr-x 3 bill staff 96 Mar 26 16:01 golang.org
drwxr-xr-x 3 bill staff 96 Mar 26 16:01 gopkg.in
-rw-r–r– 1 bill staff 2860 Mar 26 16:01 modules.txt
Listing 6 shows the listing of the vendor folder for the service project. You can see directories for some of the popular VCS sites that exist today as well as several vanity domains. All the code the project depends on to build and test are located inside the vendor folder.
Next, I will manually change the go.mod file back to version 1.13. This will allow me to show you the behavior I experienced when I used Go 1.14 for the first time against this project.
Listing 7
module github.com/ardanlabs/service
go 1.13 // I just changed this from go 1.14 to go 1.13
Listing 7 shows the change I am making to the go.mod file (switching out go 1.14 for go 1.13).
Note: There is a go mod command that can be used to change the version in the go.mod file: go mod edit -go=1.14
Go 1.13
On this first build, I will use Go 1.13.10 to build the sales-api application. Remember, the go.mod file is listing Go 1.13 as the compatible version for this project.
Listing 8
$ cd service/cmd/sales-api
$ go1.13.10 clean -modcache
$ go1.13.10 build
OUTPUT
go: downloading contrib.go.opencensus.io/exporter/zipkin v0.1.1
. . .
go: finding github.com/leodido/go-urn v1.2.0
Listing 8 shows how I navigated to the application folder, cleaned out my local module cache and then performed a build using Go 1.13.10. Notice how the Go tooling downloaded all the dependencies back into my module cache in order to build the binary. The vendor folder was ignored.
To get Go 1.13 to respect the vendor folder, I need to use the -mod=vendor flag when building and testing.
Listing 9
$ go1.13.10 clean -modcache
$ go1.13.10 build -mod=vendor
OUTPUT
Listing 9 shows how I am now using the -mod=vendor flag on the build call. This time the module cache is not re-populated with the missing modules and the code in the vendor folder is respected.
Go 1.14
This time I will run the build command using Go 1.14.2 without the use of the -mod=vendor flag.
Listing 10
$ go clean -modcache
$ go build
OUTPUT
go: downloading github.com/openzipkin/zipkin-go v0.2.2
. . .
go: downloading github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
Listing 10 shows what happens when I use Go 1.14 to build the project. The vendor folder is not being respected because the tooling is operating with Go 1.13 semantics. This is because the go.mod file is listing Go 1.13 as the compatible version for the project. When I saw this for the first time I was shocked. This is what started my investigation.
If I switch the go.mod file to version 1.14, the default mode of the Go 1.14 tooling will switch to respect the vendor folder by default.
Listing 11
module github.com/ardanlabs/service
go 1.14 // I just changed this from go 1.13 to go 1.14
Listing 11 shows the change to the go.mod file back to 1.14. I will clear the module cache again and run the build command again using Go 1.14.
Listing 12
$ go clean -modcache
$ go build
OUTPUT
Listing 12 shows that the module cache is not re-populated this time on the call to go build using Go 1.14. Which means the vendor folder is being respected, without the need of the -mod=vendor flag. The default behavior has changed because the module file is listing Go 1.14.
Future Changes For Vendoring and Modules
Thanks to John Reese, here is a link to a discussion about the tooling maintaining backwards compatibility between different versions of Go based on what is listed in the go.mod file. John was instrumental in making sure the post was accurate and flowed correctly.
https://github.com/golang/go/issues/30791
There is more support coming for vendoring that will follow in future releases. One such feature being discussed is about validating the code in the vendor folder to find situations where the code has been changed.
https://github.com/golang/go/issues/27348
I have to thank Chris Hines for reminding me about the default behaviors in the previous versions of Go and how that has been promoted with each new release. Chris also provided some interesting links that share some history and other cool things coming to the Go tooling for modules. Chris was instrumental in making sure the post was accurate and flowed correctly.
https://github.com/golang/go/issues/33848
https://github.com/golang/go/issues/36460
Conclusion
This post is a result of me being surprised that the version listed in go.mod was affecting the default behavior of the Go tooling. In order to gain access to the new default vendoring behavior in Go 1.14 that I wanted, I had to manually upgrade the version listed in go.mod from 1.13 to 1.14.
I haven’t formed any concrete opinions about the Go tooling using the version information in go.mod to maintain backwards compatibility between versions. The Go tooling has never been tied to the Go compatibility promise and so this was unexpected to me. Maybe this is the start of something great and moving forward the Go tooling can grow without the Go community worrying if their builds, tests and workflows will break when a new version of the Go tooling is released.
If you have any opinions, I’d love to hear them on Twitter.
Footnotes
[1] Beginning with Go 1.11, the -mod=vendor flag caused the go command to load packages from the vendor directory, instead of modules from the module cache. (The vendor directory contains individual packages, not complete modules.) In Go 1.14, the default value of the -mod flag changes depending on the contents of the main module: if there is a vendor directory and the go.mod file specifies go 1.14 or higher, -mod defaults to -mod=vendor. If the go.mod file is read-only, -mod defaults to -mod=readonly. We also added a new value, -mod=mod, meaning “load modules from the module cache” (that is, the same behavior that you get by default if none of the other conditions holds). Even if you are working in a main module for which the default behavior is -mod=vendor, you can explicitly go back to the module cache using the -mod=mod flag. - Bryan Mills