用户铁铁妈 發表於 2023-1-28 16:22:00

go mod和go vendor的区别

<p>这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天</p>
<h2 id="背景">背景</h2>
<p>在家安装的环境可能路径和环境变量配的有些问题,导致项目import的包全部标红,go mod tidy显示导入包不在路径,怎么可能不在路径呢。</p>
<p>这就好比我们写cpp程序,我们从官方库里include一个.h,而后自己图方便也写了个.h,但是程序并不能识别出我们自己写的.h,并反问我们这个.h为什么不在官方的包里。exm..</p>
<p>那肯定是路径错了,设置来设置去也没解决。</p>
<p>原因可能是因为不熟悉linux操作,半途没保存导致没配成功,但还是跑出hello world导致我以为自己PATH对了。费尽心思改来改去,找依赖的路径,找了两天,最后得出结论——安装目录就已经乱了。遂打算重装。接下来的笔记大概是记录重装过程&amp;常用的操作合集,算是补充了第一篇笔记遗留的还没写的东西。</p>
<p>为了解决包的问题,go mod tidy建议我进行go mod vendor,果然不报错了,可是文件夹下多了1k多的变化,是他根据我的包定义的空包以及一些外部包导到项目目录的下载,只能解决编译报错问题,根本不能对项目有任何作用。后来才了解到go vendor早就已经不适用,早年1.13版本之前,go mod还未成熟,使用起来不太方便。 开发的时候还是需要<code>go get</code>提前下载包,然后再应用。 只有要打包的时候执行一套命令,类似于下面这样:</p>
<pre><code class="language-go">go mod init ./
go build main.go 或 go build -mod=vendor main.go
go mod vendor #将包打到vendor文件夹下
</code></pre>
<h2 id="go-vendor">Go Vendor</h2>
<p>安装<code>go get -u github.com/kardianos/govendor</code></p>
<p>基础命令</p>
<pre><code>govendor init # 创建vendor目录,创建vendor.json文件
govendor add +external #生成依赖包
govendor update +vendor # 更新vendor的包命令
init    初始化 vendor 目录
list    列出所有的依赖包
add   添加包到 vendor 目录,如 govendor add +external 添加所有外部包
add PKG_PATH    添加指定的依赖包到 vendor 目录
update从 $GOPATH 更新依赖包到 vendor 目录
remove从 vendor 管理中删除依赖
status列出所有缺失、过期和修改过的包
fetch   添加或更新包到本地 vendor 目录
sync    本地存在 vendor.json 时候拉去依赖包,匹配所记录的版本
get   类似 go get 目录,拉取依赖包到 vendor 目录
</code></pre>
<h2 id="go-mod">Go Mod</h2>
<p>go module是Go1.11版本之后官方推出的版本管理工具,并且从Go1.13版本开始,go module将是Go语言默认的依赖管理工具</p>
<p>modules是源代码交换和版本控制的单元。 go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。</p>
<p>要启用go module支持首先要设置环境变量GO111MODULE,通过它可以开启或关闭模块支持,它有三个可选值:off、on、auto,默认值是auto。</p>
<p>GO111MODULE=off禁用模块支持,编译时会从GOPATH和vendor文件夹中查找包。<br>
GO111MODULE=on启用模块支持,编译时会忽略GOPATH和vendor文件夹,只根据 go.mod下载依赖。<br>
GO111MODULE=auto,当项目在$GOPATH/src外且项目根目录有go.mod文件时,开启模块支持。</p>
<p>启用 Go Modules 功能</p>
<pre><code>export GO111MODULE=on
</code></pre>
<p>基础命令</p>
<pre><code>go mod download    下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit      编辑go.mod文件
go mod graph       打印模块依赖图
go mod init      初始化当前文件夹, 创建go.mod文件
go mod tidy      增加缺少的module,删除无用的module
go mod vendor      将依赖复制到vendor下
go mod verify      校验依赖
go mod why         解释为什么需要依赖
</code></pre>
<h6 id="新建项目中使用">新建项目中使用</h6>
<p>在<code>GOPATH 目录之外</code>新建一个目录,并使用<code>go mod init</code> 初始化生成<code>go.mod</code> 文件</p>
<pre><code class="language-bash">➜~ mkdir hello
➜~ cd hello
➜hello go mod init hello
go: creating new go.mod: module hello
➜hello ls
go.mod
➜hello cat go.mod
module hello
</code></pre>
<p>go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。</p>
<p>go.mod 提供了<code>module</code>, <code>require</code>、<code>replace</code>和<code>exclude</code> 四个命令</p>
<ul>
<li><code>module</code> 语句指定包的名字(路径)</li>
<li><code>require</code> 语句指定的依赖项模块</li>
<li><code>replace</code> 语句可以替换依赖项模块</li>
<li><code>exclude</code> 语句可以忽略依赖项模块</li>
</ul>
<p>添加依赖-&gt;执行go run-&gt;go mod 会自动查找依赖自动下载-&gt;查看go mod</p>
<p>只管加依赖,然后go mod tidy,可以理解为go mod是自动生成的。</p>
<h6 id="go-module-安装-package-原则">go module 安装 package 原则</h6>
<p>go module 安装 package 原则是先拉最新的 release tag,若无tag则拉最新的commit,详见 Modules官方介绍。 go 会自动生成一个 go.sum 文件来记录 dependency tree:</p>
<pre><code class="language-bash"># 查看dependency tree
$ cat go.sum
</code></pre>
<p>再次执行脚本 <code>go run</code> 发现跳过了检查并安装依赖的步骤。</p>
<p>可以使用命令 <code>go list -m -u all</code> 来检查可以升级的package,使用<code>go get -u need-upgrade-package</code> 升级后会将新的依赖版本更新到go.mod</p>
<p>也可以使用 <code>go get -u</code> 升级所有依赖</p>
<h6 id="使用-go-get--u-升级所有依赖">使用 go get -u 升级所有依赖</h6>
<ul>
<li>运行 go get -u 将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)</li>
<li>运行 go get -u=patch 将会升级到最新的修订版本</li>
<li>运行 go get package@version 将会升级到指定的版本号version</li>
<li>运行go get如果有版本的更改,那么go.mod文件也会更改</li>
</ul>
<h6 id="改造已有项目">改造已有项目</h6>
<ol>
<li>使用 <code>go mod init</code> 初始化go.mod</li>
<li>运行 <code>go run</code>, go.mod会更新</li>
</ol>
<p>查找并下载安装依赖后会报错cmd/go: 'cannot find module for path' when importing from subdirectories · Issue #26645 · golang/go (github.com)</p>
<p>解决:更新旧的package import 方式</p>
<p>原因:使用 internal package 的方法跟以前不同,go.mod会扫描同工作目录下所有 package 并且变更引入方法,必须将(当前工作文件)当成路径的前缀,需要写成 import xxx/api,以往GOPATH/dep模式允许的 import ./api 已经失效</p>
<h2 id="使用replace替换无法直接获取的package">使用replace替换无法直接获取的package</h2>
<p>由于某些已知的原因,并不是所有的package都能成功下载,比如:<code>golang.org</code>下的包。</p>
<p>modules 可以通过在 go.mod 文件中使用 replace 指令替换成github上对应的库</p>
<h2 id="go114版本vendor和go-module冲突问题">Go1.14版本vendor和go module冲突问题</h2>
<p>go1.14版本使用go mod tidy构建依赖时会出现问题(见链接), 这个问题在go1.12版本是不会出现的.</p>
<p>这是由于1.14版本官方加入了校验机制导致的,</p>
<p>解决:</p>
<ol>
<li>使用低版本的go, 但更推荐第二种方法.</li>
<li>删除自带vendor重建依赖</li>
</ol>
<p>项目文件夹下不能有vendor目录。除非是go mod vendor生成的</p>
<pre><code># 1. 删除vendor文件夹
mv vendor ${GOPATH}
# 2. 重新replace本地依赖, 指向${GOPATH}/vendor
vim go.mod
# 3. 重建依赖
go mod tidy
# 4. 生成vendor, 可做可不做
go mod vendor
</code></pre><br><br>
来源:https://www.cnblogs.com/peace0218/p/17070557.html
頁: [1]
查看完整版本: go mod和go vendor的区别