昨天写了多半年的第一篇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是如何做的呢?
- 找到两个分支上一个diff的点,这里是共同的祖先版本1
- 对当前绿色分支的最新的版本4和版本1进行diff,生成patch
- patch作用在版本5上,生成版本6
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后



