Git好用,但无奈历史原因,整个项目还得继续使用svn,但是又想使用Git的特性,所以尽力地去追求Git与svn的协作。
git svn命令
Git 中所有 Subversion 桥接命令的基础是 git svn
。所有的命令都从它开始。相关的命令数目不少,本文不过多介绍git svn的命令使用,只简单的说明一下最常用的几个,更多的知识参考书记pro git。
整理用户名与Email的映射
在 Subversion,每个提交者在都在主机上有一个用户名,记录在提交信息中。如果想让已有的信息更好的映射到 Git 作者数据里,则需要 从 Subversion 用户名到 Git 作者的一个映射关系,因为Git是用邮箱来标识一个提交者的。建立一个叫做 user.txt
的文件,每行一条svn作者 = 作者昵称 <邮箱地址>
,用如下格式表示映射关系:
schacon = Scott Chacon <schacon@geemail.com>
selse = Someo Nelse <selse@geemail.com>
SVN代码的所有提交者的作者名可以通过以下命令获得:
svn log --xml | grep "^<author" | sort -u | \
awk -F '\<author\>' '{print $2}' | awk -F '\</author\>' '{print $1}' > user.txt
得到以下文本,然后根据以上的格式编辑作者的邮件信息等。
schacon
selse
这样我们的把有svn的提交记录的作者、邮箱user.txt
都准备好了,接下来就克隆svn的地址。
克隆svn的trunk到本地
git svn clone http://example.com/path/to/project-x/trunk \
--authors-file=users.txt --no-metadata project-x
http://example.com/path/to/project-x/trunk
是svn的项目地址,这里用了trunk的目录。
--authors-file=users.txt
是指明svn的作者信息,git要用到。
project-x
是文件夹名字
--no-metadata
参数可以不要svn的信息,适合迁移的时候使用,不适合git svn共用,见下面的小节
如果你的项目很大,这一步是非常缓慢的。因为Git会去把整个提交记录遍历过去,然后对svn的每次提交多做一个补丁,产生一个git提交。特别是到了84000的时候感觉是假死的情况,其实只要慢慢等待就可以了。
no-metadata去除不爽的git与svn的关联信息
使用这个参数,请认真阅读本片段。
如果没有使用 --no-metadata
来克隆svn项目,那么如果输入git log
将会看到一堆“没用的东西”:
commit 37efa680e8473b615de980fa935944215428a35a
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date: Sun May 3 00:12:22 2009 +0000
fixed install - go to trunk
git-svn-id: https://my-project.googlecode.com/svn/trunk@94 4c93b258-373f-11de-
be05-5f7a86268029
如果使用了--no-metadata
参数,那么得到的提交信息是这样的:
commit 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Author: Scott Chacon <schacon@geemail.com>
Date: Sun May 3 00:12:22 2009 +0000
fixed install - go to trunk
是不是变得清爽了呢?那么git-svn-id
这个东西到底是做什么用的呢?
原来git-svn-id
是记录git的提交与svn的提交的关联关系。如果没有这个,那么你只能在git上的提交,无法提交到svn。
建议:如果是你想向svn提交,那么不要使用这个参数。如果你只是迁移svn的历史记录到Git中,那么请开启这个参数。
设置Git的参数
之前我们把svn的代码拉取到本地来了,接下来要设置一下远程仓库的配置
cd project-x
# 设置远程仓库的url地址,如果你的是ssh的方式,又可能不一样了。
git remote add origin http://git.code.com/url/project-x.git
# 设置git的提交用户名和邮箱
# --global参数是全局设定,如果是想当前项目设置,那么去除这个参数
git config --global user.name youname
git config --global user.email email@email.com
从svn获取更新
刚刚我们git svn clone下载了svn的源码,但是如果有人提交了svn的代码,那么我们这个时候还要继续拉取svn的代码。
# 从svn拉取代码。这个事实拉取代码到本地,并没有合并到本地的分支来。
git svn fetch
git checkout master
git svn rebase
# svn update = git svn fetch + git svn rebase
这里检出master分支,去做一次拉取svn并合并代码的操作,理想的情况下使用其他的分支,不一定是master
分支。 然后用rebase
把提交记录应用到分支上,构成一个线性的提价记录。
我有好多个分支怎么办?
我们一开始都默认值选择了一个分支,我如果想获取多个分支怎么处理呢?
向svn提交代码
假设你在分支feature
分支上做开发,没有提交到master
分支上。那么有两种方法提交到svn。
- 保留feature分支所有的提交记录
- 压缩feature分支的提交记录,变成一个提交记录。
保留个人的提交记录
svn和git分支概念不一样,你要把git的提交推动到svn的代码库中也非常的简单。只需要使用rebase命令到跟踪svn的那个分支上就可以了。然后执行dcommit提交到svn服务器。
git checkout master # 先拉取svn的代码
git svn rebase
git checkout feature123 # rebase 到master分支上
git rebase master
git checkout master
git merge feature123 # 使用fast-forward合并,让master指针指向最新的提交
git svn dcommit # 推送到svn服务器
压缩个人的提交记录
和上一种提交没有什么区别。唯一的区别就是在如果你拉取了一个分支feature123,并且没有人在master上面做任何的提交,那么可以使用merge
来进行fast-forward快速合并(这样子是不会压缩为一个提交记录的)。然后提交到服务器。
另外一种情况是,他人在svn的分支上提交代码了,你也在master的基础上提交代码了。这个时候git没办法进行fast-forward快速合并,只能进行merge 三方合并。这个时候会把之前的提交记录变成一个提交。然后推送到服务器上。
git checkout master # 先拉取svn的代码
git svn rebase
git merge feature123 # 这里可能是fast-forward合并,也可能是三方合并。
git svn dcommit # 推送到svn服务器
使用心得
git与svn协同,这种方式用的比较麻烦,又要使用svn又要使用git。只是有这种需求的人,都是项目还在svn管理。建议将整个项目使用git提交信息,但是最后推送到svn的tag目录下。
参考
近期评论