go.mod 是 go 唯一依赖边界,依赖隔离只认当前目录下的 go.mod;go.sum 必须提交以确保校验;replace 仅限本地调试且路径须以 ./ 开头;go.work 不参与构建,ci 中须禁用;goproxy 和 gosumdb 是安全基线,不可关闭。

go.mod 是唯一依赖边界,不是目录或环境变量
Go 的依赖隔离不靠虚拟环境、不靠 shell 环境、也不靠项目放在哪,只认当前工作目录下的 go.mod。只要它存在,go build、go run、go list -m all 全部以此为准。
常见错误现象:在项目 A 目录下执行 go get github.com/sirupsen/logrus@v2.3.0,结果项目 B 也“自动升级”了——本质是误在项目 B 目录外执行了命令,导致 go.mod 被意外修改或创建;或者项目 B 根目录没 go.mod,退回到 GOPATH/src 查找,污染了全局视图。
- 每个项目根目录必须运行
go mod init your-module-name,模块名建议用域名前缀(如example.com/myapi),避免和公共包冲突 - 禁用
GOPATH模式:设GO111MODULE=on,且确保没在任意项目外执行go mod命令(比如在~/下手抖敲了go mod init) -
go.sum必须提交到 Git —— 它记录每个依赖的 checksum,缺失会导致go build失败或校验跳过(日志里出现skipped而非verified)
replace 和 require 的本地路径必须指向本项目内
用 replace 指向其他项目的本地路径(如 replace github.com/a/b => ../b)是最大泄漏点:构建时会静默拉取外部代码,破坏隔离性,CI 中还可能因路径不存在直接失败。
使用场景:本地调试未发布的内部模块,或修复上游 bug 后临时替换。
- 所有
replace路径必须是相对路径且以./开头(如replace github.com/a/b => ./internal/b),禁止跨项目目录 - 上线前必须删掉
replace行,改用正式发布版本号;或用go work use在工作区统一管理(仅限开发机,不影响构建) -
require中不能出现indirect依赖被手动提升却未实际使用的情况——go mod tidy会自动清理,但若留着,可能掩盖真实依赖树
go.work 只用于本地多模块编辑,不参与构建
go.work 文件只影响 VS Code 跳转、IDE 补全和 go run 本地调试,构建发布时仍以各子模块自己的 go.mod 为准。把它放在父目录共享给多个项目,反而会让 go list 返回混乱的模块列表。
常见错误现象:执行 go list -m all 发现输出里混了不该出现的模块;或 CI 构建时提示 “no required module provides package”,其实是工作区干扰了模块解析。
-
go.work必须放在该工作区专属根目录(如~/work/monorepo/),且该目录下不能有go.mod - 添加模块用
go work use ./service-a ./shared-lib,路径必须是相对于go.work所在目录的子路径 - CI 流水线中禁用
go.work—— 构建命令前加unset GO_WORK或直接删掉go.work文件
proxy 和 sumdb 配置决定依赖来源可信度
医疗、金融类系统要求所有依赖可追溯、不可篡改。GOPROXY 和 GOSUMDB 不是可选项,而是安全基线。设成 off 或 direct 为主,等于放弃校验。
使用场景:内网离线构建、合规审计、确定性编译。
- 强制设
GOPROXY=https://goproxy.cn,direct——direct仅允许已知私有仓库(如git.internal.company.com),公共模块必须走代理 -
GOSUMDB=sum.golang.org必须启用,禁止设为off;内网无法访问时,需部署私有sum.golang.org镜像并配置对应地址 - 验证是否生效:
go mod download -x github.com/sirupsen/logrus@v1.9.0,日志中必须出现verified github.com/sirupsen/logrus@v1.9.0,而非skipped
真正难的不是写对 go.mod,而是让所有人理解:隔离不是“启动一个环境”,而是守住三道门——模块文件位置、路径引用范围、代理校验开关。漏掉任何一道,依赖就可能从开发机悄悄溜进生产镜像。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











