迁移指南 · 来自 GitHub
从 GitHub 迁移到 SIAX Git 和 CI
GitHub 不是糟糕的工具,而且它很少是促使任何人迁移的原因。原因通常有三个:随团队增长而水涨船高的按开发者计费许可成本、难以预测的 CI 分钟数,以及代码和构建链都处于美国司法管辖之下。对面向公共部门或有监管要求的客户销售的公司来说,最后一个论点往往起决定性作用。
我们的 Git 和 CI 是自托管的 Gitea,配 Actions 兼容的 runner,全部位于欧盟。Git 协议是相同的,因此 clone、remote 和工具都能原样工作,工作流语法也基本与 GitHub Actions 相同。价格为 10 个用户 199 克朗/月,相比之下 GitHub 是按开发者许可加上可变的 CI 成本。
坦诚的提醒:Actions 兼容性很好,但并非完全一致。工作流文件通常可以直接搬过去,但个别的 marketplace actions 需要替换,而且 GitHub 生态的某些部分,比如 Codespaces、Advanced Security、Pages、与云提供商的 OIDC 联合,没有对应物。本指南把时间放在真正费力之处:用在流水线上,而不是代码上。
操作步骤
- 1
盘点仓库、工作流和集成
列出所有仓库,包括最新提交、大小,以及是否使用 LFS。逐个过一遍每个活跃工作流,记录它使用了哪些 actions、读取了哪些密钥以及部署到什么。同时记录 Git 之外的一切:GitHub Apps、webhooks、分支保护、code owners 和必需的 status checks。这份清单才是你真正的规格,而不是仓库列表。
- 2
设置组织、用户和权限
在我们这里创建组织,并按照与 GitHub 相同的权限级别设置团队。如果你有身份提供者,就通过 OIDC 把登录连接到它,否则使用强制双因素认证的本地账户。立即设置分支保护,推迟很容易,而它要到有人往 main 推送时你才会注意到。
- 3
镜像仓库并迁移 issue 历史
迁移工具通过 GitHub API、用个人访问令牌拉取仓库、tags、releases、wiki、issues 和 pull requests。先对一个中等规模的仓库做一次测试迁移,检查结果后再迁其余的。LFS 对象和 ghcr.io 中的容器镜像要单独迁移,不在同一批里。
- 4
迁移密钥,并同时轮换它们
密钥无法从 GitHub 里读出来,所以无论如何都得重新设置。利用这一点:把每个密钥作为迁移的一部分轮换,而不是粘贴相同的值。把多个仓库共享的密钥放到组织级,并记录哪个流水线需要哪些。
- 5
重写工作流,换掉那些带不过来的 actions
.gitea/workflows 的语法与 GitHub Actions 基本一致,因此文件通常可以直接照搬。然后逐个测试每个工作流:checkout、setup-node、cache 这类常见 actions 正常工作,而调用 GitHub 自己的 API、使用 OIDC 联合、或假定 GitHub runner 镜像的 actions 则不行。显式锁定版本,并用纯 shell 步骤替换失败的。这一步预计会占用最多时间。
- 6
两套系统并行运行,直到结果一致
把 GitHub 保留为镜像,在某个时段同时推送到两个 remote。在同一 commit 上逐行比较构建日志,差异通常来自 runner 镜像中预装的工具,而不是你的代码。只有当连续十到十五次运行的产出都一致时,才可以把我们的 CI 设为必需的 status check。
- 7
重定向部署目标和 webhooks,然后归档 GitHub
更新部署密钥、容器仓库,以及所有指向 github.com 的 webhook。如果流水线部署到我们的 App Hosting(从 99 克朗/月起),一个部署密钥加一个 webhook 就够了。把 GitHub 仓库设置为归档、只读模式,而不是删除,否则文档和 issues 中的旧永久链接会失效。至少保留一个季度。
真正棘手的地方
- Marketplace actions 并不总能原样运行。只运行命令的没问题;调用 GitHub 的 REST 或 GraphQL API、对 AWS 或 GCP 做 OIDC 联合、或依赖 GitHub runner 镜像的则不行。逐个测试每个 action,锁定版本,并预计要用 shell 步骤替换掉几个。
- Runner 镜像不是 GitHub 的 ubuntu-latest。假定某个工具已经安装好的流水线会失败,而且通常是构建深处一个含义不明的错误。与其依赖镜像,不如在工作流中显式安装依赖。
- 与云提供商的 OIDC 联合会消失。凡是经由 GitHub 的身份提供者获取 AWS 或 GCP 临时凭据的工作流,都必须改用长期密钥或其他机制。这是一项安全回退,应该被有意识地处理,而不是事后才发觉。
- GitHub 的某些部分没有对应物:Codespaces、Advanced Security 和代码扫描、Pages、Discussions,以及组织级 rulesets。如果其中任何一项对业务至关重要,答案不是全盘迁移,而是迁移能迁移的,并为其余的买单。
- Issue 历史会以文本形式带过来,但 pull request 的评审讨论串、status-check 历史和指向 github.com 的永久链接不会完整转移。旧文档中的链接仍然指向那里,这正是 GitHub 仓库应该归档而非删除的原因。
成本示例
GitHub Team 上一个十人团队,许可费用大约每月 40 USD,约合 450 克朗,再加上超出包含额度的 CI 分钟成本。对一个活跃且并行构建很多的 monorepo 来说,CI 这一项往往比许可还大。价格和包含的额度会不断变化,请核对当前价表。我们这边对应的方案:Git 和 CI,10 个用户 199 克朗/月。需要重度并行构建?我们会在从 890 克朗/月起的专用服务器上为你配置一台专属 runner,这仍然是可预测的,而不是可变的。
常见问题
- 我们的 GitHub Actions 工作流能原样运行吗?
- 文件通常可以不加修改地复制,语法是相同的。actions 则是另一回事:最常见的那几个能用,但对话 GitHub API 或使用 OIDC 联合的不行。预计要逐一测试和调整每个工作流,而不是盲目搬运。
- issues 和 pull requests 会一起迁移吗?
- 会。迁移工具通过 GitHub API 拉取 issues、pull requests、releases、tags 和 wiki。评审讨论串和 status-check 历史不会完全一致。先在单个仓库上做一次测试迁移,看看结果再决定全量迁移。
- 我们能并行保留 GitHub 吗?
- 可以,而且我们建议在过渡期这么做。Git 是分布式的,向两个 remote 推送只是一行配置。很多团队会把 GitHub 永久保留为公共仓库的只读镜像。
- ghcr.io 里的容器镜像怎么办?
- 它们单独迁移。我们的包仓库讲的是同一种 OCI 协议,所以只是重新打标签再推送,外加更新 Kubernetes manifests、compose 文件和部署脚本中的所有 pull 引用。别忘了镜像拉取密钥。
- 你们有 ISO 27001 或 SOC 2 吗?
- 没有。我们既没有 ISO 27001、SOC 2,也没有 PCI-DSS。我们有的是 GDPR 合规(所有数据在欧盟境内)、一路开源到底,这样你能审计实际运行的是什么,以及任何时刻都允许你导出数据的合同。如果你的采购流程有认证要求,你应该在项目开始之前就知道这一点。
- 如果行不通,我们怎么迁出去?
- 克隆这些仓库,它们包含完整历史。issues 和 pull requests 通过 API 导出,工作流文件也已经在仓库里了。出来和进去同一条路,这正是开放格式的意义。
