即使每个更改的文件都与其中一个父文件一致,如何“git show”合并差异输出的合并提交?

Posted

技术标签:

【中文标题】即使每个更改的文件都与其中一个父文件一致,如何“git show”合并差异输出的合并提交?【英文标题】:How to "git show" a merge commit with combined diff output even when every changed file agrees with one of the parents? 【发布时间】:2011-07-01 15:45:42 【问题描述】:

在进行“简单”合并(没有冲突)之后,git show 通常只显示类似

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

这是因为,对于合并,git show 使用组合差异格式,该格式会忽略与任一父版本一致的文件。

有没有办法强制 git 仍然显示组合差异模式中的所有差异?

执行git show -m 将显示差异(分别使用新版本和所有父版本之间的成对差异),但我更希望在各个列中使用 +/- 标记的差异,例如在组合模式下。

【问题讨论】:

@Tilman Vogel:请查看已接受的答案 - 看起来有更好的答案 @Jayan 虽然其他答案更受欢迎,因为它们包含有用的提示,但它们实际上并没有更接近我的问题,因为它们只是做双向差异。我正在寻找三向差异。 【参考方案1】:

查看提交信息:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

注意这条线:

Merge: fc17405 ee2de56

获取这两个提交 ID 并反转它们。所以为了得到你想要的差异,你会这样做:

git diff ee2de56...fc17405

只显示更改文件的名称:

git diff --name-only ee2de56..fc17405

要提取它们,您可以将其添加到您的 gitconfig:

exportfiles = !sh -c 'git diff $0 --name-only | "while read files; do mkdir -p \"$1/$(dirname $files)\"; cp -vf $files $1/$(dirname $files); done"'

然后通过这样做来使用它:

git exportfiles ee2de56..fc17405 /c/temp/myproject

【讨论】:

感谢您的建议,但我认为这并不能解决我的问题。由于评论标记和格式有限,我将我的评论添加到您的答案中。对不起!需要经过同行评审,直到可见。 看来,我的编辑被拒绝了。总之:您的差异不显示哪些添加来自哪个分支。而且您无法区分更改是在第二个分支中添加还是在第一个分支中删除。 更好的解决方案是git diff fc17405...ee2de56 - 这将显示 ee2de56 上的所有更改,这些更改可以从 fc17405 上的提交中获得,我相信这就是您想要的。注意 3 个点而不是两个点。 @KrisNuttycombe 3 点和顺序。而你的评论正是我想要的,我认为这更像是 OP 想要的。 @KrisNuttycombe 这在某种程度上不适用于git log,它仍然显示所有提交,例如.. 变体。 .....log 做同样的事情,但对于 diff 他们是不同的!?如何获取合并到此分支的提交列表?【参考方案2】:

更好的解决方案(@KrisNuttycombe 提到):

git diff fc17405...ee2de56

对于合并提交:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

显示ee2de56 上的所有更改,这些更改可从fc17405 上的提交中获得。注意提交哈希的顺序 - 它与合并信息中显示的相同:Merge: fc17405 ee2de56

还要注意三个点 ... 而不是两个

对于已更改文件的列表,您可以使用:

git diff fc17405...ee2de56 --name-only

【讨论】:

