离线go升级需三步:先在联网机锁定go.mod/go.sum并提交、整份迁移$gopath/pkg/mod/cache、全程设goproxy=direct;私有模块还需同步打tag并配置goprivate和ca证书。

离线环境无法直接执行 go get 或 go list -u,所谓“平滑升级”本质是两阶段动作:先在有网机器上完成可验证的版本切换与校验,再将完整、一致的状态同步到离线机。跳过任一环节都可能引发 checksum mismatch 或构建失败。
离线升级前必须确认 go.mod 和 go.sum 已锁定且无本地未提交变更
这是整个流程可信的前提。如果 go.mod 中存在未提交的 replace、exclude,或 go.sum 里混入了临时拉取的哈希(比如用 @latest 试过但没 commit),离线机上的 go build 就会因校验失败中断。
- 在联网机器上运行
git status,确保go.mod和go.sum都 clean - 用
go list -m -mod=mod -u all查看待升级项,只对明确需要升级的模块执行go get example.com/pkg@v1.2.3(严禁用@latest) - 升级后立即
git add go.mod go.sum && git commit -m "bump pkg to v1.2.3",不提交就拷贝等于埋雷
依赖缓存必须整份迁移,不能只拷贝 vendor 目录
go mod vendor 生成的 vendor/ 只含直接依赖的源码,不包含其子依赖的 go.sum 校验信息,也不含 golang.org/x/ 等间接依赖的元数据。离线构建时若启用 -mod=vendor,Go 仍会尝试读取 $GOPATH/pkg/mod/cache 中的模块元信息,缺了就报错。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 在联网机器上执行
go mod download,确保所有require行对应模块已落盘到$GOPATH/pkg/mod/cache - 用
tar -czf mod-cache.tgz -C $GOPATH/pkg mod/cache打包整个cache目录(保留层级结构) - 离线机解压时必须还原到相同路径:
sudo tar -xzf mod-cache.tgz -C $GOPATH/pkg,路径错一位就会找不到模块
GOPROXY=direct 是硬性要求,且需在构建全程生效
只要环境变量里还残留 GOPROXY=https://goproxy.cn 或其他代理地址,哪怕只在 shell 里 export 过一次,go build 就会在解析模块时发起 DNS 查询,导致超时卡住——这不是错误提示,而是静默 hang 住。
- 离线机上全局设置:
echo 'export GOPROXY=direct' >> ~/.bashrc && source ~/.bashrc - Docker 构建时,在
Dockerfile的 builder 阶段开头加ENV GOPROXY=direct,不能只写在 final 阶段 - CI 脚本中所有
go命令前显式加GOPROXY=direct,避免继承 runner 环境变量
私有模块升级要同步打 tag 并更新 GOPRIVATE
内网 GitLab 上的私有模块,如果只改了代码没打 tag,go get git.internal/pkg@v2.1.0 会失败;如果 GOINSECURE 或 GOPRIVATE 没配,Go 会因证书或代理问题拒绝访问,最终表现为 unknown revision。
- 升级私有模块前,先在仓库里
git tag v2.1.0 && git push origin v2.1.0 - 联网机器和离线机器都要设置
export GOPRIVATE="git.internal/*"(注意通配符语法) - 若用 HTTPS 访问私有 Git,离线机还需提前把内网 CA 证书追加到系统证书链,否则 TLS 握手失败
最容易被忽略的是:离线升级不是“把新版本拷过去就行”,而是“让两台机器的模块缓存、校验文件、环境变量三者状态完全一致”。少一个 go.sum 行、漏一条 GOPRIVATE、缓存目录权限不对(如 root 写、普通用户读),都会让看似成功的升级在真正构建时崩掉。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










