Skip to content


使用git的一些问题的补充

昨天写了多半年的第一篇Blog,为什么选择git作为版本管理工具 。从微博和blog上收到很多反馈,我在这里做一个统一的补充。以Q&A的形式出现。

Q:SVN为什么对并行开发支持不好?
A:因为下面这几个点导致的

  • 不支持离线版本提交(最新版我不知道)
    • 每次提交都需要和服务器进行交互,只要有代码交换就有冲突的风险。这时候一旦出现冲突则必须解决,但是这个是被动的,不自愿的,他会使你从当前的任务中抽离出来去解决冲突。
    • 如果当前我没有可以联通服务器的网络环境,那么我就无法提交代码。这样对于一个稍大一些的功能,就必须一次性的开发完成才能提交,而无法在中途有几个关键节点的提交作为管理、存档。
  • 不支持轻量级分支
    这就决定了创建、销毁分支的代价比较大。不是不可以,而是不如git那么自然。
  • 分支合并的问题
    见下一个问题

Q:SVN的分支合并有问题?
A:有问题,而且问题很大。

SVN的分支模型是比较奇怪的一种方式。SVN的分支、Tag都是采用拷贝模式,也就是把现在的代码拷贝到一个叫做branches的目录(这是SVN推荐的目录模型)。而基于这种分支模型,他的合并模型自然选用了 diff-patch 模式,也就是从开出分支的分叉点作为基础,使用源分支的最新代码和基础点做diff生成patch文件,然后把patch文件作用在目标分支上。这样说起来可能有点乱,我们看下面的图。

这里是一条提交的记录,其中的数字是版本号。我们在版本1开出一条分支,现在绿色和红色两条分支一同并行开发。
在版本6的地方,需要从绿色分支到红色分支有一个合并,SVN是如何做的呢?

  1. 找到两个分支上一个diff的点,这里是共同的祖先版本1
  2. 对当前绿色分支的最新的版本4和版本1进行diff,生成patch
  3. patch作用在版本5上,生成版本6
这个过程看上去是没问题的,而且工作良好,但是问题马上来了,如果再来一次合并呢?这个“上一次”是哪个版本?还是版本1么?还是其他版本?因为版本6是从版本4和版本1 diff来的,所以如果还要从绿色的分支想红色分支进行合并那么就需要对版本4进行diff。老的SVN(1.4、1.5?)之前是没有办法知道这个新的基础点的,所以才有了svn-merge这样的工具出现。
苇叶同学说,svn在新版本中已经天然支持了这个基础点的记录,所以合并的体验会好很多。所以我今天特意的使用svn1.6版本做尝试,但是在准备之后,merge的这一步我犹豫了。svn的merge还是老掉牙的模式,这让用习惯了git/hg的我怎么也没胆量尝试。
 
Morpheus:svn-repo yinwm$ svn merge --help
merge: Apply the differences between two sources to a working copy path.
usage: 1. merge sourceURL1[@N] sourceURL2[@M] [WCPATH]
       2. merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]
       3. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [WCPATH]

  1. In the first form, the source URLs are specified at revisions
     N and M.  These are the two sources to be compared.  The revisions
     default to HEAD if omitted.

  2. In the second form, the URLs corresponding to the source working
     copy paths define the sources to be compared.  The revisions must
     be specified.

  3. In the third form, SOURCE can be either a URL or a working copy
     path (in which case its corresponding URL is used).  SOURCE (in
     revision REV) is compared as it existed between revisions N and M
     for each revision range provided.  If REV is not specified, HEAD
     is assumed.  '-c M' is equivalent to '-r :M', and '-c -M'
     does the reverse: '-r M:'.  If no revision ranges are
     specified, the default range of 0:REV is used.  Multiple '-c'
     and/or '-r' options may be specified, and mixing of forward
     and reverse ranges is allowed.

看,上面是svn merge的帮助,当我看到还需要指定版本号的时候,我就退却了。

Q:那么git没有这些问题么?
A:没有

git的初衷是为了管理Linux内核,要知道那可是全世界维护的一个项目,所以对分支的创建、销毁、合并的支持是非常良好的。他可以创建轻量级分支,这样在本地临时切换到某个分支进行一些feature的开发是非常方便的。当开发完成后直接合并即可,而如果失败就直接废弃这个分支,没什么成本和污染的。

git的每次提交是把整个的项目做一个镜像存储的,这样任何两个版本的区别只要简单的diff出来就可以,而分支合并也归并为简单的两个版本的diff,然后根据diff合并。这样你可以打着滚儿的合并,而不怕沾一身屎。

具体的git存储可以看这里,Git 内部原理 – Git 对象(翻墙越翻越健康)

Q:git没有良好的权限管理
A:被你戳中了

git本身有一些权限的管理,但是基本上他的粒度是对整个的项目。你可以通过ssh、apache等方式进行读、写的控制。但是能否更加细粒度的控制,我个人就不知道了。

这点上SVN绝对是领先git的。SVN也更适合大团队,因为大团队会有代码的安全性的考虑,分层、分段的控制是非常必须的。但是我们的团队很小,而且我的团队哲学是任何人可以看到、修改任何东西,包括代码和文档(我们的文档用trac的wiki和GDocs管理)。

在这点上我没过多的考虑,但是有需求的童鞋们,你们要想清楚哦。

Q:git-flow 真的很好么
A:git-flow 真的很好,像 hg-flow 一样的好

XD

最后

给大家看点我们代码库的截图,看到这些你就能明白为什么我说git/git-flow对我们的并行开发有很大的帮助了。图中每条颜色的线都是一条分支。

使用git-flow前

使用git-flow后

             

Posted in 项目管理.

Tagged with , , .