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

来源:互联网 发布:网络有前景的项目 编辑:程序博客网 时间:2024/06/05 11:12
以前曾经和朋友讨论过在一个项目中同时使用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仓库,并往里面添加一些提交:


mkdir local-git-reposcd local-git-repos/git inittouch test.txtgit add test.txtgit commit -am "Added test.txt."echo aaaa >> test.txtgit commit -am "Added aaaa."echo bbbb >> test.txtgit commit -am "Added bbbb."

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


$ lstest.txt$ cat test.txt aaaabbbb$ git logcommit 15db9719b735c65b4d8ffc2cbf08b54ebad09e38Author: Zhixiang Zhu <zzxiang21cn@hotmail.com>Date:   Wed Jul 5 20:36:36 2017 +0800     Added bbbb. commit e1d6c1556fa210ca0a0b12e661ac5d23e5d215d2Author: Zhixiang Zhu <zzxiang21cn@hotmail.com>Date:   Wed Jul 5 20:36:35 2017 +0800     Added aaaa. commit d769c9a48932782a683336d478356ccd124077cdAuthor: Zhixiang Zhu <zzxiang21cn@hotmail.com>Date:   Wed Jul 5 20:36:35 2017 +0800     Added test.txt.

接着创建一个svn仓库:


cd ..svnadmin create svn-repos

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


svn co file://`pwd`/svn-repos svn-clientcd svn-client/mkdir trunk branches tagssvn add *svn ci -m "Added trunk, branches and tags."

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

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


cd ../local-git-repos/git svn init --stdlayout file://`pwd`/../svn-repos/ --prefix=svn/

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


[svn-remote "svn"]url = file:///Users/zhixiangzhu/git-svn-test/local-git-repos/../svn-reposfetch = trunk:refs/remotes/svn/trunkbranches = branches/*:refs/remotes/svn/*tags = tags/*:refs/remotes/svn/tags/*

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


$ git svn rebaseUnable to determine upstream SVN information from working tree history

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


$ git svn fetch -rHEADr1 = 72572673ab962bd61cd3f244f8cf63beca1bc8f8 (refs/remotes/svn/trunk)

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

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


$ git branch -a* master  remotes/svn/trunk

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


$ git log --oneline --decorate --all --graph* d9b5878 (svn/trunk) Added trunk, branches and tags.* 15db971 (HEAD -> master) Added bbbb.* e1d6c15 Added aaaa.* d769c9a Added test.txt.

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


$ git rebase --onto remotes/svn/trunk --root masterFirst, rewinding head to replay your work on top of it...Applying: Added test.txt.Applying: Added aaaa.Applying: Added bbbb.

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


$ git svn rebaseCurrent branch master is up to date.$ git svn infoUse of uninitialized value $lc_author in concatenation (.) or string at /usr/local/Cellar/git/2.8.1/libexec/git-core/git-svn line 1639.Use of uninitialized value $lc_rev in concatenation (.) or string at /usr/local/Cellar/git/2.8.1/libexec/git-core/git-svn line 1640.Path: .URL: file:///Users/zhixiangzhu/git-svn-test/local-git-repos/../svn-repos/trunkRepository Root: file:///Users/zhixiangzhu/git-svn-test/local-git-repos/../svn-reposRepository UUID: 79d69224-e83d-4033-9427-31fe05b277a8Revision: 1Node Kind: directorySchedule: normalLast Changed Author: Last Changed Rev: Last Changed Date: 2017-07-06 14:22:31 +0800 (四, 06  7 2017)

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


$ svn log------------------------------------------------------------------------

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


$ git svn dcommitCommitting to file:///Users/zhixiangzhu/git-svn-test/local-git-repos/../svn-repos/trunk ...Atest.txtCommitted r2Atest.txtr2 = 89de67ea07dc796a5ce4b96bb4786a890eab86d7 (refs/remotes/svn/trunk)Mtest.txtCommitted r3Mtest.txtr3 = 1aeeb3dcc30e0b4c03e27981ff04dce11472151e (refs/remotes/svn/trunk)Mtest.txtCommitted r4Mtest.txtr4 = 22a31f42be3a51c285b4fa07b3ef4e53bcf07625 (refs/remotes/svn/trunk)No changes between aa2560cf0de937d4045bc2f30dcab46752d65b94 and refs/remotes/svn/trunkResetting to the latest refs/remotes/svn/trunk$ git svn infoPath: .URL: file:///Users/zhixiangzhu/git-svn-test/local-git-repos/../svn-repos/trunkRepository Root: file:///Users/zhixiangzhu/git-svn-test/local-git-repos/../svn-reposRepository UUID: 79d69224-e83d-4033-9427-31fe05b277a8Revision: 4Node Kind: directorySchedule: normalLast Changed Author: zhixiangzhuLast Changed Rev: 4Last Changed Date: 2017-07-06 20:37:07 +0800 (四, 06  7 2017)

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


git remote add origin https://github.com/zzxiang/external-media-without-import.git


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


[remote "origin"]url = https://github.com/zzxiang/external-media-without-import.gitfetch = +refs/heads/*:refs/remotes/origin/*


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


git push --set-upstream origin master


这样本地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 命令可用于该目的,但在我的环境中这两个命令却会报错:

$ git svn tag 1.0Copying https://plugins.svn.wordpress.org/external-media-without-import/trunk at r1669373 to https://plugins.svn.wordpress.org/external-media-without-import/tags/1.0...Authentication failed: No more credentials or we tried too many times.Authentication failed at /usr/local/Cellar/git/2.8.1/libexec/git-core/git-svn line 1196.


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

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


本文在我的独立博客上的地址:http://zxtechart.com/2017/07/16/use-two-remote-repos-of-svn-and-git-at-the-same-time-for-the-same-project/

原创粉丝点击