2026 年 8 月 17 日晚约 9:40,GitHub 开始大面积宕机,超过 7 小时后才完全恢复。网站、API、Pull Request、Actions、Webhooks、Issues、Git Operations 和 Copilot 几乎同时受到影响。对研发团队来说,这不是简单的“网页打不开”,而是代码托管、评审、构建、发布和协作被同一个故障域一起拖住。
真正有能力替代 GitHub,并不等于部署一个能显示仓库列表的 Git 服务。更重要的问题是:当 GitHub 完全不可用时,你的备用平台、镜像任务、身份系统和发布流程还能不能独立工作?
一个 GitHub 账号背后,可能藏着整条研发链路
现代团队通常不只在 GitHub 上保存 Git 对象。围绕仓库,还会逐渐形成一组隐性依赖:
- Pull Request 承载代码评审和合并规则;
- Actions 负责测试、构建、制品签名和部署;
- Webhooks 驱动内部机器人、发布平台和安全扫描;
- Issues、Projects 或评论保存需求决策和故障记录;
- API 被脚本、CLI、仪表盘和权限同步任务调用;
- Release、Packages 或缓存保存可部署制品;
- GitHub 身份可能被其他系统当作唯一登录入口。
这次故障覆盖几乎全部核心功能,说明只准备一份仓库副本远远不够。即使备用 Git 服务里有最新代码,如果 CI 配置仍要调用 GitHub API、密钥只保存在 Actions、部署入口只能由 GitHub Webhook 触发,团队仍然无法发布。
因此,评估替代方案时应该按能力拆分,而不是只比较仓库页面:
| 能力 | 需要确认的问题 |
|---|---|
| Git 数据 | 分支、标签、Git LFS 对象是否完整同步? |
| 评审 | PR、评论、审批记录和保护规则能否迁移? |
| 自动化 | Runner、密钥、缓存和触发器是否独立? |
| 制品 | 镜像、包和 Release 附件是否有第二存储位置? |
| 身份 | GitHub 登录失效后,管理员还能否进入备用系统? |
| 运维 | DNS、证书、数据库、对象存储和备份是否由团队掌控? |
镜像必须在 GitHub 之外运行
最常见的错误,是用 GitHub Actions 把 GitHub 仓库同步到备用平台。平时这套方案看起来没有问题,但源平台发生大面积故障时,负责同步的执行器也可能一起消失。
可以这样实践:在独立虚拟机、自建 Runner 或另一家云平台上运行裸仓库镜像任务。下面的脚本会把源仓库的所有 Git 引用同步到备用远端。运行前将两个环境变量替换为实际地址,并为执行机器配置对应的 SSH 密钥。
#!/usr/bin/env bash
set -euo pipefail
: "${SOURCE_REPO:?set SOURCE_REPO first}"
: "${MIRROR_REPO:?set MIRROR_REPO first}"
workdir="$(mktemp -d)"
trap 'rm -rf "$workdir"' EXIT
git clone --mirror "$SOURCE_REPO" "$workdir/repository.git"
git -C "$workdir/repository.git" push --mirror "$MIRROR_REPO"
echo "Mirror completed at $(date -u +%FT%TZ)"
例如:
chmod +x mirror-repo.sh
SOURCE_REPO=git@github.com:acme/payments.git \
MIRROR_REPO=git@git.example.com:acme/payments.git \
./mirror-repo.sh
git push --mirror 会同步并删除目标端引用,权限配置错误时可能造成破坏,因此应给镜像仓库设置专用凭据,并先在测试仓库验证。它也不会迁移 Issues、PR、Actions 密钥、LFS 对象或包仓库;这些数据需要分别通过 API 导出、数据库备份或对象存储复制来处理。
对于仍在频繁开发的关键仓库,还可以让开发者的一次 git push origin 同时写入两个平台:
git remote set-url --delete --all origin git@github.com:acme/payments.git 2>/dev/null || true
git remote set-url --add --push origin git@github.com:acme/payments.git
git remote set-url --add --push origin git@git.example.com:acme/payments.git
git remote set-url origin git@github.com:acme/payments.git
git remote get-url --all --push origin
git push origin main --follow-tags
双写能缩短镜像延迟,但也引入部分成功问题:第一个远端写入成功、第二个失败时,两个平台会短暂分叉。团队需要监控两端提交 SHA,而不能只看命令的最终退出状态。
备用平台不能只是“冷仓库”
仅在事故发生后才第一次启动替代平台,往往会暴露证书过期、备份不可恢复、管理员无法登录等问题。一个更可靠的做法,是让备用平台持续承担少量真实流量,例如定期构建、只读检出或内部工具仓库。
如果团队希望验证自托管方案,可以这样搭建一个最小实验环境。以下 Compose 文件只是演练样例,假设使用 Forgejo 和 PostgreSQL;投入生产前还需要补充反向代理、TLS、对象存储、监控、异地备份和升级流程。
services:
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_DB: forgejo
POSTGRES_USER: forgejo
POSTGRES_PASSWORD: change-this-password
volumes:
- db-data:/var/lib/postgresql/data
forgejo:
image: codeberg.org/forgejo/forgejo:11
restart: unless-stopped
depends_on:
- db
environment:
FORGEJO__database__DB_TYPE: postgres
FORGEJO__database__HOST: db:5432
FORGEJO__database__NAME: forgejo
FORGEJO__database__USER: forgejo
FORGEJO__database__PASSWD: change-this-password
ports:
- "3000:3000"
- "2222:22"
volumes:
- forgejo-data:/data
volumes:
db-data:
forgejo-data:
启动后访问 http://localhost:3000 完成初始化:
docker compose up -d
docker compose ps
docker compose logs --tail=100 forgejo
这个环境证明的只是“服务可以启动”,并不证明灾难恢复成立。演练至少要覆盖:从备份恢复数据库、重新挂载仓库存储、切换 Git 远端、执行构建、访问制品,以及在 GitHub 身份不可用时用本地管理员登录。
真正的切换单位是工作流
平台替换很少能一次完成。更稳妥的方式,是选一个非核心仓库做完整切换,把从提交到部署的路径全部走通:
- 将 Git 仓库和 LFS 数据同步到第二平台。
- 把 CI 构建放到不依赖 GitHub 控制面的执行环境。
- 将镜像和包推送到独立制品仓库,并验证拉取权限。
- 为 Webhook 消费方准备手动重放或轮询入口。
- 导出关键 Issues、PR 审批记录和发布说明。
- 准备不依赖 GitHub OAuth 的紧急管理员账号。
- 模拟 GitHub 不可访问至少两小时,完成一次构建与发布。
这里的取舍很明确:双平台会增加凭据管理、权限同步、成本和运维复杂度;完全自托管又意味着团队必须承担升级、安全补丁、数据库和存储可靠性。不是每个仓库都值得建设同等级别的冗余,但发布系统、基础设施代码和关键业务服务通常应该优先处理。
判断是否摆脱单点依赖
不要用“我们已经部署了另一个 Git 服务”作为完成标准。更有效的验收问题是:关闭所有通往 GitHub 的网络访问后,团队能否找到代码、提交修复、完成评审、运行测试、生成制品并发布到生产?
只要其中任何一步仍要求 GitHub API、Actions、OAuth 或某个仅存于 GitHub 的密钥,替代方案就还没有真正独立。GitHub 的长时间宕机提醒团队,平台冗余不是多放一份仓库,而是让关键研发工作流拥有第二条可验证、可操作的路径。