go mod tidy 不清理本地模块缓存,仅同步 go.mod 与代码引用;真正清理需用 go clean -modcache 或脚本比对 go list -m all 与 cache 路径识别冷版本。

为什么 go mod tidy 不能删掉所有冗余文件
它只保证 go.mod 和实际代码引用一致,但不会清理本地 pkg/mod/cache 中已下载却未被当前模块树引用的版本。比如你曾经 go get github.com/some/pkg@v1.2.0,后来回退到 v1.1.0,v1.2.0 仍留在缓存里——go mod tidy 完全不管这事。
常见错误现象:磁盘空间突然告急,du -sh $GOPATH/pkg/mod/cache 显示几十 GB;执行 go list -m all 返回的模块数远少于 ls $GOPATH/pkg/mod/cache/download/github.com/ 下的子目录数。
-
go mod tidy是模块依赖“对齐”工具,不是“垃圾回收”工具 - 真正要清理的是
$GOMODCACHE(默认为$GOPATH/pkg/mod/cache)里的冷数据 - 别手动
rm -rf整个 cache 目录——会强制重下所有依赖,CI 或离线环境会卡死
用 go clean -modcache 清理最安全但太粗暴
这个命令会清空整个 $GOMODCACHE,适合本地开发机偶尔重置,但不适合日常维护或 CI 流程。它不区分热/冷模块,也不保留任何历史版本。
使用场景:CI 构建前确保干净缓存;本地怀疑 cache 损坏(如 checksum mismatch 错误反复出现)。
立即学习“go语言免费学习笔记(深入)”;
- 执行前确认没有其他
go进程正在写入 cache(否则可能中断下载) - 如果设置了
GOPROXY=direct或私有代理不稳定,清完后首次go build会明显变慢 - 它不接受参数过滤,无法指定“只删 v0.x 的旧版”或“跳过某组织下的模块”
精准清理:用 go list -m -u all + 脚本识别冷版本
核心思路是:找出当前模块树实际用到的所有模块版本(热版本),再对比 cache 中所有已存档路径,删除未被覆盖的。
关键点在于,go list -m all 输出的是 module path + version,而 cache 中路径是 $GOMODCACHE/download/{host}/{path}/@v/{version}.info 或 .zip,需做标准化映射。
- 先运行
go list -m all | cut -d' ' -f1,2 > active.mods得到当前活跃的module@version - 用
find $GOMODCACHE/download -name '*.info' -o -name '*.zip' | sed 's|/download/||; s|/@v/[^/]*\.info$||; s|/@v/[^/]*\.zip$||'提取 cache 中所有候选路径 - 把两组结果都转成统一格式(如
github.com/user/repo@v1.2.3),用comm -3找差集,就是可删的冷模块 - 注意
replace和indirect模块也会出现在go list -m all输出中,必须保留
示例片段(Bash):
#!/bin/bash
active=$(mktemp)
cache_paths=$(mktemp)
trap "rm -f $active $cache_paths" EXIT
go list -m all 2>/dev/null | awk '{print $1 "@" $2}' | sort > "$active"
find "$GOMODCACHE/download" \( -name '*.info' -o -name '*.zip' \) 2>/dev/null | \
sed -E 's|^.*/download/||; s|/@v/[^/]*\.(info|zip)$||' | sort -u > "$cache_paths"
comm -13 "$active" "$cache_paths" | while read p; do
echo "rm -rf $GOMODCACHE/download/$p"
done | sh
CI 环境里别自动清理,改用 go mod download 预热 + 缓存策略
在 GitHub Actions / GitLab CI 中,频繁清理 cache 反而降低命中率。更高效的做法是:固定 go.mod 后,只运行 go mod download,然后把 $GOMODCACHE 整体作为构建缓存键。
容易踩的坑:
- 某些 CI 配置用
actions/cache缓存$HOME/go/pkg/mod,但没设对key,导致不同分支共用同一 cache,引发invalid version -
go mod download不会触发replace规则,若用了本地replace,得先cp -r过去再下载 - Docker 构建时若用
multi-stage,第二阶段不要COPY --from=builder $GOMODCACHE,而是让 go 自己从第一阶段 cache 复制——否则路径错位
复杂点在于:模块冷热不是静态的,go.sum 里记录的 checksum 可能跨版本复用,而 cache 中的 .info 文件包含完整校验信息。删错一个 .info,下次 go build 可能因无法验证而重新下载——这不是失败,但会悄悄拖慢构建。所以脚本清理前,最好加一行 go mod verify 确保当前状态自洽。


















