Web Analytics

Go 模块迁移不踩坑:import path 稳定性的艺术

一场本不该发生的迁移 我认识一个团队,花了三周时间把 120 个 Go 服务从一个 Git 平台迁移到另一个。代码搬迁只用了一天。剩下的两周半?在更新每一个 repo、每一条 CI 流水线、每一个 Dockerfile、每一个下游消费者的 import path。 最扎心的是:他们之前已经经历过一次了。两年前从 SVN 迁移到 Git,那时候也重写了所有 import path。 这种悲剧反复上演,因为大多数团队把 import path 当作偶然的——Git 平台给什么路径就用什么。但 import path 是身份标识。它是所有下游项目找到你的代码的方式。改了身份,就断了所有依赖你的人。 这篇文章讲的是如何让 import path 稳定——代码可以搬,基础设施可以换,import path 永远不用改。 Import Path 为什么会断 先盘点一下哪些情况会迫使你修改 import path: 触发事件 发生什么 影响范围 Git 平台迁移 GitHub → GitLab,或迁到自建平台 所有模块,所有消费者 组织重命名 公司改名,GitHub org 名称变更 所有模块,所有消费者 仓库转移 把 repo 移到另一个 org 该模块 + 所有消费者 拆分 Monorepo 大仓拆成独立仓库 拆出的模块 + 消费者 合并为 Monorepo 多个独立仓库合入大仓 每个合入的模块 + 消费者 服务器搬迁 自建 Git 服务器 IP/域名变更 所有模块,所有消费者 发现规律了吗?每一个都是基础设施变更,不是代码变更。 你的代码没变,API 没变,但所有下游项目都要更新 go.mod、跑 go mod tidy、做一次完整的回归测试——只因为地址变了。 ...

2026年7月15日 · Tony Bai

通配路由:一条规则管理 50 个 Go 模块

路由税 你的团队已经用上了 vanity URL。导入路径干净了,不再绑定平台,看着就舒服: import "go.mycorp.com/auth" import "go.mycorp.com/config" import "go.mycorp.com/logger" 然后团队扩张了。每个迭代都有新服务上线。每个新服务都需要一条 gvu add 命令: gvu add go.mycorp.com/auth https://github.com/mycorp/auth.git gvu add go.mycorp.com/config https://github.com/mycorp/config.git gvu add go.mycorp.com/logger https://github.com/mycorp/logger.git gvu add go.mycorp.com/cache https://github.com/mycorp/cache.git gvu add go.mycorp.com/queue https://github.com/mycorp/queue.git # ... 还有 45 个 50 个仓库,50 条路由。每新建一个仓库就要提个 PR 更新路由配置。谁忘了?新服务的 go get 直接报错,整个团队被卡住。 这就是路由税——维护 vanity URL 映射的人工开销,而这些映射本该是自动的。 一条规则覆盖所有仓库 通配路由消灭路由税。不需要逐个添加仓库,你只需要写一条规则覆盖路径前缀下的所有仓库: gvu add 'go.mycorp.com/*' 'https://github.com/mycorp/*.git' 搞定。一行命令。现在 mycorp GitHub org 下的每个仓库都自动可用 vanity 路径导入: import "go.mycorp.com/auth" // → github.com/mycorp/auth import "go.mycorp.com/config" // → github.com/mycorp/config import "go.mycorp.com/logger" // → github.com/mycorp/logger import "go.mycorp.com/newthing" // → github.com/mycorp/newthing(立刻可用!) 在 GitHub 上创建了个新仓库?立刻可以用 vanity 域名 go get 拉取。不用改配置,不用提 PR,不用等人。 ...

2026年7月14日 · Tony Bai

Go Monorepo 实战:用 Vanity URL 管理多模块

Monorepo 的困境 你的团队在使用 monorepo。所有 Go 服务都放在一个 Git 仓库里: monorepo/ ├── go/ │ ├── auth/ │ │ └── go.mod # module github.com/org/monorepo/go/auth │ ├── config/ │ │ └── go.mod # module github.com/org/monorepo/go/config │ └── logger/ │ └── go.mod # module github.com/org/monorepo/go/logger ├── proto/ ├── deploy/ └── README.md 三个 Go 模块,一个仓库。这是常见的模式——共享 CI、原子化的跨模块修改、一致的版本管理。 但 import path 又长又丑,还嵌套得很深: import ( "github.com/org/monorepo/go/auth" "github.com/org/monorepo/go/config" "github.com/org/monorepo/go/logger" ) 而且绑定在 GitHub 上。要迁移到 GitLab?所有 import 都得改。 你想要 vanity URL: import ( "go.company.com/auth" "go.company.com/config" "go.company.com/logger" ) 但问题来了:传统的 go-import meta 标签是一个 import path 映射一个 repo。你的 monorepo 是一个 repo 里有三个模块。怎么搞? ...

2026年7月13日 · Tony Bai

30 秒为你的 Go 模块设置自定义导入路径