这正是我 +1 之后的样子。 这实际上显示了合并冲突的结果,而另一个答案没有。 这是不正确的。我不知道为什么它得到了这么多的支持。这将显示共同祖先和 ee2de56 之间的差异,无论其他分支或合并提交中发生什么。 (来自手册:"git diff A...B" is equivalent to "git diff $(git-merge-base A B) B."【参考方案3】:

您可以在合并前将 HEAD 设置为一个提交来创建分支。然后,你可以这样做:

git merge --squash testing

这将合并,但不会提交。那么:

git diff

【讨论】:

【参考方案4】:

如果您正在合并提交,那么这会显示差异:

git diff HEAD~1..HEAD

如果您不在合并提交中,则只需将 HEAD 替换为合并提交。这种方法似乎是最简单、最直观的方法。

【讨论】:

这不是“组合差异”输出。获取每对父母和 HEAD 之间的差异在这里不是问题。【参考方案5】:

似乎在这里回答: https://public-inbox.org/git/7vd392ezhx.fsf@alter.siamese.dyndns.org/

所以以类似的方式,运行

$ git diff --cc $M $M^1 $M^2 $(git merge-base $M^1 $M^2)

应该显示一个组合补丁来解释 $M 相对于 记录在其父级和合并基础中的状态。

【讨论】:

您知道是否可以配置任何工具以并排方式显示这样的差异,可能在几列中(例如在 IntelliJ 合并冲突解决窗口中)?你的答案正是我正在寻找的 @Max 不,恐怕我没有。谷歌搜索“n-way visual diff”确实提供了一些链接,所以我试过了。 这不会只在一次提交中显示文件,至少在第二次提交时是这样。我认为@hesham_EE 的解决方案是正确的。【参考方案6】:

我认为你只需要'git show -c $ref'。在 a8e4a59 上的 git 存储库上尝试此操作会显示组合差异(两列之一中的加/减字符)。正如 git-show 手册所提到的,它几乎委托给“git diff-tree”,所以这些选项看起来很有用。

【讨论】:

不,对于“简单”合并,git show -c $ref 显示的输出与我引用的相同,即没有差异。 -c 选择了一种组合差异模式,与合并提交的默认模式非常相似,即“--cc”,请参阅git help showgit help diff-tree。两者都完全省略了与该文件的任一父版本一致的文件。 a8e4a59 确实不属于合并提交的范畴,我的意思是。此合并提交确实包含一个与其父版本不同的文件。 Documentation/git-fast-import.txt 有一些东西是从一个父母那里添加的,一些是从另一个父母那里添加的。这会导致来自git diff-tree --cc 的非空输出。但是,仅显示了这种“冲突”情况下的变化。所有“干净”的合并结果,看git show -m a8e4a59,根本没有显示出来。 @TilmanVogel:感谢您指出git show -c 输出中忽略了“无趣”的文件合并。 (man git-diff-tree 确实说“此外,它只列出了所有父母修改过的文件。”但我当然没有发现这一点。)【参考方案7】:

如果您的合并提交是commit 0e1329e5,如上所述,您可以通过以下方式获取此合并中包含的差异:

git diff 0e1329e5^..0e1329e5

我希望这会有所帮助!

【讨论】:

【参考方案8】:

在你的情况下,你只需要

git diff HEAD^ HEAD^2

或者只是为你提交哈希:

git diff 0e1329e55^ 0e1329e55^2

【讨论】:

不,这只是在两个父母之间做了一个简单的双向差异。我要求的是一种模式,它可以同时显示 git merge-base HEAD^ HEAD^2HEAD^HEAD^2 之间的差异,其风格与与冲突合并的文件相同。【参考方案9】:

您可以使用带有 -c 标志的 diff-tree 命令。此命令显示合并提交中更改了哪些文件。

git diff-tree -c merged_commit_sha

我从Git-Scm 得到了 -c 标志的描述:

这个标志改变了合并提交的显示方式(这意味着它 仅当给定命令时才有用,或 --stdin)。 它显示了每个父母对合并结果的差异 同时,而不是显示父母和之间的成对差异 一次一个结果(这就是 -m 选项的作用)。 此外,它仅列出所有父级修改过的文件。

【讨论】:

看起来是一篇关于这个主题的好文章:haacked.com/archive/2014/02/21/reviewing-merge-commits,也许这也是:longair.net/blog/2009/04/16/git-fetch-and-merge【参考方案10】:

我构建了一种通用方法来对合并的提交执行各种操作。

第一步:通过编辑~/.gitconfig为git添加别名:

[alias]
  range = "!. ~/.githelpers && run_on_merge_range"

第二步:在~/.githelpers中,定义一个bash函数:

run_on_merge_range() 
  cmd=$1; shift
  commit=$1; shift
  range=$(git show $commit | grep Merge: | awk 'print $2 "..." $3')
  echo "git $cmd $range $@"
  if [ -z $range ]; then
    echo "No merge detected"
    exit 1
  fi
  git $cmd $range $@

第三步:盈利!

git range log <merge SHA> --oneline
git range diff <merge SHA> --reverse -p
git range diff <merge SHA> --name-only

这里可能有很大的改进空间,我只是把它放在一起来克服一个恼人的情况。随意模拟我的 bash 语法和/或逻辑。

【讨论】:

请注意,您可能需要将“awk”位中的“...”更改为“..”,具体取决于您需要什么以及正在运行的命令:***.com/questions/462974/…跨度> 【参考方案11】:

不,git show 无法做到这一点。但有时肯定会很好,而且在 git 源代码中实现可能相对容易(毕竟,你只需要告诉它修剪掉它认为无关的输出) ,所以这样做的补丁可能会被 git 维护者接受。

不过,要小心你的愿望;将一个分支与三个月前分叉的单行更改合并,与主线相比仍然会有 巨大 差异,因此这样一个完整的差异几乎完全没有帮助。这就是 git 不显示它的原因。

【讨论】:

请不要说“没办法做到这一点”,因为这是可能的——请参阅其他答案。这么说是很误导人的。 git show HEAD^...HEAD; # 每个@hesham_EE 的解决方案。 git show HEAD~1...HEAD~0 --name-only; # 更好的语法。用于迭代 pr。

以上是关于即使每个更改的文件都与其中一个父文件一致,如何“git show”合并差异输出的合并提交?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Ansible中比较多个文件

存储库和工作单元模式 - 如何保存更改

即使没有任何更改,Android 多模块 Gradle 构建也很慢

即使父节点在移动,如何在屏幕上给每个节点相同的起始位置?

UIStackView:基于所有子视图的一致高度,即使它们丢失

matlab如何批量更改文件名(删除每个文件名中的一段相同的字符串)