go build 默认不读取 vendor 目录,需显式加 -mod=vendor 参数;go 1.16+ 启用模块模式后,vendor 仅为可选快照,非默认加载路径。

go build 为什么没用 vendor 目录?
默认情况下,go build 不会读取 vendor/ 目录,除非你显式加 -mod=vendor 参数。这是 Go 1.16+ 的行为——Modules 默认启用(GO111MODULE=on),此时 vendor 只是“可选快照”,不是默认加载路径。
常见错误现象:vendor/ 下明明有 github.com/sirupsen/logrus,但 go build 仍报 cannot find package。原因通常是:
-
GO111MODULE=on(或未设为off),且没加-mod=vendor -
go.mod文件存在,但go mod vendor没执行过,vendor/是空的或结构错乱 -
vendor/内部目录层级不匹配 import path(比如缺了github.com/这一级)
什么时候必须用 go mod vendor?
不是“要不要用 vendor”,而是“要不要把依赖打包进代码树”。真正需要 go mod vendor 的场景非常具体:
- 离线构建环境(CI/CD 节点无外网、或禁止访问 proxy.golang.org)
- 交付二进制时需附带完整源码副本(如某些军工、金融类审计要求)
- 配合旧版构建工具链(如某些嵌入式交叉编译脚本硬编码找
vendor/)
注意:go mod vendor 生成的 vendor/ 仍依赖 go.mod 和 go.sum;删掉这两个文件,vendor/ 就失去校验依据,变成不可信快照。
go get 和 go install 在 mod 模式下怎么工作?
在 GO111MODULE=on 下,go get 不再往 $GOPATH/src 写代码,而是:
- 下载模块到
$GOPATH/pkg/mod/cache(全局只存一份) - 根据
go.mod中声明的版本(如github.com/gin-gonic/gin v1.9.0)解析并软链接使用 -
go get github.com/sirupsen/logrus@v1.13.0会更新go.mod并触发go.sum校验
go install 行为也变了:它现在默认安装的是模块路径(如 golang.org/x/tools/gopls@latest),而非本地 $GOPATH/bin 下的命令。如果要安装当前项目主包,得用 go install ./cmd/myapp@latest。
vendor 目录提交到 Git 是好是坏?
提交 vendor/ 是明确的工程决策,不是“可选习惯”。它带来两个硬代价:
- Git 仓库体积暴涨(常达几十 MB,含数千个文件)
- diff 噪声极大——一次
go mod vendor可能产生上千行修改,掩盖真实业务变更
但它换来的是构建确定性:只要 go.mod + go.sum + vendor/ 三者一起提交,任何人在任何机器上运行 go build -mod=vendor 都能得到完全一致的二进制。这点对发布分支或长期维护的老项目很关键。
容易被忽略的是:vendor/ 不是“备份”,它是构建时的**权威依赖源**;如果有人绕过 go mod vendor 手动增删 vendor/ 文件,就彻底破坏了哈希一致性——go build -mod=vendor 仍能通过,但实际用的已不是 go.sum 记录的代码。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