什么是 Vanity URL? 简单来说,Vanity URL 让你的 Go 模块拥有一个属于你自己的导入路径,而不是绑定在 GitHub/GitLab 的地址上。 // ❌ 冗长且绑定平台 import "github.com/your-org/your-project" // ✅ 简洁、品牌化、与平台无关 import "go.yourcompany.com/your-project" 底层代码可以放在任何 Git 服务器上——GitHub、GitLab、Gitea、自建服务器都行。更换代码仓库时,import path 不需要任何改动。 这篇教程带你从零开始,30 秒搞定。 Step 1:安装 gvu(10 秒) Linux / macOS: curl -fsSL gomodvanityurls.com/install.sh | bash Windows (PowerShell): powershell -ExecutionPolicy ByPass -c "irm https://gomodvanityurls.com/install.ps1 | iex" 安装完成后验证: $ gvu --version gvu version 0.1.5 (built: 2026-07-09T10:00:00Z) Step 2:添加你的第一个 Vanity URL(20 秒) 假设你有一个 GitHub 仓库 https://github.com/yourorg/awesome-lib,你想让它可以用 gomod.io/yourname/awesome-lib 来导入。 $ gvu add gomod.io/yourname/awesome-lib https://github.com/yourorg/awesome-lib.git ✔ Route created successfully! ═══════════════════════════════════════════════════════════ ┃ Route ID: m_abc123 ┃ Vanity Path: gomod.io/yourname/awesome-lib ┃ Target Repo: https://github.com/yourorg/awesome-lib.git ┃ Quota: 1 / 5 used (4 slots remaining) ═══════════════════════════════════════════════════════════ 搞定了。 一个匿名账户会自动创建,无需注册、无需邮箱、无需信用卡。 ...

2026年7月12日 · Tony Bai

从 IP 地址到品牌域名:一个 Go 团队的 Vanity URL 之旅

“10.0.1.50 是什么服务?” 老张盯着屏幕上的报错信息,眉头紧锁。 build failed: cannot find module "10.0.1.50/user-service": module lookup disabled by GOPROXY=off 他转头问旁边的新人小李:“你知道 10.0.1.50 是什么服务吗?” 小李一脸茫然。他才入职第三天。 这是老张所在公司——一家中型互联网金融公司——的日常。平台组有 50 多个 Go 微服务,全部用内网 IP 地址作为 import path。没有人觉得有什么不对——直到上周服务器搬迁。 背景:IP 地址做 import path 的"原始时代" 两年前,平台组刚开始用 Go 的时候,一切都很简单。5 个微服务,代码放在自建 GitLab 上,import path 直接写 IP: import ( "10.0.1.50/user-service" "10.0.1.50/order-service" "10.0.1.51/payment-gateway" ) “能用就行”,当时没人多想。 但两年后,微服务从 5 个增长到了 50 多个。团队从 8 人扩张到 30 人。问题开始浮现: 问题一:IP 地址毫无可读性 // 这段代码你能看懂每个依赖是什么吗? import ( "10.0.1.50/user-service" // ✅ 还行 "10.0.1.51/pay-gw" // ❓ 支付网关? "10.0.1.52/cfg-svc" // ❓ 配置中心? "10.0.1.53/msg-queue" // ❓ 消息队列封装? ) 新人入职第一天就要记住"IP 地址 ↔ 服务名"的映射表。老张自己都经常搞混 10.0.1.52 和 10.0.1.53。 ...

2026年7月12日 · Tony Bai

为什么你的 Go 私有模块不该直接用 GitHub 路径

一个真实的噩梦 去年,我朋友老张的公司做了一个"很正常的决定"——把代码从 GitHub Enterprise 迁移到自建 GitLab。 听起来不复杂对吧?代码搬过去,CI 改改,完事了。 直到他们发现:公司 200 多个 Go 微服务的 import path 全是以 github.com/their-org/ 开头的。 迁移代码仓库只需要一个周末。但修改所有下游服务的 import path?3 个工程师干了两个星期。改完还要回归测试,又是一周。 老张事后跟我说了一句话,我至今记得: “如果当初用了 vanity URL,这一切只需要改一条 DNS 记录。” 这篇文章,就是写给还没踩这个坑的你。 四大隐患 隐患一:平台锁定——换 Git 服务 = 改所有 import Go 模块的 import path 就是它的身份标识。当你写: import "github.com/your-org/user-service" 你实际上是在说:这个模块永远住在 GitHub 上。 想迁移到 GitLab?改 import。想迁移到 Gitea?改 import。想迁移到自建 Gitea?还是改 import。 而且不只是改一个地方——是所有引用了这个模块的项目、所有下游服务、所有 go.mod 文件。对于中型团队,这可能意味着 数百个文件的批量修改 + 全量回归测试。 这不是假设。Go 社区里几乎每年都有公司因为 Git 平台迁移而经历 “import path 大逃亡”。 隐患二:IP 地址和内网信息裸奔 比 GitHub 锁定更危险的是自建 Git 服务器的场景。很多公司内部直接用 IP 地址或内网域名: ...

2026年7月12日 · Tony Bai