Go模块缓存是显式机制,存于$GOPATH/pkg/mod(或默认路径),按哈希分层存储源码、go.mod和.info校验文件;构建时严格校验go.sum与.info的checksum,不一致则报错;缓存不解决版本漂移,需锁死patch版本。
Go 模块缓存不是“自动隐形”的黑盒,而是有明确路径、校验逻辑和加载优先级的显式机制:它把下载过的模块版本(含源码、go.mod、go.sum)存到本地固定目录,后续构建时直接复用,跳过网络请求和重复解析。
Go 默认把模块缓存放在 $GOPATH/pkg/mod;若未设 GOPATH,则使用 $HOME/go/pkg/mod(Linux/macOS)或 %USERPROFILE%\go\pkg\mod(Windows)。
这个目录下不是扁平存放,而是按模块路径哈希分层组织,例如:
golang.org/x/net@v0.25.0 → 实际路径类似 golang.org/x/net@v0.25.0/ 子目录go.mod 和一个 .info 文件(记录校验和)go mod download golang.org/x/net@v0.25.0 后,就能在该路径下看到对应内容。不手动删,它就一直留着——哪怕项目里已移除该依赖。
Go 不是“文件存在就用”,而是在构建前做三步检查:
go.sum 中该模块版本的 checksum 是否已记录.info 文件,比对 checksumchec
ksum mismatch 并拒绝使用(哪怕源码看起来“没变”)go build 也会失败;
- go mod verify 就是干这个校验的,建议 CI 中固定执行;
- go.sum 必须提交进 Git,否则不同人本地缓存可能“各自为政”。
go.mod 依赖版本变了,但旧版本缓存还在——这不叫“失效”,只是“没被用上”go 会 fallback 到 direct,但若 GOPROXY 配置漏了 direct,就会卡住go mod download 写入一半中断,缓存目录里留下残缺版本(此时 go mod verify 必然失败)go clean -modcache 是清空全部,但不会动 go.sum 或 go.mod——清完立刻 go mod download 才能恢复go clean -modcache是最粗暴也最安全的重置方式,但它代价高:所有模块都要重下,CI 时间拉长,本地开发也要等几分钟。 更轻量的做法是:
rm -rf $GOPATH/pkg/mod/cache/download/github.com/some/lib/@v/v1.2.3
go mod download,而不是反复清理go clean -modcache && go mod download,避免缓存污染;日常开发几乎不用碰go.mod 里声明的版本。如果你没锁死 require 的 patch 版本(比如写成 github.com/foo/bar v1.2.0 而非 v1.2.3),那缓存再稳,下次 go get -u 也可能拉来新 patch。
缓存机制本身很稳,出问题的从来不是缓存,而是对它“默认信任却未验证”的假设。