如何迁移多模块CVS仓库至Git并保留历史及分支结构?
我需要把旧CVS仓库迁移到Git并保留完整历史,当前要迁移的5个分支在CVS里得通过多次检出命令获取,比如:
branch1: cvs co -r branch1 sim Login SystemMonitor archiver branch2: cvs co -r branch2 par sim Login archiver cvs co -r branch2_redux editor branch3: cvs co -r GEN3 par sim SystemMonitor archiver cvs co -r GEN3_update1 tms editor cvs co -r GEN3Sim ...
CVS分支的特性导致迁移麻烦:
- 单个分支对应多个版本修订
- 一次分支检出要拉取不同模块
- 需要多次执行检出命令
而Git只能一次检出一个分支/标签,我要实现的目标:
- Git仓库里有branch1到branch5这5个分支
- 执行
git checkout branch3时,生成的文件集和CVS三次检出的完全一致,不影响项目构建 - 保留各分支的完整提交历史
- 不同分支里的相同提交SHA值一致,比如Login模块前75%的提交在所有分支里都相同
目前我已经用cvs2git完成了初步转换(耗时10小时),生成了branch1、branch2、branch2_redux、GEN3、GEN3_update1、GEN3Sim等分支,但不知道怎么把GEN3、GEN3_update1、GEN3Sim的历史和文件合并成单个branch3分支。转换命令如下:
cd ~ rsync -avz myusername@cvsserver:/path/to/cvsrepo/ ./cvsrepo_local_copy/ cvs2git --blobfile=~/git-blob.dat --dumpfile=~/git-dump.dat --username=cvs2git ~/cvsrepo_local_copy mkdir new_git_repo && cd new_git_repo && git init cat ~/git-{blob,dump}.dat | git fast-import
请问这个需求能实现吗?如果可以,具体怎么操作?
核心思路
利用Git的子树合并(subtree merge)或者精准提交筛选,把多个CVS来源分支的内容和历史整合到目标分支中,同时因为cvs2git已将相同CVS提交转换为一致的Git blob和commit SHA,只要基于已有提交操作,就能保证相同提交SHA一致。
具体操作步骤(以branch3为例)
1. 准备工作
确保当前Git仓库无未提交修改:
git status
2. 创建并切换到branch3分支
从所有分支的共同根提交(可通过git log --all --graph --oneline查找)创建分支:
git checkout -b branch3 <根提交SHA>
若不确定根提交,也可先基于GEN3分支创建:
git checkout -b branch3 GEN3
3. 合并GEN3_update1的模块与历史
GEN3_update1对应tms和editor模块,用子树合并方式将这两个模块的历史整合到branch3对应目录:
# 合并tms模块 git merge -s subtree -Xsubtree=tms GEN3_update1 --no-commit # 合并editor模块 git merge -s subtree -Xsubtree=editor GEN3_update1 --no-commit # 提交合并结果 git commit -m "Merge GEN3_update1's tms and editor modules into branch3"
4. 合并GEN3Sim的模块与历史
先查看GEN3Sim的目录结构,再针对性合并:
# 查看GEN3Sim的文件目录 git ls-tree -r GEN3Sim --name-only # 子树合并对应目录 git merge -s subtree -Xsubtree=<GEN3Sim对应目录> GEN3Sim --no-commit git commit -m "Merge GEN3Sim module into branch3"
5. 验证合并结果
切换到branch3,对比文件结构与CVS检出的是否一致:
git checkout branch3 ls -la # 与CVS检出的文件列表做对比
若有冲突,手动解决后提交即可。
6. 批量处理其他分支
对branch4、branch5重复上述步骤,将对应CVS分支的多模块版本合并到Git目标分支中。
备选方案:精准筛选提交(更灵活)
若子树合并遇问题,可手动筛选对应模块的提交:
# 筛选GEN3_update1中tms模块的提交并合并 git cherry-pick -Xsubtree=tms <GEN3_update1的起始提交SHA>..<GEN3_update1的结束提交SHA> # 筛选GEN3_update1中editor模块的提交并合并 git cherry-pick -Xsubtree=editor <GEN3_update1的起始提交SHA>..<GEN3_update1的结束提交SHA> # 筛选GEN3Sim对应模块的提交并合并 git cherry-pick -Xsubtree=<对应目录> <GEN3Sim的起始提交SHA>..<GEN3Sim的结束提交SHA>
这种方式需手动梳理各模块的提交历史,但能更精准控制合并内容。
关键注意事项
- 相同提交SHA一致性:cvs2git已将相同CVS提交转换为一致的Git commit SHA,基于已有提交操作会自动保留这一特性,满足需求4。
- 构建验证:每个分支合并完成后,务必对比Git分支与CVS检出的文件内容,确保不影响项目构建。
- 仓库备份:操作前备份当前Git仓库,避免误操作丢失历史。
内容的提问来源于stack exchange,提问作者jerkstorecalled

