v0.0.2 的时候:大家开始总结经验,不能这么搞了,所有人从 XX-v-0.0.2 的代码仓库上创建一个自己的分支,自己开发,然后每天我们找个时间坐在一起,一个一个的把自己的分支合并到 XX-v-0.0.2 上面。这种做法某种程度上缓解了 0.0.1 版本的时候遇到的问题,其实就是把冲突的频率降下去了而已,实质跟 0.0.1 的做法没有任何区别。(试想一下假如还是在同一个分支上,大家约定都不提交,每天找个时间坐在一起一个一个的提交,是不是效果一样一样的?前者唯一的好处就是自己的代码起码有个版本库管着,不至于本地丢了就全没了;但是前者一个典型的坏处就是到合并的时候如果差异特别大的话合并起来就会相当困难,甚至完全没法合并。)
0.0.1 的做法是高频冲突概率,但是每次冲突的解决成本相对较小
0.0.2 的做法是低频冲突概率,但是每次冲突解决的成本相对较高
没法玩了么?
上述情况的排列组合里面有这么一个看起来最优的组合:如果我能做到冲突的频率很低,并且冲突解决的成本也低,那岂不是达到了一个比较完美的状态?
要想做到 「冲突频率低」,那么只能限制提交的频率,怎么限制?如果都在一个分支上搞,你总不能发个红头文件限制每个人每天提交的次数吧?那就在各自分支上搞呗!提交的次数我不能限制,合并的次数我还是可控的吧?搞定!所以结论是用分支分开搞比大家搅在一起搞要好。
要想做到 「解决冲突成本低」,怎么搞?顺着上面的分支开发思路,要想成本低那就得经常合并啊?三个和尚就没水吃了,更何况是十个程序员,怎么约定谁先合并谁后合并?
干脆我们找一个人专门来做合并,这个人就是 SCM ,SCM 每天就合并代码玩儿,第一个把 A 分支的代码合并进主干,问题不大,第二个把 B 分支合并进来,稍微有点费劲(因为差异变大了,可能会有冲突),第三个把 C 分支的代码合并进来,比较费劲(差异又增大了,冲突会增多),第四个把 D 分支的代码合并进来,就很困难了,第五个把 E 分支的代码合并进来.... SCM 离职不干了。
这是一个悲惨的笨 SCM 的故事。
后来来了个聪明的 SCM ,他合并完A分支之后,告诉剩下的 9 个分支 owner :
你们把主干代码和自己的代码先合并一下,谁先合并完谁先找我,我优先帮他合并进主干。
于是聪明 SCM 把以前笨 SCM 自己干的活儿分到了 9 个人头上,显然轻松了许多。但是程序员不乐意了:
凭啥写代码的也是老子,合并的也是老子,你知道合并有多麻烦么,先 diff 俩分支,拿到 diff 文件,再 patch 到我自己的分支上,解决完冲突连厕所都不敢上赶紧一路小跑跑去找你 SCM 大人,我特么累不累啊!!
聪明 SCM 说:
大哥你别急,你们忙我也没闲着,我做了一个工具,特意取了个名字叫 Git,洋气吧?你只要运行一个命令(git rebase 主干)就自动把主干代码合并到你的分支上去了,有冲突就解决,没冲突最好。
到这个时候为止,虽然不能说皆大欢喜,至少我们的目的达到了:
分支开发,大家减少“冲突频率”
经常性的合并,并且借助工具减少 SCM 和程序员的工作量,大家都省事儿
但是,不优雅。
聪明 SCM 想:
所有人都建分支搞,搞得 svn 上一坨一坨的分支,眼花缭乱的乱死了,这不是增加我的工作量么,其实这个分支对于开发者来讲,就是用于版本控制的,你放在你自己本地不行么?当你要合并的时候你再把这个分支给我,这样咱们公司的版本库 server 上不也干净么?这些临时的代码分支不要留在上面,多碍事。那么怎么放在本地呢?很简单啊,你自己在本地搭一个 svn server ,你自己的分支就在自己本地搞,你自己专属的 svn 服务器随便怎么搞都无所谓,然后等你要提交上来给我合并的时候,你再把这个分支提交到公司的 svn server 上来,别担心,还记得我那个洋气的工具么? Git !我又给他加了一个功能,帮你区分提交到不同的服务器,你看啊,你提交你自己本地的,我叫做 git commit ,你把你本地的提交给我的,我叫做 git push ,你看,多合理,push 就是 push 我赶紧帮你搞合并呐,为了取这名字我操碎了心呐,你说我怎么这么有才呢?
好,故事讲完了,多么自然的,“双 svn 架构” 就演变成了今天的 Git,它很好的解决了我们遇到的问题: