在我们的开发环境中,使多个golang版本并存。

大部分情况下,一个比较新的golang版本就能满足我们的日常的开发需求。
但是项目中,因为协作的原因,或者由于项目启动比较早,可能我们不同的工程需要用不同的golang版本。甚至有些工作用比较新的版本编译不了。
这时候,我们就需要让本地的开发环境支持多个golang版本。

官方解决方案

当前,golang提供了一个官方的解决方案,我们只要go install对应的go版本,然后就能使用特定的版本进行工作了。
官方repo:golang.org/dl

使用方式也比较简单,比如我们要安装一个1.18的版本,只需要两步

  1. go install golang.org/dl/go1.18@latest
  2. go1.18 download

之后只需要用go1.18替换go命令,即可使用特定的这个版本进行go相关的工作了。

但是go1.18go多了好几个字符,而且由于肌肉记忆,可能我们敲了go之后就会敲后面的内容了。为了让go直接当成特定的版本使用,我们可以设置环境变量, 设置好GOROOT和把特定版本的go放到PATH前面即可。
如下,我们把下面的内容设置到我们的shell加载配置里。

export GOROOT=$(go1.18 env GOROOT)
export PATH=$GOROOT/bin:$PATH

如果是bash,放在~/.bashrc里,如果是zsh,则放在~/.zshrc里,如果是fish则放在~/.config/fish/config.fish

到此,我们就可以使用特定版本的golang了,一个开发环境也安装了多个版本的golang。

不同工程自动加载特定的版本

以上在shell配置中配置特定版本,在不同的工程中就行不通了。因为配置文件是全局的。如果用特定的版本号来运行,我们除了要敲多版本号外,还需要记得每个工作用的是哪一个版本的go。

有没有办法在我们cd到特定的目录时,自动配置环境变量,离开的时候,自动释放这些环境变量呢?

direnv可以帮我们完成这一项工作。它可以在特定目录上,把环境变量写到.envrc,那cd进去就会自动加载,离开就会自动释放。

使用自己操作系统的包管理安装好direnv后,接下来cd到我们特定的工程,假如这个工程使用1.18的版本,我们只要把下面这一段配置放到.envrc即可。

export GOROOT=$(go1.18 env GOROOT)
export PATH=$GOROOT/bin:$PATH

配置好后,direnv会提示需要对这个目录进行授权,执行以下命令即可

direnv allow

这样我们就可以安装好多个golang版本,然后在不同的工程中配置好.envrc,就能在特定的工程用特定的版本go了。

direnv使用的是bash的方案配置环境变量,所以在fish这种非标准POSIX shell,也需要使用以上的语法进行配置。

gg管理golang版本

基于官方的解决方案,我们解决了多个版本的并存问题和运行问题。但是,我们本地安装了哪些版本,官方发布了哪些版本可以给我们用?

gg这个工具为我们提供了非常方便的管理方式。它支持以下能力

  • 查看本地版本列表
  • 官方的所有版本列表
  • 安装官方版本到本地
  • 删除版本
  • 打印特定版本的环境变量

它直接基于官方的解决方案做了包装,把安装的两步合成了一个步,打印环境变量配置。

安装gg

对于fish shell用户,可以用插件管理安装,如fisher

fisher install tenfyzhong/gg

对于bash和zsh用户,可以手动下载到$PATH上,详情见gg

对于使用homebrew的用户,可以使用homebrew

brew install tenfyzhong/tap/gg

gg ls 查看本地版本

golang.org/dl的安装,会把go的数据下载到~/sdk目录下。gg ls命令会去查看这个目录存在哪些版本,进行打印。

gg ls-remote 查看官方版本

gg ls-remote会去爬出官方的版本进行展示,同时会把结果缓存起来。缓存有效期24小时。使用缓存后,可以避免每次去爬取,加快运行速度。

gg install 安装特定的版本

比如上面我们介绍的安装1.18版本,我们只需要运行下面的命令

gg install 1.18

它会使用全局的go版本,去完成安装的两步

  1. go install golang.org/dl/go1.18@latest
  2. go1.18 download

gg remove删除特定版本

删除特定的版本,只需要把$GOPATH/bin下特定的版本删除,把~/sdk下特定版本删除即可。所以gg remove的工作比较简单。

gg remove 1.18

gg use使用特定的版本

这个命令会把特定版本需要的环境变量打印出来,可以直接进行source或者重定向到.envrc上。 比如对于bash的环境变量

gg use --bash 1.18

它会输出以下的内容

# source this code to enable it
# for example:
# > gg use --bash 1.18 | source

# if you use direnv to manage environment, you can redirect the output to .envrc in the current directory
# > gg use --bash 1.18 >> .envrc; direnv allow

export GOROOT=$(go1.18 env GOROOT)
export PATH=$GOROOT/bin:$PATH

或者fish的环境变量

gg use --fish 1.18

它会输出以下的内容

# source this code to enable it
# for example:
# > gg use --fish 1.18 | source

set -gx GOROOT (go1.18 env GOROOT)
fish_add_path $GOROOT/bin

如果不指定特定的shell,它会指定为当前的登录shell。
如果要使用direnv,则需要指定为bash

总结

基于以上,只需要使用gg即可完成官方方案的多版本解决版本。再加上direnv即可让我们在特定的工程自动使用特定的版本。