暂存区域内的基础git合并过程是什么?

时间:2011-08-17 14:42:22

标签: git merge

Git执行merge魔术,然后让用户解决真正的冲突,这应该是应有的。我正在寻找基本git合并的方式和原因以及它如何使用暂存区的低级描述。

我刚刚阅读了Git Parable,以及对here的评论

  

即使考虑到它是“比喻”并且没有重述Git历史的事实(顺便说一下你可以在Git Wiki上找到一些细节),但有一点仍然存在:这是IMVHO的不良做法在将更改拆分为多个提交和/或与dity树进行组合的术语中解释暂存区域,即未更新某些更改。临时区域的主要优势(除了隐含待添加区域的其他SCM的显式版本)正在处理CONFLICTED MERGE,我认为应该如何解释它。

git merge man page标识合并的1/2/3阶段元素,但显然没有详细说明为什么和为什么。

民间可以就任何关于git如何以及为什么设法达到其他人所没有的结果的文章提供建议(超过Wincent's blog中详述的Linus V Bram),即所谓的琐事部分?

大多数网络文章都假设合并“刚刚发生”,而我没有找到解释问题的任何内容(例如需要小提交,常见提交的价值等)。

2 个答案:

答案 0 :(得分:2)

这应该有助于至少你的一些问题,因为它是git最常见的合并:

git merge-file

  

git merge-file被设计为RCS合并的最小克隆;那   是,它实现了所需的所有RCS合并功能   GIT中(1)。

答案 1 :(得分:2)

大多数VCS都采用三向合并的基本概念。这比较了两个分支,每个分支都有一个共同的祖先,所以如果两个分支之间的代码行不同,你知道哪个分支改变了它。如果它们都改变了它,那么你就必须由人来解决合并冲突。

在少数情况下,很难确定合适的共同祖先。为此,许多研究都采用了不同的算法,其中很多涉及使用提交跟踪其他元数据。

Linus的基本创新是跟踪而不是文件。这是一种微妙的区别。要使用Wincent博客中的示例进行说明,请考虑分支foo中的文件A。你分支出来建立分支B。在分支A foo中,重命名为bar。在分支B中,它将被删除。然后,您尝试合并。

如果您正在跟踪文件,则如下所示:

在分支之前,创建了文件foo的版本1。

在下次提交之后,分支A指向foo的版本2(已删除的文件)和新文件bar的版本1。

在下一次提交之后,分支B指向foo的2.1版,这是一个已删除的文件。

合并时,foo的版本2和2.1进行比较,发现它们是相同的。那里没有合并冲突。分支B甚至没有名为bar的文件,因此也没有冲突。您最终会以静默方式接受分支A的重命名,即使被删除的foo与重命名之间存在真正的冲突。

如果您正在追踪树木,它会是这样的:

在分支之前,会创建一个带有哈希dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81的blob。创建一个树,其中包含指向散列的标签foo

在下次提交之后,分支A指向一个树,其中包含指向同一哈希的标签bar的条目。

在下次提交之后,分支B指向空树。

合并时,会比较树,B显示删除,A显示重命名blob8bd7a97ab39f4c156a1a96d4b10720a39fb81。人们被问到他更喜欢哪一个。

您可以通过添加重命名元数据来减轻文件跟踪VCS的影响,但git的方式使用其正常的标准数据结构。此外,元数据方式在复杂合并方面存在困难,其中共同祖先有许多可能的选择。你可以在共​​同的祖先和两个分支头之间放置十亿条可能的路径,git仍会看到一个具有相同哈希的blob,并且能够检测到重命名和删除。例如,在通过电子邮件接受补丁中的更改时,保存元数据也很困难。

重命名的文件同时发生变化会变得有点棘手,但通过跟踪树,git可以获得所需的所有信息。它看到blob dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81从两个分支都消失了,但它也看到一个新的树条目指向一个新的blob,并且可以比较这两个。如果文件的重要部分匹配,则认为是重命名。显然,如果你在重命名的文件中进行了大量的更改,这会发生故障,但在某些时候,没有合并算法可以帮助你。

请参阅Linus的this email,了解有关此主题的哲学的更多见解。