51Testing软件测试论坛

标题: Git 与 Subversion [打印本页]

作者: Mario洁    时间: 2019-1-25 15:04
标题: Git 与 Subversion
Git 与 Subversion

当前,大多数开发中的开源项目以及大量的商业项目都使用 Subversion 来管理源码。作为最流行的开源版本控制系统,Subversion 已经存在了接近十年的时间。它在许多方面与 CVS 十分类似,后者是前者出现之前代码控制世界的霸主。

Git 最为重要的特性之一是名为 git svn 的 Subversion 双向桥接工具。该工具把 Git 变成了 Subversion 服务的客户端,从而让你在本地享受到 Git 所有的功能,而后直接向 Subversion 服务器推送内容,仿佛在本地使用了 Subversion 客户端。也就是说,在其他人忍受古董的同时,你可以在本地享受分支合并,使暂存区域,衍合以及 单项挑拣等等。这是个让 Git 偷偷潜入合作开发环境的好东西,在帮助你的开发同伴们提高效率的同时,它还能帮你劝说团队让整个项目框架转向对 Git 的支持。这个 Subversion 之桥是通向分布式版本控制系统(DVCS, Distributed VCS )世界的神奇隧道。


git svn

Git 中所有 Subversion 桥接命令的基础是 git svn 。所有的命令都从它开始。相关的命令数目不少,你将通过几个简单的工作流程了解到其中常见的一些。

值得警戒的是,在使用 git svn 的时候,你实际是在与 Subversion 交互,Git 比它要高级复杂的多。尽管可以在本地随意的进行分支和合并,最好还是通过衍合保持线性的提交历史,尽量避免类似与远程 Git 仓库动态交互这样的操作。

避免修改历史再重新推送的做法,也不要同时推送到并行的 Git 仓库来试图与其他 Git 用户合作。Subersion 只能保存单一的线性提交历史,一不小心就会被搞糊涂。合作团队中同时有人用 SVN 和 Git,一定要确保所有人都使用 SVN 服务来协作——这会让生活轻松很多。


初始设定

为了展示功能,先要一个具有写权限的 SVN 仓库。如果想尝试这个范例,你必须复制一份其中的测试仓库。比较简单的做法是使用一个名为 svnsync 的工具。较新的 Subversion 版本中都带有该工具,它将数据编码为用于网络传输的格式。

要尝试本例,先在本地新建一个 Subversion 仓库:

  1. $ mkdir /tmp/test-svn
  2. $ svnadmin create /tmp/test-svn
复制代码

然后,允许所有用户修改 revprop —— 简单的做法是添加一个总是以 0 作为返回值的 pre-revprop-change 脚本:

  1. $ cat /tmp/test-svn/hooks/pre-revprop-change
  2. #!/bin/sh
  3. exit 0;
  4. $ chmod +x /tmp/test-svn/hooks/pre-revprop-change
复制代码

现在可以调用 svnsync init 加目标仓库,再加源仓库的格式来把该项目同步到本地了:

  1. $ svnsync init file:///tmp/test-svn http://progit-example.googlecode.com/svn/
复制代码

这将建立进行同步所需的属性。可以通过运行以下命令来克隆代码:

  1. $ svnsync sync file:///tmp/test-svn
  2. Committed revision 1.
  3. Copied properties for revision 1.
  4. Committed revision 2.
  5. Copied properties for revision 2.
  6. Committed revision 3.
  7. ...
复制代码

别看这个操作只花掉几分钟,要是你想把源仓库复制到另一个远程仓库,而不是本地仓库,那将花掉接近一个小时,尽管项目中只有不到 100 次的提交。 Subversion 每次只复制一次修改,把它推送到另一个仓库里,然后周而复始——惊人的低效,但是我们别无选择。


入门

