GitHub 又一次出现严重宕机,开发者熟悉的讨论也随之重启:有没有值得迁移的替代方案?这类问题表面上是在比较 GitLab、Gitea 或其他平台,实际是在追问一个更现实的工程问题:代码、议题、构建流水线和发布权限,是否都被绑定在同一个外部服务上?
Hacker News 的讨论之所以有价值,是因为评论者没有把迁移简单描述成“换一个网站”。自托管 GitLab 是传统答案,但它也意味着数据库、对象存储、升级、备份、监控和故障恢复都要由团队负责。替代平台真正的差异,不只在功能列表,还在于团队愿意承担多少运维责任。
自托管不是免费的午餐
GitLab 的吸引力很直接:功能完整,覆盖代码托管、合并请求、权限控制、CI/CD 和项目管理。对于已经使用这些能力的团队,迁移到自托管 GitLab 通常比重建整个研发流程更容易。
但“自己部署”会把平台可靠性问题转移给你。过去由 GitHub 负责的事情,现在可能变成团队的值班事项:
- 数据库和 Redis 是否有可恢复的备份?
- Git 仓库、附件、构建产物和容器镜像是否分开保存?
- 升级失败时能否快速回滚?
- 身份认证服务故障时,管理员还能否登录?
- CI Runner 是否和代码平台部署在同一故障域?
- 发生误删或勒索事件后,备份是否真的能恢复?
因此,自托管 GitLab 的成本不应只按服务器费用计算。更准确的公式是:基础设施费用,加上维护时间、故障响应时间、升级风险和恢复演练成本。
如果团队没有专门的运维能力,选择托管版 GitLab 或其他托管平台,可能比直接购买服务器更稳妥。控制权和可靠性之间没有固定答案,关键在于谁负责把服务恢复起来。
替代方案要按责任边界比较
社区讨论中的不同阵营,本质上是在选择不同的责任边界。
继续使用 GitHub,但降低单点依赖
这通常是改动最小的做法。团队保留 GitHub 的协作体验,同时把关键仓库、发布包和文档定期复制到第二个位置。这样不能消除 GitHub 宕机期间的协作影响,但可以降低代码丢失、账号受限或迁移时没有数据可用的风险。
这种方式适合已经深度依赖 GitHub Actions、Issues、Pull Requests 和生态集成的团队。它的缺点是需要自己维护同步任务,并且第二个平台的权限和访问流程也必须定期验证。
托管版替代平台
托管版 GitLab、Bitbucket 或其他代码托管服务可以减少数据库、升级和备份的运维负担。选择时应重点检查这些能力,而不是只比较界面:
- 是否支持完整 Git 镜像和批量导出?
- CI/CD Runner 能否运行在自己的网络中?
- 是否支持 SAML、OIDC、SCIM 或现有目录服务?
- 项目附件、Release、Packages 和容器镜像如何迁移?
- 服务中断时是否有清晰的状态页、备份策略和数据导出机制?
托管并不等于没有风险。服务商仍可能宕机、调整价格、改变产品方向,或者限制某些高级功能。托管方案减少的是日常运维,不是业务连续性设计。
自托管 GitLab、Gitea 或 Forgejo
自托管平台适合需要更强控制权、内网部署或数据主权的团队。GitLab 功能更丰富,但资源占用和运维复杂度通常也更高。Gitea、Forgejo 这类轻量平台可以覆盖核心 Git 工作流,适合小团队、内网项目或希望降低平台维护成本的场景。
轻量不代表无需管理。你仍然需要处理备份、TLS、单点登录、Runner、升级和监控。平台越简单,迁移后的功能重建工作可能越多,例如议题、代码审查、制品仓库和自动化流水线不能只靠复制 Git 对象解决。
先做可恢复的镜像,再讨论迁移
不要在事故发生时才第一次尝试导出仓库。下面的脚本可以把一个仓库同步为完整的裸镜像,并推送到备用远端。运行前请把环境变量替换成实际地址,并确认备用平台已经创建了同名空仓库。
#!/usr/bin/env bash
set -Eeuo pipefail
SOURCE_URL="${SOURCE_URL:?set SOURCE_URL to the primary repository}"
BACKUP_URL="${BACKUP_URL:?set BACKUP_URL to the backup repository}"
WORKDIR="$(mktemp -d)"
trap 'rm -rf "$WORKDIR"' EXIT
repo_dir="$WORKDIR/repository.git"
git clone --mirror "$SOURCE_URL" "$repo_dir"
git -C "$repo_dir" remote set-url --push origin "$BACKUP_URL"
git -C "$repo_dir" push --mirror
echo "Mirror completed: $BACKUP_URL"
可以这样运行:
export SOURCE_URL="git@github.com:example/service.git"
export BACKUP_URL="git@git.example.net:backup/service.git"
./mirror-repository.sh
这个例子只同步 Git 仓库中的引用和对象。它不会自动迁移以下内容:
- Issues、Pull Requests 及评论
- Wiki、项目看板和团队权限
- GitHub Actions 或其他 CI 配置中的密钥
- Release 附件、Packages、容器镜像
- Webhook、部署环境和外部集成
所以,镜像任务应当被视为“代码可用性保护”,而不是完整的平台迁移方案。对于重要项目,可以把仓库镜像、平台元数据导出和制品备份拆成不同任务,并给每项任务设置最近成功时间和告警。
一份更务实的退路清单
选择替代方案前,可以用一周时间完成一次小规模演练:
- 选一个非核心仓库,导出代码、议题、制品和权限清单。
- 在候选平台创建项目,验证 SSH、HTTPS、合并请求和 CI Runner。
- 从备用平台重新克隆代码,并执行一次完整构建和发布。
- 暂停主平台访问,模拟 DNS、身份认证或平台不可用的情况。
- 记录恢复步骤、负责人、凭据位置和预计恢复时间。
- 根据恢复结果决定采用双写、定期镜像、托管迁移还是完全自托管。
迁移决策可以用两个问题快速筛选:团队能否长期承担平台运维?业务能否接受托管服务的控制边界?如果两个答案都不明确,先建立可验证的异地备份和恢复流程,通常比立刻迁移全部项目更稳。
GitHub 宕机提醒我们的不是“某个平台一定不可靠”,而是外部服务本身就是依赖。真正成熟的做法不是盲目寻找一个永远在线的替代品,而是明确故障边界,保留可用副本,并定期证明这些副本真的能够支撑开发和发布。