vendor目录本身不改变go模块语义,仅是源码快照,必须配合-mod=vendor参数及gosumdb=off等环境变量才能实现可靠离线构建。

vendor 目录不是 Go 的默认行为,是 go mod vendor 手动触发的
Go 1.14 之后,vendor 目录完全被模块系统接管,它不再自动生效,也不会影响 go build 行为——除非你显式加 -mod=vendor 参数。很多人以为只要目录存在,编译就自动走 vendor,结果离线时仍报 cannot find module,就是因为漏了这个开关。
-
go mod vendor只是把当前go.mod中所有依赖(含 transitive)拷进vendor/,不校验版本一致性,也不清理冗余文件 - 离线编译必须配对使用:
go build -mod=vendor,否则 Go 工具链仍会尝试联网解析go.sum或 fetch 模块 - CI 环境中若用
go install或go test,同样要加-mod=vendor,不然测试可能因网络抖动失败
go.sum 不等于 vendor,但离线时两者缺一不可
go.sum 是模块校验和快照,记录每个依赖的哈希值;vendor/ 是源码副本。离线时,go build -mod=vendor 仍会读 go.sum 校验 vendor 里的代码是否被篡改或损坏——所以删掉 go.sum 或让它过期,会直接报 verifying github.com/xxx@v1.2.3: checksum mismatch。
- 执行
go mod vendor不会自动更新go.sum,需额外跑go mod verify或go build -mod=readonly触发校验并补全缺失条目 - 如果依赖里有 replace 指向本地路径(如
replace example.com/a => ../a),go mod vendor默认忽略它,vendor 里不会包含该模块,得手动 cp 或改用go mod edit -replace落到远端地址再 vendor - 某些私有仓库依赖(如用
git+ssh协议)在 vendor 后可能丢失 .git 信息,导致go list -m all显示版本为devel,影响构建可重现性
vendor 目录下没有 go.mod,但 go 命令仍按模块模式运行
有人误以为 vendor 是“退回到 GOPATH 时代”,其实不是。go build -mod=vendor 仍是模块模式,只是把模块查找路径从远程/本地缓存切到了 vendor/。vendor 目录里不能、也不该放 go.mod——Go 会直接忽略它,甚至报 go: inconsistent vendoring 错误。
- 项目根目录的
go.mod必须保持有效,vendor 只是它的“镜像”,不是替代品 - 如果 vendor 里混入了未声明在
go.mod中的包(比如手动 cp 进去),go build -mod=vendor会静默跳过,但go list -m all会漏掉它,造成依赖图不一致 - IDE(如 VS Code + gopls)默认不识别
-mod=vendor,提示 “no packages found” 是因为没传参数,需在settings.json配"go.toolsEnvVars": {"GOFLAGS": "-mod=vendor"}
离线编译失败?先检查 go env GOSUMDB 和 GOPROXY
即使用了 vendor 和 -mod=vendor,如果环境变量 GOSUMDB 没关,Go 仍会尝试连接 sum.golang.org 校验——这在纯离线环境必然超时失败。同理,GOPROXY 若设为 https://proxy.golang.org,go mod vendor 本身就会失败。
立即学习“go语言免费学习笔记(深入)”;
- 离线前务必设置:
go env -w GOSUMDB=off GOPROXY=direct,否则go mod vendor可能卡住或拉不到私有模块 -
GOSUMDB=off不影响go.sum文件存在,只跳过在线校验;但你要确保go.sum是之前联网时生成且完整 - 若团队共用离线构建机,建议把这两项写进 CI 脚本开头,而不是依赖开发者本地配置
-mod=vendor,或漏关 GOSUMDB,离线就等于白忙。