有了可以写入的 Subversion 仓库以后,就可以尝试一下典型的工作流程了。我们从 git svn clone 命令开始,它会把整个 Subversion 仓库导入到一个本地的 Git 仓库中。提醒一下,这里导入的是一个货真价实的 Subversion 仓库,所以应该把下面的 file:///tmp/test-svn 换成你所用的 Subversion 仓库的 URL:

  1. $ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
  2. Initialized empty Git repository in /Users/schacon/projects/testsvnsync/svn/.git/
  3. r1 = b4e387bc68740b5af56c2a5faf4003ae42bd135c (trunk)
  4.       A    m4/acx_pthread.m4
  5.       A    m4/stl_hash.m4
  6. ...
  7. r75 = d1957f3b307922124eec6314e15bcda59e3d9610 (trunk)
  8. Found possible branch point: file:///tmp/test-svn/trunk => \
  9.     file:///tmp/test-svn /branches/my-calc-branch, 75
  10. Found branch parent: (my-calc-branch) d1957f3b307922124eec6314e15bcda59e3d9610
  11. Following parent with do_switch
  12. Successfully followed parent
  13. r76 = 8624824ecc0badd73f40ea2f01fce51894189b01 (my-calc-branch)
  14. Checked out HEAD:
  15. file:///tmp/test-svn/branches/my-calc-branch r76
复制代码

这相当于针对所提供的 URL 运行了两条命令—— git svn init 加上 git svn fetch 。可能会花上一段时间。我们所用的测试项目仅仅包含 75 次提交并且它的代码量不算大,所以只有几分钟而已。不过,Git 仍然需要提取每一个版本,每次一个,再逐个提交。对于一个包含成百上千次提交的项目,花掉的时间则可能是几小时甚至数天。

-T trunk -b branches -t tags 告诉 Git 该 Subversion 仓库遵循了基本的分支和标签命名法则。如果你的主干(译注:trunk,相当于非分布式版本控制里的master分支,代表开发的主线),分支或者标签以不同的方式命名,则应做出相应改变。由于该法则的常见性,可以使用 -s 来代替整条命令,它意味着标准布局(s 是 Standard layout 的首字母),也就是前面选项的内容。下面的命令有相同的效果:

  1. $ git svn clone file:///tmp/test-svn -s
复制代码

现在,你有了一个有效的 Git 仓库,包含着导入的分支和标签:

  1. $ git branch -a
  2. * master
  3.   my-calc-branch
  4.   tags/2.0.2
  5.   tags/release-2.0.1
  6.   tags/release-2.0.2
  7.   tags/release-2.0.2rc1
  8.   trunk
复制代码

值得注意的是,该工具分配命名空间时和远程引用的方式不尽相同。克隆普通的 Git 仓库时,可以以 origin/[branch] 的形式获取远程服务器上所有可用的分支——分配到远程服务的名称下。然而 git svn 假定不存在多个远程服务器,所以把所有指向远程服务的引用不加区分的保存下来。可以用 Git 探测命令 show-ref 来查看所有引用的全名。

  1. $ git show-ref
  2. 1cbd4904d9982f386d87f88fce1c24ad7c0f0471 refs/heads/master
  3. aee1ecc26318164f355a883f5d99cff0c852d3c4 refs/remotes/my-calc-branch
  4. 03d09b0e2aad427e34a6d50ff147128e76c0e0f5 refs/remotes/tags/2.0.2
  5. 50d02cc0adc9da4319eeba0900430ba219b9c376 refs/remotes/tags/release-2.0.1
  6. 4caaa711a50c77879a91b8b90380060f672745cb refs/remotes/tags/release-2.0.2
  7. 1c4cb508144c513ff1214c3488abe66dcb92916f refs/remotes/tags/release-2.0.2rc1
  8. 1cbd4904d9982f386d87f88fce1c24ad7c0f0471 refs/remotes/trunk
复制代码

而普通的 Git 仓库应该是这个模样:

  1. $ git show-ref
  2. 83e38c7a0af325a9722f2fdc56b10188806d83a1 refs/heads/master
  3. 3e15e38c198baac84223acfc6224bb8b99ff2281 refs/remotes/gitserver/master
  4. 0a30dd3b0c795b80212ae723640d4e5d48cabdff refs/remotes/origin/master
  5. 25812380387fdd55f916652be4881c6f11600d6f refs/remotes/origin/testing
复制代码

这里有两个远程服务器:一个名为 gitserver ,具有一个 master分支;另一个叫 origin,具有 master 和 testing 两个分支。

注意本例中通过 git svn 导入的远程引用,(Subversion 的)标签是当作远程分支添加的,而不是真正的 Git 标签。导入的 Subversion 仓库仿佛是有一个带有不同分支的 tags 远程服务器。







欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2