【问题标题】:Is there a 4 views merge?是否有 4 个视图合并?
【发布时间】:2025-12-21 16:25:16
【问题描述】:

大多数工具执行 3 个视图:

  1. 本地
  2. base-vs-remote-vs-local
  3. 远程

问题在于,中间的基本视图试图突出显示来自本地和远程的变化,如果这些变化很大,它们会重叠很多,使其基本视图不可读。

所以我的问题是:

有没有办法使用 4 视图模式合并文件:

  1. 本地
  2. 基础与本地
  3. base-vs-remote
  4. 远程

那么base-vs-local和base-vs-remote各有各的看法?

【问题讨论】:

  • 扮演魔鬼代言人,这对你有什么用?如果你分别解决 base-local 和 base-remote 的变化,那么当你完成合并时不会还有冲突吗?
  • 单独拥有base-local,我可以清楚地看到什么需要移动到远程。拥有 base-remote 后,我可以在遥控器中看到 where 他们需要移动到的位置。
  • 我没有单独解决它们,你从哪里得到的?我正在查看 base-vs-remote 和 base-vs-local,而不是一个 base-vs-both。它是如何分开的?

标签: git merge diff


【解决方案1】:

我不知道有任何工具可以在一个大共享视图中执行此操作(我一开始不喜欢大共享视图),但您可以从命令行非常轻松地手动完成。

我们来看一个典型案例:

$ git fetch
...
   1234567..fedcba9  feature/foo -> origin/feature/foo
...
$ git status
On branch feature/foo
Your branch and 'origin/feature/foo' have diverged,
and have 123 and 321 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working directory clean

呃,需要大合并或变基,差异时间。让我们看看他们在合并基地后做了什么:

$ git diff feature/foo...origin/feature/foo

...以及自合并基础以来我所做的事情:

$ git diff origin/feature/foo...feature/foo

这里有几件重要的事情需要注意:

  • 三点语法A...B。通常——即,当不使用git diff 时——这个语法意味着你运行的任何 Git 命令都使用git rev-list(或者直接调用它的修订解析器代码,如果它在 C 中)并且得到 对称差异 一组提交:可以从A B 访问的每个提交,但没有可以从A B 访问的提交.对于具有单个合并基础的典型分支名称对,这是分支点任一“侧”上的所有提交,不包括合并基础本身和所有早期提交。图形化:

                  A1 - A2 - A3   <-- A
                /
    ... - o - *
                \
                  B1 - B2        <-- B
    

    在这种情况下,总共有五个选定的提交,三个在A 分支上,两个在B 分支上。标记为* 的提交是合并基础,它和之前的所有提交(如* 之前的o)都在两个分支上。

  • 此语法不特定于远程跟踪分支,也不特定于本地分支。它适用于标识提交的任何对标识符:分支名称、标签名称、HEAD~10 等。它只是做一个图操作,计算几个中间集来找到对称差:

          SA = 祖先(A)
    SB = 祖先(B)
    S普通 = SA AND SB

          结果 = (SA OR SB) - S普通

    注意——假设只有一个合并基——两个分支的合并基是公共子集中最新的(图中最右边)提交S常见。如果(在某些复杂的 DAG 中就是这种情况)存在 多个 合并基,则它们在 Scommon 中是 all 并因此从对称差分结果中删除 all(这通常是我们想要的,但见下文)。

  • 对于git rev-list 或其客户端,我们通常想知道提交来自哪个“侧”,因此有--left-right,它标记了它们。另请参阅--cherry-mark--left-only--right-only--cherry-pick 等。

git diff 使用合并基础

但是,对于git diff,三点语法被盗用于不同的目的。它不是计算对称差异,而是选择合并基础:在我们的绘图中标记为 * 的提交。

diff 命令集只会比较两个项目(两个提交,一个提交和工作树,一个提交和索引,等等)。三点对称差分语法主要用于获取两个(通常很大)提交列表,SA-ScommonSB-Scommon。我们可以将此类列表提供给git log -p,这在检查大型合并或变基集时可能会有所帮助(如在原始问题中),例如,当我们想要隔离为什么发生某些特定更改时.不过,对于git diff,我们只是比较两个特定的提交

比较明显的两个是A 的合并基和尖端(合并的一侧),以及B 的合并基和尖端(合并的另一侧)。这就是三点语法在这里的作用:找到合并基,然后与右边的项目进行比较。因此git diff B...A 将合并基础提交(AB)与(提示提交)A 进行比较。由于BA 的合并基础与AB 的合并基础相同,git diff B...A 将同一提交与B 的(提示)进行比较。

当有一个合并基础时,结果效果最好。对于具有多个合并基础的复杂 DAG,您只需以明显随机的方式选择一个。 (recursive 合并策略选择所有这些合并基并首先合并它们,然后将生成的树与两个分支提示合并。其他 Git 命令,包括 git diffgit merge-base,一般只是选择从合并基查找算法中弹出的第一个。1 多个合并基并不常见,理想情况下,当它们确实发生时,它们都具有相同的树,因此没有一个这很重要,但值得牢记。)


1我在写这篇文章时突然想到,没有正式保证为A...B 选择的合并基础与为B...A 选择的合并基础相同。我认为我们得到相同的合并基础,当有多个候选时,但如果算法对我们输入两个提示提交的顺序敏感,我们可以想象选择两个不同的 /em> 提交,当合并基集包含多个时。最终,我将不得不去看看代码,但现在我没有足够的时间......

【讨论】: