对一个项目同时使用svn和git两个远程仓库

以前曾经和朋友讨论过在一个项目中同时使用svn和git两个远程仓库的可能,如今真的遇到了这样的实际需求。

在开发WordPress插件External Media without Import的时候,因为希望插件能在WordPress官方渠道发布,所以需要在WordPress官方提供的svn远程仓库上托管这个项目。WordPress官方给我提供的svn仓库的地址是https://plugins.svn.wordpress.org/external-media-without-import/

但另一方面,考虑到github作为开源社区的人气,以及fork、pull request等代码贡献的便利性,我也想在github上托管这个项目。因此我在github上也创建了一个仓库:https://github.com/zzxiang/external-media-without-import.git

与此同时,我希望本地只需要维护一个项目文件夹,或者绝大部分操作只需要在一个文件夹中执行。这个文件夹由git管理,并可以方便地与WordPress的svn和github双方同步。不过后来经过一段时间摸索,我似乎只能做到让git和svn仓库的trunk分支同步,但这也足够了。

也就是说,我希望实现的应用场景如下图所示:

WordPress官方提供的svn仓库和github上的仓库在刚创建好的时候都是空库,里面没有任何文件;而在此之前我已经在本地的git管理的文件夹中工作了一段时间,里面已经有多条提交记录和多份文件。我希望将这些历史记录和文件都同步到远程的svn和git仓库。最后要达成的效果是远程svn仓库的trunk分支、远程git仓库的master分支和本地git仓库的master分支中的提交一一对应。这三个分支保持同步,完全相同。

与github的同步较为简单,毕竟本地和远程都是git仓库。因此先来解决和svn仓库同步的问题。我要将本地的git仓库和远程的svn仓库之间关联起来。

出于示例的目的,我在本地从零开始建立一个git仓库和一个svn仓库,并用它们模拟这种情况,让git仓库已有的提交全部同步到svn仓库,并且在此之后能直接向svn仓库提交以及直接从svn仓库更新。实际应用的时候将下文以 file:// 为前缀的svn仓库URL替换为实际的 svn:// 或 https:// 为前缀的URL即可。

先在本地创建一个git仓库,并往里面添加一些提交:

现在git仓库里应该有一个text.txt并且已经有三条提交:

接着创建一个svn仓库:

用svn客户端在仓库里创建好trunk、branches和tags这样的标准目录:

接下来可以开始将git和svn关联起来,从现在起基本上所有操作都全部在git中执行,如果不需要开辟svn分支和标签的话,甚至可以将svn-client目录删掉。

进入git仓库,先用 git svn init 命令将svn仓库的地址添加到git目录的配置中:

本地git目录里的.git/config文件中应该增加了如下一段配置:

在日常工作中,一般是通过 git svn rebase 将svn仓库里的提交更新到本地的git仓库,并且将本地git仓库中还未同步到远程的提交rebase到已从远程仓库更新下来的提交之上。但现在就执行这条命令的话会报错:

git svn info 命令也会报同样的错误。这是因为git仓库中尚不存在远程svn仓库的对应分支。我们要先通过fetch命令获取svn仓库的内容,从而创建出这个远程分支。

实际应用中我曾遇到过fetch无效的现象,似乎是因为svn仓库中没有提交也没有文件。用svn客户端往仓库里提交一份文件(内容任意,注意不是文件夹)后,git这边就能fetch到东西了。

现在本地git目录中应该多了个远程分支对应svn仓库:

此时也可以通过git日志看到本地git目录中svn分支的存在:

现在将git仓库中已有的提交全部rebase到svn远程分支上:

现在 git svn rebase 和 git svn info 应该能正常工作了:

上面 git svn info 的输出中出现 Use of uninitialized value $lc_author 的提示是因为 Last Changed Author 和 Last Changed Rev 为空,从svn客户端中也看不到提交记录(其实我对这一点不是很明白,因为明明应该有一个创建trunk、branches和tags目录的提交):

将git仓库中的提交推送到svn仓库中,这个错误消息就会消失:

现在我们已经将本地git仓库和svn仓库成功关联起来。接下来要给本地git仓库添加远程git仓库的引用。这个工作比较简单,在本地git仓库目录中执行以下命令:

.git/config文件中应该会增加下面一段内容:

最后把本地git仓库中的提交全部push到远程git仓库:

这样本地git仓库和svn仓库及远程git仓库就都同步了。日常工作中使用以下四个命令在这三个仓库之间同步:

  • 本地git仓库向svn仓库推送提交: git svn dcommit 
  • 本地git仓库从svn仓库获取更新: git svn rebase 
  • 本地git仓库向远程git仓库推送提交: git push 
  • 本地git仓库从远程git仓库获取更新: git pull 

一般不需要再使用svn客户端。唯一的例外是需要在svn仓库中创建分支和标签的时候。虽然git也有 git svn branch 和 git svn tag 命令可用于该目的,但在我的环境中这两个命令却会报错:

后来我还是使用了svn客户端来创建svn仓库中的分支和标签。

本文参考了这篇文章:Using Git and Subversion Together

《对一个项目同时使用svn和git两个远程仓库》上有1条评论

发表评论

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