先问你一句:你是真的需要“跨仓库提交迁移”,还是只是要把整个仓库换个地方托管?这两个问题看起来像,实际操作完全是两码事。
如果在代码仓库从单体拆分、服务独立交付、仓库合并、平台切换这类场景里待过,大概率会碰到一种需求:把仓库 A 的某一部分代码,连同它的完整提交历史,搬进仓库 B。很多人第一反应是“把代码复制过去再重新提交一次”,但这样做历史就没了;懂一点的会想到 git filter-branch,但用起来极其难受,还容易把仓库搞坏。今天这篇我就围绕 Git 的跨仓库提交迁移,把背后的对象模型、常用工具、梳理过的实操案例和一些踩坑经验一次性讲清楚。
这篇文章适合谁?想拆分 monorepo 的后端开发、要整理仓库边界的架构师,以及被老板要求“把支付模块历史搬到新仓库,但一条提交都不能少”的运维或全栈同学。文章核心不算短,但我尽量把每一步为什么这样做讲明白,而不是丢给你一堆跑不清楚的命令。
1. 先分清你的迁移层级:空仓库整体迁,还是让 Git 改写历史
跨仓库提交迁移的第一课不是学命令,而是判断需求属于哪一层。根据我的经验,至少三分之一的人根本不需要做“历史改写”,只是在托管平台间搬家而已。搞清楚这一点,能帮你省下几个小时,也避免在不该重写历史时把全部提交哈希搞乱。
1.1 目标仓库是空仓时,搬运即可,不用重写
如果旧仓库整体迁移到新地址,新仓库是空的,且你要保留分支、标签、全部提交,那直接搬运对象就行。Git 的提交对象本身是可移植的,commit、tree、blob 这些对象从一台服务器传到另一台,只要内容没被改动,哈希就不会变。很多人误以为“换仓库就等于 SHA 一定变”,其实不是,迁移只是对象被原封不动地搬走。
最简单的操作是 --mirror:
bash复制git clone --mirror git@git.example.com:old/legacy-project.git
cd legacy-project.git
git push --mirror git@git.example.com:new/legacy-project.git
用 mirror 而不是普通 clone 再 push,原因在于 mirror 会把远端所有引用,包括分支、tag、远程跟踪分支,都完整地复制下来。普通
