比较Git中rebase之间的差异



假设我刚刚将分支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作为补丁发生的所有更改,这正是我想要检查的最小值。然而,调用是复杂的,并且输出的解释并不完全简单。

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

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

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

当重新基准需要解决合并冲突时,比较更改之后由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输出的提交头一样,第三行将旧提交涂成红色,新提交一个是绿色的,其余的类似于git show的提交头。


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

请参阅Stefan Beller(stefanbeller)的提交2543a64、提交8d5ccb5、提交7648b79(2018年8月17日)和提交4441067、提交f103a6f、提交29ef759、提交017ac45、提交9d1e16b、提交84120cc、提交c5e64ca、提交991eb4f(2018年08月14日)
(由Junio C Hamano合并——gitster——提交30035d1,2018年9月17日)

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

当涉及到的特殊行时,范围差异着色有点模糊diff,例如用+++---指示新文件和旧文件会拾取第一个字符并根据其颜色进行解释看起来很烦人,就像在常规diffs中一样,这些行通过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更改的行将被视为外部和内部diff中的上下文,以便这些行保持不变常规颜色。

我们真正想要展示的是冲突组合的diff,它就像我们从(a)到(b)进行了合并一样生成,其中(a)以前基于(上游旧),(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"显示结果,这将生成一个组合的diff格式,显示所有必要的位作为冲突解决方案,它会自动忽略实际上不是解决冲突的一部分的更改。

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

不幸的是,我还没能弄清楚如何在不生成树的情况下,以同样的方式将"git-diff"转换为diff。我不确定我们必须通过哪些论点才能达到这一点。

git-cherry在一个分支上搜索不在另一个分支的提交。你会用它作为:

git cherry -v OLDTIP TIP UPSTREAM

即查找在CCD_ 24上但不在UPSTREAM..TIP上的提交。它会查看补丁签名,以查看是否包含补丁,因此,如果在重新基础期间添加、删除或修改了补丁,则它将显示在列表中。没有更改的应用程序将不会出现。

返回OLDTIP并执行git rebase -i TIP可以获得类似的效果,因为这使用相同的逻辑来填充提交列表。

主foo:和重基foo:之间的差异

git diff master..foo

与。

分支出master后预重基准foo的差异(注意三点):

git diff master...foo@{1}

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

我认为你可以做以下事情(假设你还没有做git gc):

在重新基准后的分支foo上:

$ git reflog

这将显示分支的头是如何移动的。你应该看到一些这样的记录(取决于你是否以交互方式重新基准):

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在合并前的最后一次提交。根据你所做的,这可能很困难,也可能不困难。这就是为什么我没有提供一个做它的脚本。

获取在重新基准之前最后一次提交foo的提交id,然后与该提交id进行比较。假设提交id为:XXXX:

git diff XXXX...foo

也许这就是你想要的。

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

有几种方法可以利用这种支持来重新建立基础:

选项1:

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

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

选项2(如果重新定基比合并更容易):

  1. 重新设置基准
  2. 使用移植使其看起来像是本地/临时合并

要做到这一点,请用一行创建一个.git/info/移植物:

TIP UPSTREAM OLDTIP

其中TIP是重新建立基础的分支的提交ID,其他是两个所需的父级(即,如果您正在进行合并,您将合并的两个内容)。然后将其视为真正的合并进行检查。

我不确定是否要将其自动化;我倾向于用gitk open来做这些事情,因为它可以很容易地比较正确的修订(使用右键菜单)。

如果你真的想比较两个diff,那么你可能想看看interff(1),但我不确定它能在多大程度上处理不同的基本文件。

最新更新