go mod常用命令 已经 常见问题

最近接触到go mod,网上查了查资料,这里记录一下。

1 介绍

1.1、go mod是什么

go mod 是Golang 1.11 版本引入的官方包(package)依赖管理工具,用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。

之前Golang 主要依靠vendor和GOPATH来管理依赖库,vendor相对主流,但现在官方更提倡go mod。

1.2、go mod初始化及使用

下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)

Golang 提供一个环境变量 GO111MODULE 来设置是否使用mod,它有3个可选值,分别是off, on, auto(默认值),具体含义如下:

    off: GOPATH mode,查找vendor和GOPATH目录
    on:module-aware mode,使用 go module,忽略GOPATH目录
    auto:如果当前目录不在$GOPATH 并且 当前目录(或者父目录)下有go.mod文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode。

修改 GO111MODULE 的值的语句是:set GO111MODULE=on 。

在使用模块的时候, GOPATH 是无意义的,不过它还是会把下载的依赖储存在 GOPATH/src/mod 中,也会把 go install 的结果放在 GOPATH/bin(如果 GOBIN 不存在的话)

go mod download 下载模块到本地缓存,缓存路径是 $GOPATH/pkg/mod/cache
go mod edit 是提供了命令版编辑 go.mod 的功能,例如 go mod edit -fmt go.mod 会格式化 go.mod
go mod graph 把模块之间的依赖图显示出来
go mod init 初始化模块(例如把原本dep管理的依赖关系转换过来)
go mod tidy 增加缺失的包,移除没用的包
go mod vendor 把依赖拷贝到 vendor/ 目录下
go mod verify 确认依赖关系
go mod why 解释为什么需要包和模块

注意有几个坑的地方:

go mod 命令在 $GOPATH 里默认是执行不了的,因为 GO111MODULE 的默认值是 auto。默认在$GOPATH 里是不会执行, 如果一定要强制执行,就设置环境变量为 on

go mod init 在没有接module名字的时候是执行不了的,会报错 go: cannot determine module path for source directory。可以这样执行:

$ go mod init github.com/jiajunhuang/hello

否则就要在 main.go 里加上导入声明,例如:

$ cat main.go
package main func main() {
println("Hello world")
}
$ go mod init
go: cannot determine module path for source directory /Users/jiajun/hello (outside GOPATH, no import comments)
$ vim go.mod
$ cat go.mod
module github.com/jiajunhuang/hello
$ go mod init
go mod init: go.mod already exists
$ rm go.mod
$ vim main.go
$ cat main.go
package main // import "github.com/jiajunhuang/hello" func main() {
println("Hello world")
}
$ go mod init
go: creating new go.mod: module github.com/jiajunhuang/hello
$ ls
go.mod main.go
$ cat go.mod
module github.com/jiajunhuang/hello

当然,如果在已有代码的仓库里执行是不存在这个问题的。

2 命令

2.1 指定module的根目录并生成go.mod文件

go mod init example.com/hello

2.2 下载并添加依赖到go.mod文件中

go build, go test

2.3 查看module下的所有依赖

go list -m all

2.4 更新稳定版依赖

go get rsc.io/sampler

2.5 更新为指定版本依赖

     

    go list -m -versions rsc.io/sampler

     
     
     

    rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99

     
     
     

    go get rsc.io/sampler@v1.3.1

2.6 清理无用的依赖

go mod tidy

2.7 将依赖复制到项目路径的vendor文件夹中

go mod vendor

2.8 忽略cache里的包,只使用vendor目录里的依赖进行编译

go build -mod=vendor

2.9 校验依赖并查看是否有修改

go mod verify

3 问题

3.1 go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

go mod init

go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

开启go module:

    set GO111MODULE=on //windows

    export GO111MODULE=on //linux

3.2 $GOPATH/go.mod exists but should not

GO 1.11或之后模块遇到这个问题:

$GOPATH/go.mod exists but should not

开启模块支持后(set GO111MODULE=on),并不能与$GOPATH共存,所以把$GOPATH从env中移出即可(unset GOPATH),可运行“unset GOPATH && make”。

4 例子

4.1 例子1

go mod初始化:在$GOPATH外建一个文件夹,把个人代码放进去,我的测试代码路径:https://github.com/kevinhao8/go-mod-example。

首先main入口代码所在文件夹创建mod

创建语句  go mod init [module name]

比如我的测试代码 redisTest.go,创建语句就是  go mod init redisTest,成功创建时返回  go: creating new go.mod: module redisTest

此时文件夹下出现 go.mod文件,打开发现只有2行如下,并没有记录依赖库。

