迁移 Git 仓库到新服务器并保留所有分支历史,最可靠的方式是使用git clone `--bare`配合git push `--mirror`。这种方式适合需要完整保留分支、标签和提交记录的场景,但操作前必须确保源仓库停止写入,防止数据不一致。
先说结论:用裸克隆加镜像推送能完整复制仓库的所有引用,但目标仓库必须为空且需提前处理分支保护策略。
- 适合:跨平台迁移、服务器更换、需要保留全部提交历史的场景
- 先看:目标仓库是否为空、是否有保护分支、源仓库是否有 LFS 文件
- 建议:迁移前锁定源仓库防止新提交、迁移后验证分支和标签数量、保留源仓库至少一周作为备份
核心命令
以下是可直接执行的迁移命令,替换其中的仓库地址即可。注意命令中不要包含多余符号:
git clone `--bare` https://old-server.com/group/project.git cd project.git git push `--mirror` https://new-server.com/group/project.git cd .. rm -rf project.git
如果源仓库使用了 Git LFS,迁移后需在新仓库执行git lfs fetch `--all`补全大文件对象。
迁移前准备
第一步:锁定源仓库
迁移过程中如果有新的提交推送到源仓库,会导致数据不一致。建议在维护窗口期操作,或在 GitLab/GitHub 设置中将源仓库设为“Read Only”,并通知团队暂停推送。
第二步:检查源仓库状态
记录源仓库的分支和标签数量,作为迁移后的验证依据:
git ls-remote `--heads` https://old-server.com/group/project.git | wc -l git ls-remote `--tags` https://old-server.com/group/project.git | wc -l
第三步:创建空的目标仓库
在新服务器上创建空白项目,不要初始化 README、.gitignore 或 license 文件。如果平台自动生成了初始文件,必须手动删除或重建项目,否则镜像推送会因 non-fast-forward 被拒绝。
详细操作步骤
第四步:执行裸克隆
git clone `--bare` https://old-server.com/group/project.git cd project.git
克隆完成后会生成以.git 结尾的目录,这是裸仓库,没有工作目录,不支持 git status 或 git checkout,只用来推送。
第五步:处理分支保护
如果目标仓库的 master 或 main 分支被设为受保护,推送会失败。需要临时关闭保护或让管理员用维护者权限执行推送。在 GitLab 中进入 Settings → Branches,勾选 Allow force pushes 或 Developers can push。
第六步:镜像推送
git push `--mirror` https://new-server.com/group/project.git
注意这里是两个短横线`--mirror`。推送完成后可以删除本地裸仓库。警告:`--mirror`会强制覆盖远程所有引用,如果本地裸仓库克隆不完整,会导致远程分支丢失,务必确认第一步克隆成功。
第七步:配置 LFS(如适用)
如果源仓库用了 Git LFS,`--mirror`不会自动迁移 LFS 对象,需在新仓库克隆后执行:
git clone https://new-server.com/group/project.git cd project git lfs fetch `--all` git lfs checkout
验证与回滚
验证方法
迁移完成后,对比源仓库和目标仓库的引用数量:
git ls-remote `--heads` https://old-server.com/group/project.git | wc -l git ls-remote `--heads` https://new-server.com/group/project.git | wc -l
两行输出应该一致。同样验证标签:
git ls-remote `--tags` https://old-server.com/group/project.git | wc -l git ls-remote `--tags` https://new-server.com/group/project.git | wc -l
还可以克隆新仓库到本地,检查git branch -a和git tag的输出是否与源仓库一致。
回滚方案
如果迁移后发现数据缺失或配置错误:
- 立即停止团队对新仓库的写入。
- 由于
`--mirror`已覆盖目标仓库,无法直接撤销。 - 若源仓库仍保留,重新执行迁移流程。
- 若源仓库已销毁,需从服务器备份恢复目标仓库数据。
- 建议验证无误前,源仓库至少保留一周只读状态。
常见报错与解决
目标仓库非空
报错:error: failed to push some refs to ... 或 rejected。
解决:如果新仓库已有初始提交,镜像推送会失败。必须先清空或重建项目,确保目标仓库完全空白。
保护分支拦截
报错:[remote rejected] master -> master (pre-receive hook declined)。
解决:这不是命令错误,是目标仓库的分支保护策略在拦截。需要临时关闭保护或用更高权限账号推送。
忘记进裸仓库目录
报错:fatal: 'origin' does not appear to be a git repository。
解决:克隆后直接在父目录下执行git push `--mirror`会报错,必须先cd project.git。
LFS 文件丢失
现象:大文件变成指针文件,无法读取内容。
解决:`--mirror`不会自动迁移 LFS 对象,需要在目标端手动补全,否则大文件会变成指针文件。
分支名不匹配
现象:原仓库主分支叫 main,但推送后只有 master。
解决:推送前确认分支名一致,`--mirror`会保留原分支名,不要手动指定git push origin master。
原文链接:https://www.zjcp.cc/ask/11192.html
