Git:查看自上次合并冲突后其分支上的更改

Git:查看自上次合并冲突后其分支上的更改,git,git-merge,Git,Git Merge,我认为我的情况应该相当普遍,必须有一种更简单的方法来做我所做的事情。假设有两个分支,current和next,用于两条开发线下一步在此阶段接收来自当前分支的所有更改。作为next分支的维护者,我正在同步更改(对于alpha版本是必要的),如下所示: $ git co origin/next -b next $ git merge origin/current 某些文件在下一个上更改了格式,自上次同步合并以来对这几个文件所做的每一次更改都会导致冲突。要解决此冲突,我需要查看自上次合并以来当前分支

我认为我的情况应该相当普遍,必须有一种更简单的方法来做我所做的事情。假设有两个分支,
current
next
,用于两条开发线<代码>下一步在此阶段接收来自
当前
分支的所有更改。作为
next
分支的维护者,我正在同步更改(对于alpha版本是必要的),如下所示:

$ git co origin/next -b next
$ git merge origin/current
某些文件在下一个上更改了格式,自上次同步合并以来对这几个文件所做的每一次更改都会导致冲突。要解决此冲突,我需要查看自上次合并以来当前分支上的更改。通常很多文件都已更改,但只有1或2个像我提到的文件是冲突的

例子 假设
current
分支上的文件
baz.dat
包含方括号中的单词,如

[real]
[programmers]
[use]
[pascal]
next
分支上,语法更改要求用冒号代替单词

:real:
:programmers:
:use:
:pascal:
当前分支上的更改在文件中添加了一行:

[real]
[programmers]
[don't]
[use]
[pascal]
每次合并冲突都会导致以下差异合并标记:

<<<<<<< ours
:real:
:programmers:
:use:
:pascal:
=======
[real]
[programmers]
[don't]
[use]
[pascal]
>>>>>>>> theirs
我在找什么 查看自上次合并以来,
当前
(“其”)分支上发生的更改的方法,以便我可以手动将更改合并到下一个
(“我们”)分支中

而diff只会将冲突文件的更改显示为合并基础和合并点之间的增量(在理想情况下,我会进一步限制,例如
--magic switch--theres


这样一个神奇的开关存在吗?看来我错过了一些明显的东西

git mergetool
将在您选择的diff编辑器(meld、vimdiff、kdiff3、winmerge…)中逐个打开冲突文件,作为3个版本之间的3路合并:

  • local
    :当前分支中的版本(在您的情况下:
    next
    的版本)
  • base
    :合并基提交中的版本
  • remote
    :合并分支中的版本(在您的情况下:
    origin/current
    的版本)
如果您编辑并保存中心文件,git会将此冲突标记为已解决,这是您保存在索引中的一个阶段


如果合并由于冲突而停止,
git
会在
.git/merge\u HEAD
中存储对合并提交的引用。这意味着您可以在git命令中将字符串
“MERGE\u HEAD”
用作有效的引用:

git log -1 MERGE_HEAD            # view last commit on the merged branch
git merge-base MERGE_HEAD HEAD   # no need for the name of the branch
然后,您可以构建一个更简单的别名:

theirs = 'git diff $(git merge-base MERGE_HEAD HEAD) MERGE_HEAD'
# usage :
git theirs                  # complete diff between 'base' and 'theirs'
git theirs -w -- this/file  # you can add any option you would pass to 'git diff'

啊,有了这个例子,我们可以有所作为

这不是Git内置的,因为它通常是一个非常困难的问题。但是,如果我们对它进行某种限制,我们可以编写一个脚本、工具或过程来处理它(事实证明,这一部分是内置在Git中的!…嗯,有点)。让我们看看是否可以描述这些约束:

  • 这是一个标准的三方合并,有一个标准的修改冲突,因此有一个基本版本(第1阶段)、一个本地/头/
    ——我们的版本(第2阶段)和一个远程/其他/
    ——他们的版本(第3阶段)

  • 合并的一个“方面”涉及每一行,但以重复和可识别的模式,我们可以暂时退出。(让我们给这个更改起个名字:让我们简称它为“系统增量”或SD,+SD表示添加或保留此增量,-SD表示撤消/删除它。SD可能是一个不可逆的更改,即-SD可能无法完全撤消它;如果是这样,我们可能仍然能够自动处理它。)它可能还有一些额外的更改,也可能没有,对基地

  • 合并的另一面只涉及几行,甚至没有几行,并且缺少重复和可识别的模式更改,我们可以添加到其中,可能是暂时的

我们有几个额外的问题和决定要考虑,也许是在一个特例逐案的基础上,或者可能是系统的。它们将影响我们编写脚本、工具或过程的方式。这些是:

  • SD实际上是可逆的吗?也就是说,一旦我们发现了SD,base+SD-SD会复制原始的base吗
  • 我们想要结果中的SD吗
  • 我们能检测到SD的存在吗?(我们可能不需要这样做,但如果可以的话,我们会觉得很方便。)
如果SD是可逆的,我们就处于良好状态,因为我们可以得到任何我们喜欢的结果。如果没有,我们将不得不将SD应用于缺少它的任何一方:当且仅当我们希望SD出现在结果中时,这是可以的

现在让我们假设结果中需要+SD。在本例中,我们的状态非常好:让我们将应用SD的过程称为“规范化”文件。或者,如果我们想在结果中使用-SD,并且SD是可逆的,那么我们将doing-SD称为“规范化”。此外,如果我们可以判断一个文件是否应用了SD,我们可以编写一个“normalizer过滤器”,并通过该过滤器运行所有内容

这就是Git的内置功能:它有“干净”和“污迹”过滤器,如中所述。此外,在进行合并之前,我们可以指示
git merge
在每个文件上运行两个过滤器(两个过滤器都可以,但我们可以使它们都“正常化”,或者保留一个未设置的过滤器,这是我们的特殊目的)。因为“规范化”给了我们想要的最终形式,它让Git完成了我们想要的合并

如果SD是不可逆的,我们需要更聪明,但只要我们希望结果中有+SD,我们仍然可以。我们可以编写自己的合并驱动程序,而不是使用。这也记录在同一手册中(进一步)。我不会在这里详细介绍,因为清理/污迹过滤方法更容易,并且可能适用于您的案例,但其本质是我们提取三个阶段,将+SD应用于需要它的任何阶段(通过测试或先验知识选择“需要它的文件”),然后
$ git status 
. . . .
      both modified:   foo/bar/baz.dat <== copy/paste every conflict filename
$ git diff `git merge-base HEAD origin/current`..origin/current -- foo/bar/baz.dat
(next)$ git merge origin/current
. . . 
CONFLICT (content): foo/bar/baz.dat
(next|MERGING)$ git diff --magic-switch
git log -1 MERGE_HEAD            # view last commit on the merged branch
git merge-base MERGE_HEAD HEAD   # no need for the name of the branch
theirs = 'git diff $(git merge-base MERGE_HEAD HEAD) MERGE_HEAD'
# usage :
git theirs                  # complete diff between 'base' and 'theirs'
git theirs -w -- this/file  # you can add any option you would pass to 'git diff'