module redisTest

go 1.12

此时需要输入go test语句,根据需要的依赖自动生成require,也就是依赖包,此时go.mod多了如下内容(红字是我写的注释,文件里面没有)

require (
      github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect(有indirect注释的代表间接依赖,没有的代表直接依赖)
      github.com/gin-gonic/gin v1.3.0  
      github.com/golang/protobuf v1.3.1 // indirect
      github.com/mattn/go-isatty v0.0.7 // indirect
      github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect(这里是版本号+时间戳+hash)
      gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
      gopkg.in/yaml.v2 v2.2.2 // indirect
)

此时会有如下失败提示,此处为我踩得第一个坑!!!花了挺长时间才解决

build redisTest: cannot load dbredis: cannot find module providing package dbredis

dbredis是我写的私有包,代码是没有问题的,为什么找不到呢?从网上查了一圈,发现私有包如果不想发布到网上,需要手动添加require ,然后replace 进行替换,将私有包指向本地module所在的绝对或相对路径。一般用相对路径更通用。

此时手动将go.mod改为如下,红字为新加

require (
      dbredis v0.0.0
      github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
      github.com/gin-gonic/gin v1.3.0
      github.com/golang/protobuf v1.3.1 // indirect
      github.com/mattn/go-isatty v0.0.7 // indirect
      github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect
      gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
      gopkg.in/yaml.v2 v2.2.2 // indirect
)

replace dbredis v0.0.0 => ./dbredis

再度运行go test  命令,发现仍有失败提示如下,找不到dbredis文件夹下的go.mod文件。

go: parsing dbredis\go.mod: open E:\code\go-mod-example\dbredis\go.mod: The system cannot find the file specified.
go: error loading module requirements

从网上查资料发现,这种情况下需要给私有包也生成mod,这样整个工程的依赖才能完整。故运行如下命令:

cd dbredis

go mod init dbredis(此处我写的mod名跟package名一致,不知道不一致行不行)

go test

三条命令依次运行通过,dbredis文件夹下的go.mod文件如下:

module dbredis

go 1.12

require github.com/go-redis/redis v6.15.2+incompatible

此时再运行如下命令:

cd ..(回到上层文件夹)

go test

运行通过,不再有报错。运行命令 go build redisTest.go 也能够正常生成redisTest.exe

至此通过mod来管理依赖包基本实现,我们的程序能基本脱离$GOPATH编译。

5 go mod 和 dep 比较

go mod 支持代理,以后就可以使用私有镜像源了~,具体请搜索 GOPROXY
go mod 速度比 dep 快很多
go.mod 中列出了所有的依赖,这一点其实我不是很喜欢,因为当项目一大,历史一久,只要升级其中一个依赖,很可能整个依赖 就挂了。我还是比较喜欢只要列出顶级依赖,由程序处理子依赖的情况。

一个生成的 go.mod 的示例

module github.com/my/module/v3  // 这是你的包的声明

// require 里是依赖。需要带上路径和版本。
require (
github.com/some/dependency v1.2.3
github.com/another/dependency v0.1.0
github.com/additional/dependency/v4 v4.0.0
)

https://github.com/golang/go/wiki/Modules

其他

windows下的尝试:

gomod初尝试
下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)
go mod help查看帮助
go mod init<项目模块名称>初始化模块,会在项目根目录下生成 go.mod文件。

go mod tidy根据go.mod文件来处理依赖关系。

go mod vendor将依赖包复制到项目下的 vendor目录。建议一些使用了被墙包的话可以这么处理,方便用户快速使用命令go build -mod=vendor编译

go list -m all显示依赖关系。go list -m -json all显示详细依赖关系。

go mod download <path@version>下载依赖。参数<path@version>是非必写的,path是包的路径,version是包的版本。

在gopath外新建一个项目,单独开一个cmd设置set GO111MODULE=on(习惯性的和git初始化一样)go mod init然后报错了。 正解如下:go mod init xxx(module名称可与文件名不同)

在项目目录下执行go mod tidy下载完成后项目路径下会生成go.mod和go.sum

go.mod文件必须要提交到git仓库,但go.sum文件可以不用提交到git仓库(git忽略文件.gitignore中设置一下)。

go模块版本控制的下载文件及信息会存储到GOPATH的pkg/mod文件夹里。

--------------------分割线---------------------------------------------------------

gopath 与go mod的区别

     

    环境变量GOPATH不再用于解析imports包路径,即原有的GOPATH/src/下的包,通过import是找不到了。

     

    Go Module功能开启后,下载的包将存放与$GOPATH/pkg/mod路径

     

    $GOPATH/bin路径的功能依旧保持

go get 流程的变化

     

    老的go get取包过程类似:git clone + go install , 开启Go Module功能后go get就只有 git clone 或者 download过程了。

     

    新老实现还有一个不同是,两者存包的位置不同。前者,存放在$GOPATH/src目录下;后者,存放在$GOPATH/pkg/mod目录下。

     

    老的go get取完主包后,会对其repo下的submodule进行循环拉取。新的go get不再支持submodule子模块拉取。

依赖包的变化

     

    三方远程包:

     

    检查远程仓库最新的tag版本,有就取得该版本

     

    远程仓库没有tag版本时,直接获取master分支的HEAD版本

     

    如果在go.mod文件中指定了具体版本,go get直接获取该指定版本

     

    go.mod中除了可以指定具体版本号以外,还支持分支名

     
     
     

    本地包:

     

    通过replace()进行替换

私有仓库权限和私有vcs非标准路径取包问题

     

    权限问题

     

    windows10下:

     

        控制面板>用户账户>凭据管理手动添加普通凭据即可

     

    linux下:

     

    增加 $HOME/.gitconfig 配置:

     

    [url "ssh://git@github.com/MYORGANIZATION/"]

     

    insteadOf = https://github.com/MYORGANIZA...

     
     
     

    增加 $HOME/.netrc:

     

    machine github.com login YOU password APIKEY

     

    将其中的 APIKEY 换成自己的登录KEY。

     
     
     

    非标准路径问题(https://private.vcs.com:20000)

     

    搭建一个中间服务:https://private.vcs.com 能够通过go get的包路径匹配查询正确的仓库地址。

参考:

https://blog.csdn.net/Lazybones_3/article/details/89355133

https://blog.csdn.net/kevinh531/article/details/88691870

https://jiajunhuang.com/articles/2018_09_03-go_module.md.html

https://blog.csdn.net/qq_33296108/article/details/88184060

go mod常用命令 已经 常见问题的相关教程结束。

相关推荐:

Python包管理工具_pip常用命令总结

pip是python核心包管理工具,支持安装(含指定版本)、升级、卸载、查看、搜索包及配置镜像源等操作,如pipinstallrequests、piplist、pipuninstallrequests、pipconfigsetglobal.index-url。 pip是Python最常用的包管理工具...

Python 网络编程常见问题总结

python网络编程常见坑包括:socket默认阻塞需设超时;recv()不保证收全数据须拼包;中文需统一utf-8编解码;socket非线程安全应独占使用。 Python网络编程中,很多问题并非语法错误,而是对底层协议、IO模型或库行为理解偏差导致的。以下是最常踩的几类坑,覆盖阻塞与非阻塞、连接管...

Python 并发模型详解及面试常见问题

Python的GIL是什么,它如何影响并发 CPython解释器中存在一个全局解释器锁(GIL),它确保同一时刻只有一个线程执行Python字节码。这意味着多线程在CPU密集型任务中无法真正并行,只能交替执行;但对I/O密集型任务影响较小,因为线程在等待I/O时会主动释放GIL。 关键点: GIL是...

Python 爬虫项目常见问题汇总

Python爬虫项目上线后,多数问题不是出在代码语法上,而是集中在请求行为、反爬应对、数据提取和运行稳定性这几个环节。下面整理高频问题及对应解决思路,不讲理论,只说实际踩过的坑和怎么绕过去。 请求被拒绝:403、406、ConnectionResetError 网站返回403或直接断连,大概率是请求...

Python ValueError 常见问题总结

ValueError本质是数据不符合预期 Python报ValueError,不是语法错,也不是找不到对象,而是函数或操作“看不惯”你给的数据——类型对,但值不合适。比如int("abc")不报TypeError(字符串能转int是合法操作),但会报ValueError,因为"abc"这个值无法解析...

Python ImportError 常见问题总结

pythonimporterror常见原因有五类:①模块名拼写或大小写错误;②模块不在sys.path搜索路径中;③循环导入导致部分初始化失败;④缺少依赖或版本/环境不兼容;⑤包目录缺失__init__.py文件。 模块名拼写错误或大小写不匹配 Python区分大小写,importMyModule和...

Python 列表删除元素的正确方式面试常见问题

删除元素应据需求选方法:按值删用remove()(仅首匹配,需防valueerror);按位置删用pop()(返回元素)或del(不返回);遍历时禁用remove()/pop(),宜反向遍历、列表推导式或切片赋值。 Python列表删除元素看似简单,但面试中常考细节:什么时候用remove()、po...