git clone --mirror 是迁移 Git 仓库最彻底、最可靠的方式,它会完整复制原仓库的所有引用(分支、标签、PR/MR 引用、notes 等),保证目标仓库与原仓库在 Git 对象层面完全一致。
以下是完整迁移流程,按场景分类:
一、核心原理
--mirror 等价于 --bare + 所有引用映射,它会:
- 克隆所有分支(包括远程追踪分支)
- 克隆所有标签
- 克隆所有 Git 引用(如
refs/pull/*/head、refs/notes/*等) - 保留完整的 reflog 和配置
二、标准迁移流程(通用)
步骤 1:镜像克隆原仓库
bash
# 创建裸镜像
git clone --mirror https://github.com/old-org/old-repo.git
cd old-repo.git
步骤 2:配置目标仓库地址
bash
# 设置目标仓库为新的 remote
git remote set-url origin https://github.com/new-org/new-repo.git
步骤 3:推送所有引用到目标仓库
bash
# 推送所有分支、标签、引用
git push --mirror
注意 :如果目标仓库已存在内容,
--mirror推送会强制覆盖,确保目标仓库为空或你确实要覆盖。
步骤 4:清理本地镜像(可选)
bash
cd ..
rm -rf old-repo.git
三、完整迁移清单(生产环境推荐)
1. 迁移前准备
bash
# 1. 确认原仓库完整性
git clone --mirror https://github.com/old-org/old-repo.git
cd old-repo.git
# 2. 检查仓库大小和引用数量
git count-objects -vH
git show-ref | wc -l
# 3. 验证所有分支和标签
git branch -a
git tag -l
# 4. 检查是否有 Git LFS 文件
git lfs ls-files 2>/dev/null || echo "No LFS detected"
2. 创建目标空仓库
在 GitHub/GitLab/Gitea 等平台创建一个空仓库(不要初始化 README、License 或 .gitignore)。
3. 执行迁移推送
bash
# 设置目标地址
git remote set-url origin https://github.com/new-org/new-repo.git
# 推送所有引用(分支 + 标签 + 其他 refs)
git push --mirror
# 如果目标仓库有保护规则限制强制推送,可能需要先临时关闭
4. 迁移 Git LFS(如有)
bash
# 如果原仓库使用了 Git LFS,需要单独迁移 LFS 对象
git lfs fetch --all
git lfs push --all origin
5. 验证迁移完整性
bash
# 在新机器上克隆目标仓库验证
cd /tmp
git clone https://github.com/new-org/new-repo.git
cd new-repo
# 对比提交数量
git rev-list --all --count
# 对比标签
git tag -l | sort
# 对比分支
git branch -a
四、不同平台迁移的特殊处理
GitHub → GitHub(含 PR 引用)
GitHub 的 Pull Request 引用存储在 refs/pull/*/head 和 refs/pull/*/merge。--mirror 会保留这些引用,但新 GitHub 仓库不会自动重建 PR 记录(PR 是平台元数据,不是 Git 数据)。
bash
# 镜像克隆会拉取 PR 引用,但新仓库中这些只是普通引用
git clone --mirror https://github.com/old-org/old-repo.git
git push --mirror https://github.com/new-org/new-repo.git
PR 历史、Issue、Wiki、Actions 记录等属于平台数据,需通过 API 或平台自带迁移工具迁移。
GitLab → GitLab(含 MR 引用)
GitLab 的 MR 引用在 refs/merge-requests/*。同样,--mirror 会保留引用但不会自动重建 MR 记录。
自建 Git 服务器 → 新服务器
bash
# 直接在服务器上操作(更快)
cd /var/git/old-repo.git
git push --mirror ssh://new-server/var/git/new-repo.git
五、高级:保留原仓库所有配置
bash
git clone --mirror https://github.com/old-org/old-repo.git
cd old-repo.git
# 查看原仓库 remote 配置
cat config
# 修改 origin URL 指向新仓库
git remote set-url origin https://github.com/new-org/new-repo.git
# 如果需要保留其他 remote(如 upstream)
git remote -v
# 推送所有引用
git push --mirror
六、常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
! [remote rejected] ... |
目标仓库有保护分支 | 临时关闭分支保护 |
! [rejected] ... (fetch first) |
目标仓库非空 | 创建空仓库或先清空 |
| LFS 文件缺失 | 未迁移 LFS 对象 | 执行 git lfs push --all |
| PR/MR 历史丢失 | PR 是平台数据 | 使用平台 API 迁移 |
| 仓库体积异常大 | 包含大量垃圾对象 | 原仓库先 git gc --aggressive |
七、一键迁移脚本
bash
#!/bin/bash
set -e
OLD_URL="https://github.com/old-org/old-repo.git"
NEW_URL="https://github.com/new-org/new-repo.git"
REPO_NAME="old-repo"
# 1. 镜像克隆
git clone --mirror "$OLD_URL" "${REPO_NAME}.git"
cd "${REPO_NAME}.git"
# 2. 检查 LFS
if git lfs ls-files 2>/dev/null | head -1; then
echo "检测到 Git LFS,正在迁移..."
git lfs fetch --all
fi
# 3. 设置新地址并推送
git remote set-url origin "$NEW_URL"
git push --mirror
# 4. 推送 LFS(如有)
if command -v git-lfs &> /dev/null && [ -d "lfs" ]; then
git lfs push --all origin
fi
# 5. 清理
cd ..
rm -rf "${REPO_NAME}.git"
echo "迁移完成: $NEW_URL"
八、迁移后必做检查
- 提交历史 :
git log --oneline --all --graph | head -20 - 标签完整性 :
git tag -l | wc -l对比原仓库 - 分支完整性 :
git branch -a - 大文件/LFS:检查仓库体积是否合理
- CI/CD 配置:更新 webhook、部署密钥、CI 变量
- Issue/PR 链接 :旧仓库中的
#123链接会失效,需平台级迁移