将代码仓库从SVN迁移至Git,并保留所有提交记录

更新日期: 2022-02-07阅读: 1.5k标签: svn

最近接手一个非常老的项目,因为使用SVN进行控制,而现在大部分都已经使用Git进行版本控制,所以就想迁移到Git,Git的优点自然是不用在这里说了,必经是当前公认最好用的。

因为项目比较老,代码比较多,提交多达3w多次,同时svn还有几十个分支和标签,这些历史记录丢失将对今后追溯debug造成很多麻烦,所以关键是如何才能保留所有的这些提交记录、分支、标签。



1. 提取开发者信息

为了实现正确的数据迁移,我们要对开发者信息,即提交作者的信息做一个映射,这就需要先生成一个用户对应关系的文件,格式如下:

JefferyWang = JefferyWang <jefferywang@example.com>

为了能够快速从svn内提取作者信息,可以使用下面的脚本,来快速提取在svn内有过提交的用户名,然后再做映射的处理,生成上面格式的文件即可:

svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2}' | sort -u

当然如果你们所有作者的邮箱后缀都是一样的,可以使用下面这段脚本:

svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2"@example.com>"}' | sort -u > authors.txt


2. 仓库转换

标准的svn文件布局


如果你的svn仓库是标准的目录结构,即只包含 /trunk , /branches , tags 几个目录的结构,那么可以直接在运行命令的时候加上参数 --stdlayout 。

命令格式为 git svn clone --stdlayout --authors-file=authors.txt <svn-repo>/<project> <git-repo-name> ,下面是一个示例:

# git v1.x
git svn clone --stdlayout --authors-file=authors.txt http://svn.example.com/test_rep/demo_proj demo

# git v2.x
git svn clone --prefix="" --stdlayout --authors-file=authors.txt http://svn.example.com/test_rep/demo_proj demo

非标准的svn文件布局


针对非标准的目录结构,我们分别做显式指定参数 --trunk , --branches , --tags 。

# git v1.x
git svn clone --trunk=/trunk --branches=/branches --branches=/bugfixes --tags=/tags --authors-file=authors.txt http://svn.example.com/test_rep/demo_proj demo

# git v2.x
git svn clone --prefix="" --trunk=/trunk --branches=/branches --branches=/bugfixes --tags=/tags --authors-file=authors.txt http://svn.example.com/test_rep/demo_proj demo

大仓库的转换策略

有些svn仓库可能非常大,而转换过程是个非常漫长的过程,这个也取决于机器性能。因此,如果你不在乎老的一些历史记录的话,那么你可以只保留部分提交历史,来加速转换的过程。

命令格式: git svn clone -r${REVNUMBER}:HEAD --stdlayout --authors-file=authors.txt <svn-repo>/<project> <git-repo-name>

git svn clone -r52733:HEAD --stdlayout --authors-file=authors.txt https://svn.waterstrong.com/demo demo


3. 仓库清理

这里查看我们的仓库,就发现转换工作基本已经完毕了,如果你只关注trunk和master分支,那么可以不用在乎这一部分,直接跳到下一节即可。这一步主要是将分支和标签进行本地化。

git svn clone 操作并不会将svn的分支和标签导入到新的git仓库里面,并且在本地分支中也找不到svn的分支和标签。转换后,其实是把svn的分支和标签导入为git的远程分支和标签了,如下面示意图所示:


这个策略主要是为了svn和git双向同步服务的,但是我们切换为git后,应该大部分都会禁止在svn再进行提交,所以我们就需要对这些进行一下清理。


第一种方法:

Atlassian提供了一个工具 svn-migration-scripts.jar ,可以进行清理。

下载地址:svn-migration-scripts.jar 下载

使用方法:

java -Dfile.encoding=utf-8 -jar ~/svn-migration-scripts.jar clean-git
--force

第二种方法:

只需要执行两个命令:

# 标签本地化
for t in $(git for-each-ref --format='%(refname:short)' refs/remotes/tags); do git tag ${t/tags\//} $t && git branch -D -r $t; done

# 分支本地化
for b in $(git for-each-ref --format='%(refname:short)' refs/remotes); do git branch $b refs/remotes/$b && git branch -D -r $b; done

当然,如果你使用git v2.x版本,你可能通过网上查询的资料,在执行 git svn clone 的时候没有加参数 --prefix="" ,那么执行之后会在远程的分支名称前面添加 origin/ ,直接按照上面的脚本处理会有问题,你可以按照下面的命令进行处理

# 标签本地化
for t in $(git for-each-ref --format='%(refname:short)' refs/remotes | grep "origin/tags"); do git tag ${t/origin\/tags\//} $t && git branch -D -r $t; done

# 分支本地化
for b in $(git for-each-ref --format='%(refname:short)' refs/remotes); do git branch ${b/origin\//} refs/remotes/$b && git branch -D -r $b; done


4. 收尾工作

添加远程仓库地址

git remote add origin JefferyWang@github.com:test/demo.git

将本地分支和标签推送到远程仓库

git push origin --all

git push origin --tags

原文 https://blog.wangjunfeng.com/post/svn2git/


链接: https://fly63.com/article/detial/11093

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!