vendor目录解决依赖版本不一致和离线构建问题:它将依赖包特定版本快照到本地,使go build等命令只读取vendor/而非GOPATH或模块缓存,确保构建可重现与离线可用。
Go 的 vendor 目录本质是把依赖包的特定版本“快照”到项目本地,让 go build、go test 等命令默认只读取它,而非 $GOPATH 或模块缓存。它最直接解决两个现实痛点:
go get 到的依赖版本不一致,导致构建结果不可复现在 Go 1.5 引入 vendor 机制、到 Go 1.11 模块(module)成为默认之前,这是主流的依赖锁定方案。即使现在用 go mod,vendor 仍可作为可选补充——比如你明确要求所有构建必须离线完成。
只要项目根目录下存在 vendor 文件夹,且当前工作目录在该模块内,go 命令(1.6+)会自动启用 -mod=vendor 模式,即:
go build 不再读取 go.sum 或模块缓存,只从 vendor/ 加载包go list -m all 仍显示模块依赖树,但 go list -f '{{.Dir}}' some/pkg 返回的是 vendor/ 下路径go mod tidy 默认仍会修改 go.mod 和 go.sum,但不会触碰 vendor/ 内容;要同步 vendor,得显式运行 go mod vendor
注意:如果项目启用了 module(有 go.mod),又想临时禁用 vendor,可以加 -mod=readonly 或 -mod=mod 参数覆盖默认行为。
看似简单,实操中几个点容易翻车:
go mod vendor 不会自动感知 go.mod 变更,改了依赖后必须手动执行,否则 vendor/ 和 go.mod 不一致,CI 构建可能失败或行为异常vendor/ 下可能混入编辑器临时文件、.gitignore 未覆盖的构建产物,导致仓库臃肿甚至泄露敏感信息go.mod,其 vendor/ 不会被主命令识别;Go 只认当前模块根下的 vendor/
golint)或 IDE 插件(旧版 Goland)在 vendor 模式下路径解析出错,报 “cannot find package”一个典型错误现象:go test ./... 成功,但 go test -v ./cmd/myapp 报错说找不到某个 vendor 里的内部工具包——这是因为该包被 go.mod 声明为 replace,而 vendor 里没同步替换后的代码。
绝大多数新项目不需要主动维护 vendor 目录。Go 模块 + go.sum 已足够保证可重现构建,而且体积小、更新快、语义清晰。只有当你遇到以下任一情况,才值得引入 vendor:
备 CI)如果决定用,务必把 go mod vendor 加进 CI 流程的前置检查,并在 .gitignore 里严格限定只允许 /vendor/**,禁止 vendor/ 下出现任何非 Go 源码文件。