git and subversion

June 14, 2007 – 9:45 pm

Linus 在 Google 做了他对于版本控制软件的演讲。他似乎非常偏爱分布式版本控制软件,否则宁愿用 tarball+patch (其时 tarball+patch 确确实实是一种分布式的方法呢!)。以至于在 Linux 内核不能试用 BitKeeper 以后,他自己动手写了 git 。他对版本控制软件有许多要求,比如:

  1. 取出来的东西要和放进去的东西一样。如果连数据的完整性都无法保证的话,谁还敢用这样的版本控制软件?不过确实有这样的软件存在呢。
  2. 分布式。我在后面会解释分布式的好处。
  3. 高效率。Linux 内核也算是一个很大的软件了,如果版本控制系统运行起来慢吞吞的,确实是非常让人恼火的呢。
  4. ……

Linus 当时(Linux 2.6.12 的那阵)说现有的版本控制系统都不行,他两个周就能写出一个更好的。结果他 4 月 7 日开始写 git ,在 4 月 20 日的时候内核已经开始使用 git 进行源代码管理了。参见这里的原文:

Linus began writing “git” on April 7’th [story], a rapidly evolving userland filesystem upon which various SCM implementations are being built or adapted. The 2.6 kernel source is already managed in a git repository, with the first succesful git release being 2.6.12-rc3 on April 20’th

当然可用离好用还是有很远的距离的,不过 Linus 确实很厉害了!后来 git 由其他人维护,并且在用户界面上进行了改进,现在已经相当好用了。另外一个有名的开源的分布式版本控制系统是 mercurial ,这个是由 Python 写成的,不知道在效率一条上满不满足 Linus 的要求,呵呵!其时各种分布式版本控制软件在开源社区是很流行的,有时候下载一些软件的时候就看到如果要获取最新代码,就要用作者使用的版本控制系统来进行抓取,像 Arch 、bazaar 、monotone 、darcs 一类的,都是使用得比较多的分布式版本控制系统。

为什么分布式版本控制系统会流行起来呢? sishen 在他的 Blog DistributedSCM or not? 里面提到了传统的版本控制和分布式版本控制模型之间的差别。下面说一下我自己的看法:

  • 更方便的 Merge 。分布式管理必然导致大量的 Branch 和 Merge 操作。因此分布式版本控制系统都特别注意这方面。在传统的 CVS 里面制作 Branch 和 Merge 简直就是噩梦,Subversion 作为一个用于替代 CVS 的系统,专门改进了 Branch 操作,在它的主页上可以看到这样一句话:
    Branching and tagging are cheap (constant time) operations

    There is no reason for these operations to be expensive, so they aren’t.

    Branches and tags are both implemented in terms of an underlying “copy” operation. A copy takes up a small, constant amount of space. Any copy is a tag; and if you start committing on a copy, then it’s a branch as well. (This does away with CVS’s “branch-point tagging”, by removing the distinction that made branch-point tags necessary in the first place.)

    然而似乎人们没有注意到,Branch 是轻松了,可是 Merge 呢?如果不能很方便地 Merge 回来,做 Branch 仍然是噩梦。事实上,我就经历过在开发团队里面由于队友操作不对而在 Merge 的时候把我的许多代码都覆盖掉了。当时正是使用的 subversion 。虽然源代码仍然在历史里面,但是要去一个一个地找出被覆盖掉的文件并恢复过来确实是一件很难忘的事情。

  • 更轻松的管理。传统的版本控制系统使用中央仓库,一些仓库相关的管理就只能在仓库上进行。赋予开发团队每一个人中央仓库的管理权限是非常不好的。但是有时候确实会比较不方便的地方。
  • 更健壮的系统。分布式系统一般情况下总是比单服务端的系统要健壮,因为但服务端一旦服务器挂掉了整个系统就不能运行了。然而分布式系统通常不会因为一两个节点而受到影响。
  • 对网络的依赖性更低。虽然现在网络非常普及,但是并不是随时随地都有高速网络,甚至有时候根本没有网络可以访问。低速的网络会让人心情烦躁,有时候就呆呆地盯着屏幕上的 commit 进度,什么事情也干不了。而没有网络连接更是致命的:你无法 commit !这表示你进行任何改动以前都必须小心翼翼,否则你可能再也找不会你曾经写的一些代码了。
  • 更少的“仓库污染”。我不知道用“仓库污染”这个词是否恰当。有时候你要做一个模块,它不是太大,所以没有必要为它新建一个 branch ,但是它又不是那么小,不可能一次提交就做好。于是便会提交一些不完整的代码到仓库,有时候会导致整个程序无法运行,严重影响团队里其他人的开发。大多数人在这种情况下的解决办法都是写完之后再提交。但是作为习惯了版本控制的人来说,进行不计后果的大幅修改是经常的事情,到后来突然发现自己先前的代码没有提交,就后悔莫及了。如果是分布式系统的话就不会存在这样的问题,因为本地仓库的修改不会影响到别人的仓库。当你完成并测试以后,就可以在邮件列表里面说:我已经把这个模块做好了。然后感兴趣的人就可以从你这里 pull 你的成果了。

然而,不管怎么说,现在传统的版本控制系统仍然是主流。许多源码 Host 站点如 SourceForgeGoogle Code 等都是使用主流的 subversion 作为源代码版本控制的工具。

