这里就不再赘述关于SVN与Git的区别以及为什么要迁移源码到Git了,毕竟Git是当前的主流DVCS了,而且已经公认地非常好用,如果你还在使用SVN的话该考虑换了,是时候迁移那些遗留代码了,有兴趣可以参阅 Why Git 和 Perforce to Git 了解更多。
通常来说,在项目开发过程中,难免会遇到一些老项目代码正被SVN管理着,但基于当下诸多原因,或是扩展开发,或是战略转移,或是为了更好地开发体验,需要将这些在维护的遗留项目源码迁移为Git管理。
那如何有效地迁移源码?并且如何保留提交记录、分支记录以及开发成员等信息呢?笔者前一段时间就经历了这样的迁移工作,还是有必要分享一下,也算是一种总结了。
准备工作
迁移SVN源码到Git仓库的方法肯定不是暴力地将代码Copy再Paste到Git仓库,也不是直接在项目下git init初始化仓库的,而是应该使用git svn命令操作实现迁移工作。那git-svn命令如何使用?有哪些注意事项呢?
首先,在正式开始迁移项目之前,需要做一些准备工作:
- 准备一台安装有最新Git环境的磁盘容量足的电脑
- 经获知Git仓库的远程地址,无论是自己创建还是团队提供
- 确保对Git远程仓库有读写权限,无论通过用户名密码还是SSH访问都行
- 准备一份开发者的SVN用户名到Git全名 邮件的映射关系列表文件authors.txt,格式为:
loginname = Username <user@example.com>
由于SVN对每次提交只记录开发者的用户名,而Git存储其全名和邮件地址,这意味着需要对开发者信息进行映射转换,在准备authors.txt
文件时,可以到团队系统数据库直接查询开发者登录名、用户名和邮件地址并拼接成指定的格式,或者可下载Atlassian的工具包svn-migration-scripts.jar,通过命令拉取SVN仓库的用户并生成对应的开发者信息映射文件,需要Java运行时环境支持:
java -jar svn-migration-scripts.jar authors https://svn.example.com > authors.txt
转换仓库
准备工作完成后可以开始实施转移仓库了,应该注意的是,在转移SVN项目时需要根据是否是标准的SVN文件布局来确定命令行的参数。(注:以下所有示意图均来自Atlassian)
标准的SVN文件布局
如果SVN仓库使用标准的了 /trunk
,/branches
和/tags
的目录结构,就可在运行命令时加上参数--stdlayout
。
git svn clone --stdlayout --authors-file=authors.txt <svn-repo>/<project> <git-repo-name>
git svn clone --stdlayout --authors-file=authors.txt https://svn.waterstrong.com/demo demo
非标准的的 SVN 文件布局
如果SVN仓库是非标准的目录布局,那就需要分别显示指定参数 --trunk, --branches, --tags
。
git svn clone --trunk=/trunk --branches=/branches --branches=/bugfixes --tags=/tags --authors-file=authors.txt <svn-repo>/<project> <git-repo-name>
Authors 文件的使用
--authors-file
:在之前的命令中已经提到需要添加参数--authors-file=<filename>
读取开发者信息映射文件,文件内容格式为loginname = Username <user@example.com>
,但如果在文件中不存SVN某个用户名的对应关系,那么git svn操作会被自动中止,因此,必须在authors.txt
文件中添加丢失的用户对应关系,然后重新运行git svn命令即可。配置其git config时的key为svn.authorsfile。--authors-prog
:但如果希望在使用authors.txt文件时,即使某个SVN用户名对应关系不存在,命令也可以执行成功并自动使用默认值,可以使用该参数—authors-prog= 。配置其git config时的key为svn.authorsProg,另外,可以在Tutorials - Synchronize 中找到关于authors文件的更多使用信息。
大仓库的转换策略
特别注意的是,当SVN仓库非常非常大时,据官方统计数据,若转换拥有33000个提交的400MB大小的仓库需要花12个小时来完成转换。因此,在这种情况下,可以选择找一台机器,运行命令后就不管了直到完成转换为止,或者是选择放弃保存非常老的提交历史记录,这样可以加速转换过程,如果转换时只保留部分提交历史的话可以使用以下命令:
代码语言:javascript复制git svn clone -r${REVNUMBER}:HEAD --stdlayout --authors-file=authors.txt <svn-repo>/<project> <git-repo-name>
git svn clone -r19698:HEAD --stdlayout --authors-file=authors.txt https://svn.waterstrong.com/demo demo
清理仓库
至此,SVN到Git的转换工作接近尾声,如果只是关注 trunk 和 master 主分支,那么可以不用在意清理仓库这一部分的内容了,可以直接跳过进入下一节,如果需要清理并将分支和标签进行本地化,则可以关注一下本节内容。
对于SVN的分支和标签,转换操作是不会将其导入到新的Git仓库中,而且在Git分支中也找不到SVN的分支branch,也找不到对应的标签tag,不过可以使用命令git branch -r
可以查看到所有SVN的分支和标签,这是因为在使用git svn clone
命令时会将SVN的分支和标签导入为Git的远程分支和标签,如下示意图所示。
该策略主要是为SVN与Git双向同步服务的,但通常SVN单向转换到Git后都会直接使用Git了,并且会禁止SVN提交了,所以还是会对分支和标签内容进行清理以转换为Git的分支和标签。可以使用Atlassian提供的脚本工具快速实现对仓库分支和标签的清理工作:
代码语言:javascript复制java -Dfile.encoding=utf-8 -jar svn-migration-scripts.jar clean-git --force
将SVN分支和标签转换Git的本地分支和标签后结构如下图所示:
收尾工作
完成以上步骤后,迁移工作基本完成,接下来需要根据项目代码性质、团队约定等情况做一些收尾工作,需要具体情况具体分析。这里会以一个Gradle构建的Java项目(IDE使用IntelliJ)为例介绍从SVN迁移到Git后的收尾工作:
- 查看Git远程地址是否已经配置了,如果还没有配置,可以使用命令git remote命令配置origin,比较常用的两组命令为:
git remote add origin xxx # 添加新的远程地址
git remote set-url origin xxx # 修改origin的远程地址
- 使用命令
git update-index
配置构建工具的执行权限,如果有其他执行脚本也需要配置相应权限信息:
git update-index --chmod= x gradlew
git update-index --chmod= x gradlew.bat
git update-index --chmod= x xxx.sh
- 添加
.gitignore
文件,根据不同的项目写入要忽略的文件,如Java项目ignore文件会包括:
/out
/build
/.idea
.gradle
.DS_Store
*.iml
*.ipr
*.iws
- 更新IDE的vcs配置为Git而非Svn,在build.gradle文件修改vcs配置:
idea.project.vcs = "Git"
- 最后上传到Repo,并根据团队内部的约定设置相应的权限,通常会有一个检查清单,比如:
- 设置分支模型
- 添加分支权限
- 限定PR合并权限
- 配置SVN提交通知
- 变更CI拉取代码地址
- ……
结语
总得来说,从SVN迁移源码到Git仓库包括:准备工作、转换仓库、清理仓库以及收尾工作,其中清理仓库部分可以跳过,其他部分是需要完成的,还必须注意SVN文件布局以及正确地使用authors文件,同时,要考虑在遇到大仓库时应根据实际情况采用相对适合的迁移策略,最后,应遵循团队的约定,对照检查清单完成所有收尾工作。
本文链接:https://blog.waterstrong.me/svn-to-git-migration/