go get @vx.y.z 未写入 go.mod 是因它仅作版本偏好提示,非强制覆盖;若已有更高主版本则拒绝降级,或 tag 不可达时 fallback 到 latest;应使用 go mod edit -require + go mod tidy 强制写入并同步。

go get @vX.Y.Z 为什么没把版本写进 go.mod
执行 go get github.com/sirupsen/logrus@v1.9.3 后,go.mod 里仍是 v2.0.0+incompatible 或根本没变——这不是命令失效,而是 Go 把它当作“版本偏好提示”,不是强制覆盖指令。
- 如果已有更高主版本(比如
v2.0.0),Go 默认拒绝降级,报错version "v1.9.3" is lower than current version - 如果该 tag 在代理(如
https://proxy.golang.org)中不存在或未缓存,Go 会 fallback 到 latest 并只 warn,不 abort -
@v1.9.3是语义化版本请求,但若仓库没打规范 tag(比如只有 commit 或 branch),Go 无法解析
真正生效的做法是绕过“提示”逻辑,直接写入并清理:
- 先删旧 require 行:
go mod edit -droprequire=github.com/sirupsen/logrus - 再精确写入:
go mod edit -require=github.com/sirupsen/logrus@v1.9.3 - 最后同步依赖图:
go mod tidy - 验证结果:
go list -m github.com/sirupsen/logrus应输出v1.9.3
如何让 v1 和 v2 版本共存于同一项目
Go Modules 不允许同一模块路径(如 github.com/sirupsen/logrus)同时存在 v1.9.3 和 v2.1.0 ——它靠路径区分版本,不是靠版本号本身。
- 必须使用不同导入路径:一个用
import "github.com/sirupsen/logrus"(对应 v1),另一个用import "github.com/sirupsen/logrus/v2"(对应 v2) -
go.mod中需同时存在两行:github.com/sirupsen/logrus v1.9.3和github.com/sirupsen/logrus/v2 v2.1.0 - 不能用
replace把/v2映射回根路径,否则破坏模块隔离,go.sum校验失败 - 没有
/v2子路径的模块(即+incompatible)无法与兼容版本共存,Go 会统一选一个——通常是最高版本
间接依赖被悄悄升级怎么办
你没 import 某个包,但它被其他依赖引入(标记为 // indirect),go get -u 却把它升了——这是默认行为,不是 bug。
-
go get -u=patch只升 patch 版本(如v1.2.3 → v1.2.4),不碰 minor/major - 想彻底冻结某个间接依赖?手动在
go.mod中加require行(即使没直接 import),再go mod tidy - 检查哪些间接依赖被动了:
go list -m all | grep -v 'your-module-name' - CI 中建议加校验:
git status --porcelain go.sum,非空则失败(防哈希被篡改或源变更)
vendor 目录真能离线构建吗
有 vendor/ 不等于离线安全,它只是可选兜底手段,且默认不生效。
- 构建时必须显式加
-mod=vendor:go build -mod=vendor,否则 Go 仍走GOPROXY -
go mod vendor只复制go.mod里声明的依赖,不会自动更新已存在的vendor/内容 -
vendor/必须和go.mod、go.sum一起提交,且每次go mod tidy后要重跑go mod vendor - 私有模块或无签名仓库下,
go.sum是唯一可信依据;丢掉它,vendor就失去防篡改意义
多版本共存的关键不在“下载”,而在模块路径是否严格区分、go.mod 是否被精确编辑、go.sum 是否受控——任何一步跳过,都会在 CI 或新机器上暴露问题。