事实上,有时候我把 subversion 和 git 混合起来用。因为二者都有忽略某些文件的功能,只要在 subversion 的目录属性里面忽略掉 .git 一类的文件,再在 .gitignore 里面忽略 .svn 等文件,两者基本上也能很和谐地合作。通常在本地工作,使用 git 控制,并在适当的时候用 subversion 提交一次。

事实上它们配合得相当不错。即使是像 rm 一类的命令。比如,先用 svn rm foofoo 删掉了。当前目录下已经不存在 foo 了,不过 git rm foo 仍然是能正常工作的。不过这和更改文件内容不一样了,不能自动跟踪,只能每次都在两个版本控制系统下都执行一遍。虽然可以用一些简单的脚本来减少这种重复劳动,但是有时候混用两个东西确实有种提心吊胆的感觉。 :P

  1. 15 Responses to “git and subversion”

  2. 我预计open source将越来越多的采用DSCM管理, 不过在公司范围内, DSCM还是很难比SVN流行.

    By sishen on Jun 14, 2007

  3. 恩,毕竟公司不像开源世界那样天南地北的,管理相对集中,而且公司内部肯定是高速网络。不过 DSCM 通常都有一种 push 的方式也可以模拟一个中央服务器出来。但是对于公司来说,既然 svn 能工作得很好,通常都不会花额外的代价去移植到另外一个全新的系统上的。发展还要一步一步地来啊。 Emacs 的仓库现在还是 CVS 呢。

    By pluskid on Jun 14, 2007

  4. Linus 果然厉害的。估计写的时候已经娴熟于胸了。有机会我玩玩Mercurial.

    By Jack on Jun 16, 2007

  5. 这种偏好更大程度上是因为管理因素而非技术因素。FreeBSD项目够大了,参与者也够发散了,用集中式SCM一样管理得很好。

    By adoal on Jul 6, 2007

  6. to adoal:

    恩, Emacs 也还在用 CVS 进行维护。不过我觉得从纯技术上来说 DSCM 还是比传统的 SCM 有优势的(至少比 CVS 有优势)。不过黑客们都很厉害罢了,汇编 + ed 就能写出棒极了的 UNIX 来,但是不能因此说 C 语言和汇编相比在技术上没有优势是吧?

    By pluskid on Jul 6, 2007

  7. adoal, 很好和更好是一种区别,没有人都认集中式的SCM, 但是分布式的SCM是不是解决了更多的不方便呢?这里introduction to Git我想回答了很多这种问题: http://nextlib.lifegoo.com/user/jack/article/647

    By Jack on Jul 9, 2007

  8. 不需要 git 和 svn 这样来混合呀,

    git 有 git-svn 插件,
    可以直接从 svn 仓库抓取分枝,
    在本地使用 git 管理,
    大修改再提交回 svn。

    By 华华 on Jan 27, 2008

  9. @华华:
    嗯,还没有听说过,不过现在 git 确实是越来越流行了,有了许多脚本可以用。

    By pluskid on Jan 27, 2008

  10. 简单的流程像是这样
    0. 给 git 安装 git-svn
    1. 使用 git-svn clone svn://xxx.yyy/zzz 取出
    2. 在取出的目录里边工作
    3. 使用 git commit 本地提交
    4. 其他跟 svn 类似
    5. 使用 git-svn rebase 来获取自更新,当然如果发生冲突了,那还是需要你手工解决这些冲突。
    6. 用 git-svn dcommit 将你的工作提交到 svn 仓库中,没有人知道你在用 Git 来管理你本地的代码

    而 bzr-svn 的情况有些类似,
    只是 bzr 自动判断仓库类型,不需要区分命令。

    By 华华 on Jan 27, 2008

  11. 恩,其实分布式的 SCM 大多也有一个类似于中央仓库的节点,这样中央仓库 + 分布式的方式也不失一直解决办法,只是用不同的工具一般没什么必要,最主要的还是用于工作在现存的 svn 仓库上吧。

    By pluskid on Jan 27, 2008

  12. @华华:
    恩,试用了一下,git-svn 果然是一个很不错的工具,特别是最近家里面雪灾,老是停电断网的,只用 svn 的话,会很不方便,而许多做 project hosting 网站似乎都没有支持 DSCM 的。 :)

    By pluskid on Jan 31, 2008

  13. 然而似乎人们没有注意到,Branch 是轻松了,可是 Merge 呢?如果不能很方便地 Merge 回来,做 Branch 仍然是噩梦。事实上,我就经历过在开发团队里面由于队友操作不对而在 Merge 的时候把我的许多代码都覆盖掉了。当时正是使用的 subversion 。虽然源代码仍然在历史里面,但是要去一个一个地找出被覆盖掉的文件并恢复过来确实是一件很难忘的事情。
    ========================
    我个人理解merge时只要有conflict,都要人手处理,很难想像git是怎样避免这个问题的,难道git可以做到不conflict?这更加超出我的想象范围。。。希望博主能讲讲git是怎样轻松merge的

    By Jarod on May 30, 2008

  14. @Jarod,
    我想遇到冲突的时候需要人的参与是不可避免的,这里说的“轻松”并不是指可以自动处理冲突,而是指方便地处理。git 尽可能地自动化可以自动化的东西,而,如果我没有记错的话,在 svn 里 merge 一个 branch 甚至需要手工输入 branch 的起始和终止版本号之类的信息吧?

    By pluskid on May 30, 2008

  15. 大家可以试试国内提供git服务的
    http://www.githost.cn

    By bugx on Sep 15, 2008

  1. 1 Trackback(s)

  2. Sep 6, 2007: Free Mind » Blog Archive » Workflows of SCM

Post a Comment