SVN 和 GIT 对比的系列博文尚有几篇一直放在草稿中,处于构思阶段,今天从故纸堆里检出来(checkout?)

我们在《Subversion 用户眼中的 Git (7): 完全不同的分支和里程碑的实现》中介绍过,Git 和 Svn 的分支实现机制完全的不同,这也直接导致了 SVN 在分支合并中困难重重。尽管在 SVN 1.5 之后,通过 svn:mergeinfo 属性引入了合并追踪机制,但是在特定情况下,合并仍会出现很多困难。

《SVN 树冲突和目录丢失问题(1)》系列博文中,介绍了帮助我的一个朋友解决SVN树冲突的过程。这实际上在 GIT 中是 “a piece of cake”。你可以用 Git 模拟一下不同分支中文件目录改名引发合并冲突,在Git 中解决的是那么自然和漂亮!

这是为什么呢?因为 SVN 是单亲家庭,而 GIT 是双亲/多亲家庭啊。

SVN 的单亲家庭

在博文《Subversion 用户眼中的 Git (4): 全局版本号和全球版本号》中我们提到过,SVN 的版本号是连续的版本号。每一次新的提交都会版本号+1 ,而无论这个提交是在哪个分支中进行的。我们在《Subversion 用户眼中的 Git (7): 完全不同的分支和里程碑的实现》也提到过,SVN一个提交可以同时修改不同分支的不同文件,因为提交命令可以在 /trunk, /branches, /tags 的上一级目录执行。

  • SVN 的提交是单线索的,每一个提交(最原始的提交0除外)都只有一个单亲节点(版本号小一个的提交节点)
  • SVN 的提交链只有一条,仅从版本号和提交说明,我们无法获得分支图
  • SVN 的分支图在某些工具(如乌龟SVN)可以提供,那是需要对提交内容进行检查,对目录拷贝动作视为分支,对 svn:mergeinfo 的改动视为合并,但这会由于目录管理的灵活性,导致千奇百怪的分支图表
  • SVN 的单亲节点的设计,是SVN分支合并输在起跑线上的唯一原因。也是 SVN 永远无法在 GIT 面前抬头的最重要原因

Git 的双亲/多亲家庭

Git 的提交实际上是按照多亲进行设计的,即一个提交可以包含两个以上的多亲节点,不过一般合并是双分支合并,因此合并节点以双亲居多。

  • 大部分提交实际上只用到了多亲节点中的一个,即大部分提交是对前一个提交的修改
  • 合并操作一般用到两个双亲节点(或者更多),这很自然
    合并操作是将两个提交合二为一,因此在新的合并结果的提交后产生的节点会有两个双亲节点。

Git 的提交也没有顺序的要求

  • 不必非要基于最新节点提交,因为作为分布式版本控制系统,你根本不知道是不是有人在你之前进行和提交
  • 你甚至可以先切换(检出)到之前老的提交节点,修改代码再进行提交,提交就形成分支
  • 和其他人的版本库合并,也会形成分支

基于以上的特点,提交之间会形成复杂的提交家族谱系。从一个原始节点开始(甚至多个原始节点),派生出任意多的谱系。

  • 可以用下面的命令查看提交关系图
    • 最简单的命令是:
      $ git log --graph
    • 还可以通过工具 gitk,qgit 等提供图形化的分支显示界面