Go工程管理和业务实践

这是我参与更文挑战的第16天,活动详情查看:更文挑战

Go工程和依赖管理基本机制

依赖管理机制的变迁

GoPath—>GoVendor—->GoMod

  • GoPath:会要求工程代码要保存在GoPath/src的目录下面。同时要求你的依赖库也要是这个目录下面的:
$GOPATH/src/yourProject/

$GOPATH/src/gorm  :如果依赖了gorm
复制代码

编译的时候会直接使用GoPath/src目录下的代码。Go Get下载的代码也会放在GoPath中。

往往我们在安装Go以后,通过go env查看我们的Go Path,进入该文件目录,目录结构是这样的:

├── bin //用来存放编译后的可执行文件
│   ├── dlv
│   ├── go-outline
│   ├── gomodifytags
│   ├── gopkgs
│   ├── goplay
│   ├── gopls
│   ├── gotests
│   ├── impl
│   └── staticcheck
├── pkg //用于存放编译后生成的归档文件
│   ├── mod
│   └── sumdb
└── src // 用来存放go源码文件
    └── github.com
复制代码

这个结构,配上GoPath的要求,我们就必须要把我们的代码写在src文件下。或者是在其他任意目录写代码,但是最后构建的二进制文件要放在src下,才能执行。

刚刚说了,Go Get下载的代码也会放在GoPath中,这样你的工程代码和第三方代码都在同一个目录下,甚至你的多个工程代码也会在一个Go path目录下,十分混乱。

为了解决这个问题(还是使用GoPath),我们就会每个工程都指定一个新的GoPath,这样看起来项目管理很清晰,大家都分开了。然而第三方库,你每次都要下载。

  • GoVendor

通过命令启用govendor:

export GO15VENDOREXPEIMENT=1
复制代码

效果是所有的依赖包都会下载到./vendor目录下面。编译的时候也会使用目录下的依赖包,使用go vendor命令更新依赖包。这样子解决了依赖包和工程代码混杂的问题,但是没有解决多个工程代码之间混杂的问题。

  • Go Mod
export GO111MODULE=on // 启用go mod
复制代码

本质是使用go.mod文件来描述我们依赖库的名称和版本。下载的依赖会放在

$GOPAHT/pkg/mod文件夹下面
复制代码

同时工程代码不一定要放在GOPATH下面。

但是在企业实践中,我们还是建议所有工程都放在GOPATH目录下,这样工程结构会比较清晰,也就是govendor其实和go mod效果差不多。

Go mod 如何工作的

  • gomod版本的表达方式
  1. 语义化版本,也就是常见的v1.0.3这种形式
v${major}.${minor}.${patch}

major不同则认为是两个不同的仓库
复制代码
  1. 伪版本号

可以基于某个commit来,比如我们常见:

xx/xxx/xxx v0.0.0-20210323104329-2dfsdfsdf
xx/xxx/xxx v0.0.0        -20210323104329      -2dfsdfsdf
						基本版本前缀   commit utc时间        commit hash前12位
复制代码
  1. 主要的命令
go get xxxx依赖库
- go get 依赖库可以跟上具体的commit hash 也可以跟上某个分支例如:
- go get 依赖库@hash  
- go get 依赖库@master


go mod tidy // 自动添加或者删除项目依赖的库
复制代码
  • gomod 版本选择机制

问:x项目依赖a,b,a、b都依赖c项目,但是a依赖c的v1.1.1,b依赖c的v1.2.2,最后编译x的时候使用的c项目的版本是什么?

答案是最高版本v1.2.2。下图是Go mod的选择策略Minimal version selection (MVS)

![image-20210626155846867](/Users/bytedance/Library/Application Support/typora-user-images/image-20210626155846867.png)

工程和依赖管理常见问题

  • 在go mod文件中我们会看见一些标识:

    • // indirect

    此依赖不是本项目直接的依赖,但在本项目中指定该依赖。(a依赖b,b依赖c,在a中可以指定c是什么版本)

    • // incompatible

    该依赖未使用gomod管理依赖,不影响使用

  • 一些工具

go mod graph :查看依赖之前的关系

go mod vendor: 把依赖的文件放在工程目录下的vendor文件夹中,类似go vendor。一般不用提交vendor下的文件,主要是用来查、跳转代码用的。

  • 临时修改依赖库中的代码进行测试

git clone下来代码到本地,checkout对应版本,go mod文件中replace

业务实践中的经典案例

  1. go get -u 会拉取依赖的依赖,可能会导致一些意想不到的问题,建议不要加上-u
  2. 如果依赖没有使用mod,默认是拉取最新的版本;建议无论依赖有没有使用mod,我们的新项目都要用mod
  3. 依赖的a项目的tag删除了,该怎么办
    • 如果只是你的项目,那么就重新go get,获取最新的版本
    • 如果不仅是你的项目,而且你的依赖b也依赖这个a项目,那么就在你的项目上replace这个a项目。长期来看,还是要把你的依赖b重新go get一下。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享