40

假设我只是foo在 , 上重新建立了分支master,有冲突。我想确保我没有foo在解决冲突期间通过引入额外的更改或丢失更改(不适合解决冲突的更改)意外损坏内容。我通过以下方式做到了这一点:

diff -u <(git diff `git merge-base master foo@{1}` foo@{1}) \
        <(git diff `git merge-base master foo    ` foo    )

(更新:或我刚刚被提醒的等效...语法:)git-diff

diff -u <(git diff master...foo@{1}) <(git diff master...foo) | mate

master..foo这向我展示了所有被视为补丁的更改,这正是我想要检查的最小化。但是,调用很复杂,并且输出并不完全易于解释。

有没有更好的方法来完成这项任务——提供相同的信息,但使用更好的方法或格式——或者我应该把上面的内容封装在一个脚本中?

4

6 回答 6

8

我们真正想要展示的是冲突组合差异,它产生的好像我们已经完成了从 (a) 到 (b) 的合并,其中 (a) 以前基于 (upstream-old) 而 (b) 现在是基于(上游新)。

我们不想要一个直接的差异。

相反,我们基本上可以进行合并,但强制生成的树为 $b^{tree} ,我们已经知道这是我们想要的正确“结束”点。

或多或少,让我们假设我们有

newcommit -> the new version of the series
oldcommit -> the old version of the series
upstream -> the (new) version of the base of the series

我们可以通过生成合并

git commit-tree newcommit^{tree} -p oldcommit -p upstream -m "message"

然后使用“git show”显示结果,这将生成一个组合的差异格式,将所有必要的位显示为冲突解决方案,它会自动忽略实际上不是解决冲突的一部分的更改。

这甚至也适用于简单地修改更改,您可以做更多的工作来确保生成的合并提交具有准确的作者和提交时间戳,以便在多次调用中保持一致(因为我们松散的 ref 存储到对象中数据库)。

不幸的是,我还没有弄清楚如何在不实际生成树的情况下让“git diff”以相同的方式进行差异化。我不确定我们必须通过什么论据才能达到这一点。

于 2016-10-21T18:47:44.837 回答
7

甚至更好interdiff,现在有了 Git 2.19(2018 年第三季度),您拥有git range-diff.
请参阅“ Git diff - 两个不相交的修订范围

git range-diff文档包括以下示例

当 rebase 需要解决合并冲突时,使用以下命令直接比较 rebase 引入的更改

$ git range-diff @{u} @{1} @

的典型输出git range-diff如下所示:

------------
-:  ------- > 1:  0ddba11 Prepare for the inevitable!
1:  c0debee = 2:  cab005e Add a helpful message at the start
2:  f00dbal ! 3:  decafe1 Describe a bug
    @@ -1,3 +1,3 @@
     Author: A U Thor <author@example.com>

    -TODO: Describe a bug
    +Describe a bug
    @@ -324,5 +324,6
      This is expected.

    -+What is unexpected is that it will also crash.
    ++Unexpectedly, it also crashes. This is a bug, and the jury is
    ++still out there how to fix it best. See ticket #314 for details.

    Contact
3:  bedead < -:  ------- TO-UNDO
------------

在此示例中,有 3 个旧提交和 3 个新提交,其中开发人员:

  • 删除了第 3 个,
  • 在前两个之前添加了一个新的,并且
  • 修改了第二次提交的提交消息及其差异。

当输出到终端时,默认情况下它是彩色编码的,就像常规git diff的输出一样。另外,第一行(添加一个提交)是绿色,最后一行(删除一个提交)是红色,第二行(完美匹配)是黄色的,就像git show's output 的提交头一样,第三行颜色旧的提交是红色的,新的提交是绿色的,其余的就像git show's 提交头。


使用 Git 2.20,新类型的(范围)差异更好地支持颜色

