使用git和meld进行交互式重定基的三向合并中的三个文件是什么



假设我用git rebase -i进行了一次交互式重基。如果出现冲突,我可能会遇到合并冲突,并被要求进行3路合并。使用meld,我看到了三个窗口:LOCAL(左)、???(中)和REMOTE(右)。这里所说的???只是指meld没有提供一些特殊的名称来附加到文件中。

在正常的合并过程中,这是有意义的,因为中间是共同的祖先,并且您正在合并该祖先的本地和远程更改。然而,在交互式重新基准期间,情况似乎并非如此——不清楚每个文件代表什么。

三向合并中的这些文件在交互重定基准期间分别代表什么?编辑这些文件时,我的目标是什么?

更新:基于我看到的评论和实验:

  • Left(LOCAL):在提交-回放序列中,此时文件的本地版本
  • Right(REMOTE):最初应用当前提交之后的文件状态
  • Middle:原始提交序列中权限的父级

因此,我的任务是确定从中间到右边的增量,然后将该增量应用于左边。Middle应该反映在新提交序列中应用当前提交增量之后文件的状态。

请注意,至少在某种程度上,这种配置似乎是熔化物特有的。Git的3向合并行为可能与其他编辑器不同。

中间版本是合并基础,就像git merge一样。

(名称"other"可能比"remote"更合适,因为没有要求合并的另一端是远程的,而且Mercurial一直使用名称"other",这并不是说Git需要匹配Mercurial,但一些一致性可能很好。请注意,Git在这里也使用名称"ours"one_answers"their",所以我们永远不会从Git获得100%的一致性。:-)

但是等等,怎么会有合并基础呢

总是有合并基。

通常我们甚至不必找到它,因为当将每个补丁作为补丁处理时(不尝试三方合并),它都会干净地应用。但有时补丁不会干净地应用,我们确实不得不回到三方合并。

(顺便说一句,您可以禁用此回退。请参阅git-am文档中的--3way--no-3wayam.threeWay,尽管由于这些控件最近发生了更改,此处链接的页面已经过期。)

$ git rebase -i
pick aaaaaaa first commit
pick bbbbbbb second commit
pick ccccccc third commit

让我们也画一个提交图,这样我们就可以看到我们从到的基础

              A - B - C   <-- branch
            /
... - o - *
            
              G - H       <-- origin/branch

我们将挑选提交ABCA=aaaaaaa等),以便最终得到以下结果:

              A - B - C   [abandoned]
            /
... - o - *           A' - B' - C'   <-- branch
                   /
              G - H       <-- origin/branch

让我们仔细看看A的第一个樱桃。

这将(diffs)A与其父级(即提交*)进行比较,并尝试将得到的diff应用于提交H

然而,提交H与提交*有些偏离。事实上,我们可以在AH之间找到一个合并基,它是。。。提交*。这实际上是一个相当不错的合并基础,尽管最好Git可以按原样应用补丁,而不必退回到三方合并代码。

因此,当在H上选取A时,提交*是合并的基础。合并完成后,我们得到新的提交A'。(例如,它的新SHA-1 ID可能是aaaaaa1。可能不是;我们就叫它A'。)

现在我们来挑选B。这使B与其父级A发生差异,并尝试将差异应用于A'

然而,提交A'与提交B有些偏离。事实上,我们可以在BA'之间找到一个合并基,即。。。再次提交*。不幸的是,这是一个糟糕的合并基地。幸运的是,只有当补丁不能按原样应用时,Git才会依赖它,而且通常情况下它可以。但如果不能,Git将区分*B以及*A',并尝试合并这两个差异。请注意,*B包含了我们在A中所做的所有更改,但*A'也包含了所有相同的A更改,所以如果幸运的话,Git会注意到已经包含的更改,并且不会重复它们编辑Git作弊。(该代码最近在2.6版本中发生了更改,尽管总体策略保持不变。)

当仅用于显示从提交A到提交B的更改时,请考虑git diff的实际输出。这包括一条index线路:

diff --git a/foo b/foo
index f0b98f8..0ea3286 100644

左边的值是提交A中文件foo版本的(缩写)哈希。右边的值是提交B中文件版本的哈希。

Git只是从左侧散列中伪造一个合并基。换句话说,提交A中的文件版本成为伪造的合并基础。(Git将--build-fake-ancestor传递到git apply。这要求特定的文件blob对象在存储库中,但由于它们在提交A中,所以它们是在存储库。对于通过电子邮件发送的修补程序,Git使用相同的代码,但blob可能存在,也可能不存在。)

请注意,Git在挑选提交A时也会这样做,但这次的合并基础文件是提交*的版本,它实际上是合并基础。

最后,我们精心挑选了C。这与BC的差异,正如我们上次与AB的差异一样。如果我们能按原样使用补丁,那就太好了;如果没有,我们将返回,再次使用commit *作为合并基础。这又是一个相当糟糕的合并基地 和以前一样,假装B中的版本是公共基础。

顺便说一句,这也解释了为什么对于这些rebase,你会一次又一次地看到相同的合并冲突:我们每次都使用相同的合并base。(启用git rerere会有所帮助。)

合并和重基在这方面是相同的。合并和rebase之间的唯一区别是,有了rebase,历史看起来更好(更线性)。但是,对于即将出现的和你必须解决的冲突,它们是一样的。

相关内容

最新更新