svn迁移到git仓库并保留commit历史记录

作者: veaxen 分类: Git/Svn 发布时间: 2018-09-28 21:52

环境准备

sudo apt-get install subversion
sudo apt-get install git
sudo apt-get install git-svn

迁移

首先用svn将代码checkout到本地

svn checkout http://svn.company.com/projectname

创建用户映射

在subversion,每个提交者都在主机上有一个用户名,记录在提交信息中,比如blame的输出以及git svn log。如果想要让这条信息过呢更好的映射到git里面,需要在svn用户名到git用户名之间建一个映射关系,我们这里用user.txt文件来建立这个映射关系:

veaxen = veaxen <veaxen@veaxen.com>
jack = jack <jack@veaxen.com>
tom = tom <tom@veaxen.com>

在svn库下执行下面的命令生成user.txt,获取svn作者的列表:

svn log --xml | grep -P "^<author" | sort -u | perl -pe 's/<author>(.*?)<\/author>/$1 = /' > user.txt

根据svn账号与git账号的映射,补充user.txt为上述格式。

导出svn工程

利用git clone ...命令,可以将svn工程导出为git工程,但是如果只是简单的执行下面命令的话:

svn checkout http://svn.company.com/projectname/trunk

那么我们只是将其中的主分(trunk分支)支及其log拉去到本地,其他分支并没有,需要用到--trunk--tags--branches等选项。

需要注意的有下面几点:
1. 除了trunk单词是单数之外,其他选项单词都是复数--trunk参数指明了svn主分支所在目录,如果不指明默认是trunk目录,--tags指明了svn的tag所在目录(我们公司没有用到tag管理代码,这里我忽略),--branches参数指明了其他分支所在目录,如果不指明默认是branches目录。
2. 这几个选项指定的都是相对路径,相对于git svn clone后面紧跟着的路径位置,所以不要在选项里制定诸如“http://”开头的相对路径。
3. 除了trunk之外,其他几个选项都可以重复指定,如果你的分支/标签分别在svn目录上的不同文件夹下,可以多次指定。

于是,对应我的实际情况,git-svn命令是这样的:

git svn clone http://svn.company.com/projectname/    \   #注意这里写到项目根目录,而不是写到分支所在路径
--trunk="trunk" --branches="branch"   \  #这里的trunk可以不指定,而branches则是一定要指定的,这是由于我们的svn项目的目录不是标准的svn目录,我们的其他分支是在branch目录下,而不是svn建议的branches目录
--no-metadata --authors-files=user.txt  \   #前一个参数用来阻止git svn包含哪些svn附带的信息,后一个参数是根据文件里指定的映射关系,将svn用户同git用户联系起来
projectname

稍等一会,就可以看到真个svn的主分支和其他分支都被导出来了,并且保留了commit信息,一棵赛艇!:smile::smile:

分支处理

执行git branch -a可以看到相应的分支已经按照我们指定的选项建立起来了,我的实际情况是:

git branch -a
* master
  remotes/origin/develop
  remotes/origin/func_01_branch
  remotes/origin/func_02_branch
  remotes/origin/func_03_branch
  remotes/origin/func_04_branch
  remotes/origin/func_05_branch
  remotes/origin/trunk

你会发现,remotes/origin/xxx这样的分支,git会认为他们是虚拟的远程分支,我们可以通过下面命令将分支拉到本地(以develop为例):

git checkout -b develop remotes/origin/develop

还有一点要说明的是,remotes/origin/trunk分支其实与本地master分支是一样的,所以我们没有必要将这个分支转换为本地分支。

上传到git服务器

首先要在git服务器上创建一个空的工程,比如“git@rdgit.company.com/some_group/projectname.git”

然后再本地仓库执行:

git remote add origin git@rdgit.company.com/some_group/projectname.git

将主分支上传到git服务器:

git push origin master:master

其他分支也是利用这个语句创建新分支上传。

完成之后,在git服务器上就可以看到完整的change log以及分支的变化情况了。

关于空目录

其实迁移的时候还需要注意一个问题,那就是 svn 支持空目录的版本控制,但是 git 不支持。

导出 svn 之后,最好对比一下原始的 svn 工程内是否有空目录。如果有,那么你需要手工(或者写脚本)在导出的 git 工程中创建这些目录,并且在目录中建立一个 “.gitkeep” 文件(这是约定俗成的做法),并且将这些文件git add .gitkeep,以加入 git 的版本控制。这样就以迂回的方式通过 git 版本控制了目录。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.