通过使分支非常便宜,SVN使分支变得更容易,但合并仍然是SVN中的一个真正的问题--Git据说可以解决这个问题.
Git能实现这一目标吗?
(免责声明:我所知道的关于Git的全部内容都是基于Linus讲座 - 这里的总git noob)
Git不会阻止合并中的冲突,但即使他们不共享任何父级祖先,也可以协调历史.
(通过grafts文件(.git/info/grafts
),它是一个列表,每行一个,其后是其父项的提交,您可以修改该"协调"目的.)
在那里非常强大.
但是要真正了解"如何通过思考进行合并",你可以先谈谈Linus本人,并意识到这个问题与"算法"无关:
Linus:我个人而言,我希望有一些非常可重复且不聪明的东西.我理解或告诉我它无法做到的事情.
坦率地说,合并单个文件历史而不考虑所有其他文件的历史记录让我"唉".合并的重要部分不在于它如何处理冲突(无论如何,如果它们都有趣的话,需要由人来验证),但它应该将历史整合在一起,以便为未来的合并提供新的坚实基础.
换句话说,重要的部分是微不足道的部分:父母的命名,并跟踪他们的关系.不是冲突.
看起来99%的SCM人似乎认为解决方案是更加聪明的内容合并.完全错过了这一点.
所以Wincent Colaiuta补充说(强调我的):
不需要花哨的元数据,重命名跟踪等等.
您需要存储的唯一内容是每次更改之前和之后树的状态.哪些文件被重命名?哪些被复制?哪些被删除了?添加了哪些行?哪些被删除?哪条线在它们内部发生了变化?哪个文本块从一个文件复制到另一个文件?
您不必关心任何这些问题,您当然不应该保留特殊的跟踪数据以帮助您回答:树的所有更改(添加,删除,重命名,编辑等)都是隐含的以树的两个状态之间的增量编码 ; 你只跟踪什么内容.绝对一切都可以(而且应该)被推断出来.
Git打破了模式,因为它考虑的是内容,而不是文件.
它不跟踪重命名,它跟踪内容.它在整个树级别上都这样做.
这与大多数版本控制系统完全不同.
它不打算尝试存储每个文件的历史记录; 它改为将历史存储在树级别.
执行差异时,您要比较两棵树,而不是两个文件.另一个根本智能的设计决策是Git如何合并.
合并算法很聪明,但它们并不会过于聪明.明确的决定是自动做出的,但是当有疑问时,由用户决定.
这是应该的方式.您不希望机器为您做出这些决定.你永远不会想要它.
这是Git合并方法的基本见解:虽然每个其他版本控制系统都试图变得更聪明,但Git很乐意自我描述为"愚蠢的内容管理器",并且它更适合它.
现在,人们普遍同意这种3向合并算法(可能还有重命名检测和处理更复杂的历史等增强功能),它考虑了当前分支('我们的')上的版本,合并分支上的版本('他们') ),并且合并分支的共同祖先版本('祖先')是(从实际角度来看)解决合并的最佳方法.在大多数情况下,对于大多数内容树级别合并(要采用哪个版本的文件)就足够了; 很少需要处理内容冲突,然后diff3算法就足够了.
要使用3向合并,您需要了解合并分支的共同祖先(称为合并基础).为此,您需要了解这些分支之间的完整历史记录.什么颠覆(电流)1.5版是缺乏之前(不含第三方工具,像SVK或SVNMERGE)为合并跟踪,即记忆的合并提交父母什么(什么承诺)的合并使用.没有这些信息,在重复合并的情况下无法正确计算共同的祖先.
考虑以下图表:
---.---a---.---b---d---.---1 \ / \-.---c/------.---2
(这可能会被破坏......有能力在这里绘制ASCII艺术图表会很好).
当我们合并提交'b'和'c'(创建提交'd')时,共同的祖先是分支点,提交'a'.但是当我们想要合并提交'1'和'2'时,现在共同的祖先是提交'c'.如果不存储合并信息,我们就必须错误地认为它是提交'a'.
Subversion(1.5版之前)和早期的CVS合并很难,因为你必须自己计算共同的祖先,并在进行合并时手动提供有关祖先的信息.
Git在提交对象中存储有关提交的所有父项(在合并提交的情况下多于一个父项)的信息.这样你可以说Git存储了DAG(直接非循环图)的修订,存储和记住提交之间的关系.
(我不确定Subversion如何处理下面提到的问题)
另外,在Git中合并可以解决另外两个复杂问题:文件重命名(当一方重命名文件,而另一方没有重命名;我们想要重命名,我们希望将更改应用于正确的文件)和十字交叉合并(更复杂的历史,当有多个共同的祖先时).
合并期间的文件重命名使用基于启发式相似性得分(文件内容的相似性和路径名的相似性都被考虑)来重命名检测.Git检测合并分支(和祖先)中哪些文件彼此对应.在实践中,它对于现实世界的案例非常有效.
Criss-cross合并,参见revctrl.org wiki的定义(以及多个合并库的存在)通过使用递归合并策略来管理,该策略生成单个虚拟共同祖先.
上面的答案都是正确的,但我认为他们错过了git轻松合并的中心点.SVN合并要求您跟踪并记住已合并的内容,这是一个巨大的PITA.从他们的文档:
svn merge -r 23:30 file:///tmp/repos/trunk/vendors
现在这不是杀手,但是如果你忘记它是23-30包容还是23-30独家,或者你是否已经合并了其中的一些提交,你就被软管了,你必须找出答案以避免重复或遗漏提交.如果你去分支,上帝会帮助你.
使用git它只是git merge而且所有这些都无缝地发生,即使你已经挑选了几个提交或做了许多奇妙的git-land事情.
据我所知,合并算法并不比其他版本控制系统更智能.但是,由于git的分布式特性,不需要集中合并.每个开发人员都可以随时将其他开发人员的小更改重新绑定或合并到他的树中,因此产生的冲突往往会更小.