请参阅提交 2543a64提交 8d5ccb5提交 7648b79(2018 年 8 月 17 日)和提交 4441067 提交f103a6f提交 29ef759提交 017ac45提交 9d1e1​​6b提交 84120cc提交 c5e64ca提交 991eb4f(8 月 14日(由Junio C Hamano 合并 -- --提交 30035d1中,2018 年 9 月 17 日)stefanbeller
gitster

range-diff: 缩进特殊行作为上下文

+++当涉及到差异的特殊行时,范围差异着色有点模糊,例如用and指示新旧文件---,因为它会拾取第一个字符并解释它的颜色,这在常规差异中看起来很烦人, 这些行通过 . 以粗体显示 DIFF_METAINFO

通过用空格缩进这些行,它们将被视为更有用的上下文,范围差异系列本身的示例:

git range-diff pr-1/dscho/branch-diff-v3...pr-1/dscho/branch-diff-v4

(来自存储库github.com/gitgitgadget/git

[...]
    + diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt
    + new file mode 100644
    + --- /dev/null
    + +++ b/Documentation/git-range-diff.txt
    +@@
    ++git-range-diff(1)
[...]
    +
      diff --git a/Makefile b/Makefile
      --- a/Makefile
      +++ b/Makefile
[...]

为手册页介绍新文件的第一行将带有“ +”符号,该行的其余部分将是粗体。

后面指示更改的Makefile行将被视为外部和内部差异中的上下文,以便这些行保持常规颜色。

于 2018-08-21T21:06:47.520 回答
3

git-cherry在一个分支上搜索不在另一个分支上的提交。您可以将其用作:

git cherry -v OLDTIP TIP UPSTREAM

即查找已打开OLDTIP但未打开的提交UPSTREAM..TIP。它查看补丁签名以查看是否包含补丁,因此如果在 rebase 期间添加、删除或修改了补丁,那么它将显示在列表中。不会出现未经更改而应用的内容。

回到OLDTIPdoing可以达到类似的效果git rebase -i TIP,因为它使用相同的逻辑来填充提交列表。

于 2012-09-26T16:10:51.780 回答
2

由于它是变基而不是合并,因此您可能希望foo在合并之前与自身进行比较。如果我没记错的话,foo@{1}将产生当前提交的父级foo,也许这不是你要找的。

我认为您可以执行以下操作(假设您尚未完成 a git gc):

在变基后的分支foo上:

$ git reflog

这将显示您的分支的 HEAD 是如何移动的。您应该会看到一些这样的记录(取决于您是否以交互方式变基):

64d3c9e HEAD@{15}: rebase -i (finish): returning to refs/heads/master
64d3c9e HEAD@{16}: rebase -i (fixup): Fixes external dependencies
049169e HEAD@{17}: rebase -i (fixup): updating HEAD
d4c2e69 HEAD@{18}: rebase -i (pick): Fixes external dependencies
049169e HEAD@{19}: rebase -i (fixup): Imports futures
e490bed HEAD@{20}: rebase -i (fixup): updating HEAD
...
etc
...

期待foo合并前的最后一次提交。根据您所做的,这可能会很困难,也可能不会。这就是为什么我没有提供一个 do-it 脚本的原因。

选取在变基之前具有最后一次提交的提交 id,foo然后与该提交 id 进行比较。假设提交 id 是: XXXX:

 git diff XXXX...foo

也许这就是你想要的。

于 2012-09-24T20:33:45.893 回答
2

master 和 rebase foo 的区别:

git diff master..foo

对比

分支 master 后 pre-rebase foo 的差异(注意三个点):

git diff master...foo@{1}

?

于 2012-09-20T13:16:59.570 回答
1

稍微不同的方法:Git 很好地支持在合并的情况下显示这一点。即“相对于 parent-1 发生了什么变化,而 parent-2 无法解释?”

有几种方法可以利用这种支持来支持你的 rebase:

选项1:

  1. 首先进行一次性合并(而不是变基)。然后正常的合并显示将显示合并更改的内容。检查这是你想要的。

  2. 返回并重新设置基准,并将重新设置的提示与合并结果进行比较——它们应该是相同的。

选项 2(如果变基比合并更容易):

  1. 做rebase。
  2. 使用移植使其看起来像本地/临时合并。

为此,请使用一行创建一个 .git/info/grafts:

TIP UPSTREAM OLDTIP

其中 TIP 是您的 rebase 分支的提交 ID,其他是两个所需的父级(即,如果您进行合并,您将合并的两件事)。然后检查它,就好像它是一个真正的合并一样。

我不确定是否将其自动化;我倾向于在打开 gitk 的情况下做这些事情,因为它使比较正确的修订变得容易(使用右键菜单)。

如果您真的想比较两个差异,那么您可能想查看 interdiff(1),但我不确定它在处理不同的基本文件时的效果如何。

于 2012-09-26T12:45:04.653 回答