> 查看原文:[blog.keyboardman.me](https://blog.keyboardman.me/2018/02/23/early-adopters-versioned-go/)
一直以来,对go来说依赖包的版本控制上没有一个好的方案,当前主要有两种方式`Import Versioning`和`Semantic Versioning`。
* Import Versioning:`gopkg.in`网站,其实是GitHub版本变化的重定向器,你可以通过`gopkg.in/yaml.v1`和`gopkg.in/yaml.v2` 的这样的导入方式来指向Git库的不同提交版本
* Semantic Versioning:制定了一个文件格式规范来描述管理vendor目录下代码的准确源和版本信息(dep、glide)
前几天(2018-02-20)Russ Cox博客上介绍了他为go设计的新工具`vgo`,这是为处理软件包版本而设计的go工具的替代品,vgo即versioned go的缩写,意即带版本的go。vgo目前只能运行在go1.10之上,否则会得到`vgo objabi: cannot find GOMIPS`这样的错误。
首先安装vgo。
```bash
go get -u golang.org/x/vgo
```
我们先尝试下,跟着[官方示例](https://research.swtch.com/vgo-tour)。
```bash
mkdir $GOPATH/src/hello
cd $GOPATH/src/hello
curl -sS https://swtch.com/hello.go > hello.go
```
我们看一下`hello.go`的内容。
```go
package main // import "github.com/you/hello"
import (
"fmt"
"rsc.io/quote"
)
func main() {
fmt.Println(quote.Hello())
}
```
其中`// import "github.com/you/hello"`注释用来告诉vgo模块的“导入路径名称”应该是什么,并且使用此模块的其他软件包将用作导入标识符。
创建一个空的go.mod文件来标记此项目的根目录,然后编译一下。
```bash
echo >go.mod
vgo build
```
可以看到生成可执行文件,并修改了`go.mod`的内容,自动生成了依赖关系。
```bash
module "github.com/you/hello"
require "rsc.io/quote" v1.5.2
```
`go.mod`文件包含了模块所依赖包的最小版本。如果模块没有提供一个`tag`版本。对于未命名的提交,`v0.0.0-yyyymmddhhmmss-commit `表示一个指定日期的提交。`go.mod`文件还可以实现排除和替换的版本,需手动修改`go.mod`文件。
```bash
exclude "rsc.io/sampler" v1.99.99
replace "rsc.io/quote" v1.5.2 => "../quote"
```
但是,最重要的变化还是终结了`GOPATH`作为Go代码工作空间的设置,由于`go.mod`文件包含了完整的模块路径并且还定义了每个使用的依赖的版本,因此包含`go.mod`文件的目录就可以被认为是一个目录树的根目录了,该目录树作用于自身的工作空间,并且和其他类似的目录彼此隔离。
vgo其他功能
```bash
vgo list -m # 查看所有依赖
vgo list -m -u # 查看所有依赖同时检查更新,会打印出最新版本和当前版本
vgo test all # 执行所有测试,包括依赖包的测试
vgo test http://rsc.io/sampler # 执行指定包测试
vgo get -u # 更新所有依赖
vgo list -t http://rsc.io/sampler # 检查指定包所有可用的版本 即tag
vgo get http://rsc.io/sampler@v1.3.1 # 获取指定版本,并修改go.mod
vgo vendor # 退到vendor 兼容不使用vgo的用户
...
```
vgo在下载github仓库时,如果当前环境是未认证的账号会受到限流影响,得到如下警告。
```bash
GitHub applies fairly small rate limits to unauthenticated users, and
you appear to be hitting them. To authenticate, please visit
https://github.com/settings/tokens and click "Generate New Token" to
create a Personal Access Token. The token only needs "public_repo"
scope, but you can add "repo" if you want to access private
repositories too.
```
这时候需要获取github token,在github网站依次点击`Settings`-`Developer settings`-`Personal access tokens`-`Generate new token`,填写名字和勾选权限后生成token。创建或修改`$HOME/.netrc`文件,添加下行,把生成的token填写进去,就能解决了。
```bash
machine api.github.com login YOU password TOKEN
```
目前vgo的文档不够完善,代码也不够健壮,在生产环境可能还不适合去使用。我在测试时就遇到了些问题,比如有的`gopkg.in`仓库使用标签而不是分支来标记主要版本。当前vgo处理这些仓库会出错。
```go
import (
_ "gopkg.in/natefinch/lumberjack.v2"
)
```
将得到如下错误。
```bash
import "gopkg.in/natefinch/lumberjack.v2": unexpected status (https://api.github.com/repos/natefinch/lumberjack/commits?sha=v2&until=2018-02-23T03%3A49%3A22Z&per_page=2): 404 Not Found
# 或
vgo: import "gopkg.in/natefinch/lumberjack.v2": unexpected status (https://api.github.com/repos/natefinch/lumberjack): 403 Forbidden
```
不过vgo应该很快就会修复这些问题。
有疑问加站长微信联系(非本文作者))