31

有没有办法查看已经在 3-way diff 中提交的合并?

如果在 3 周前提交了分支之间的巨大合并,有什么方法可以在BeyondCompare3 等外部差异工具中看到它的 3 路差异?我正在寻找合并提交中更改的文件。如果我可以让它只显示冲突和手动更改的任何内容,而不是查看两个分支之间文件的全部差异,则奖励。

如果左侧有 <<<<< ===== >>>>> 冲突标记,而右侧是提交的结果,我不介意解决 2 路差异。

我尝试查看diff-treediff-filesdiffdifftoolshow等,但无法弄清楚。我知道 gitk 只会在合并提交中显示更改,但我不喜欢上下差异视图,当有大量更改时很难理解。

如果我能做类似的事情git difftool --cc firstparent..secondparent..result

4

3 回答 3

7

更新的答案:我下面脚本的原始版本是有缺陷的,$conflicting_files事实上它不仅包含真正有冲突的文件,还包含在两个父分支中更改的所有文件(但不一定有冲突)。此外,它没有使用基本原理中宣传的“配置的合并工具”,而是diffuse. 我已经在当前版本的脚本中解决了这两个问题。

原始答案: 假设我们有一个“master”分支,主要开发正在进行中,还有一个“topic”分支,它在 master 的某些(旧)状态之上添加了一些功能。通过说您只是在寻找合并提交中更改的文件,我假设您只对合并提交中引入“主”的更改“主题”感兴趣(包括任何冲突解决),而不是非自“主题”分支以来在“主”中完成的冲突更改。进一步假设“master”是合并提交的第一个父级,“topic”是第二个父级,这可以通过

git difftool <merge commit>^1 <merge commit>

请注意,在这里使用 3-way diff 是没有意义的,因为我们正在查看包含任何冲突解决的状态。这也是 GitHub 为合并提交显示的内容,顺便说一下,请参阅我用于测试的这个合并提交。

为了在 3-way diff 工具中只查看冲突文件及其分辨率,我想出了这个脚本

#!/bin/sh

if [ $# -ne 1 ]; then
    echo "Rationale : Show the conflict resolution of a given merge commit in the configured merge tool."
    echo "Usage : $(basename $0) <merge commit>"
    exit -1
fi

# Test e.g. with https://github.com/git/git/commit/8cde60210dd01f23d89d9eb8b6f08fb9ef3a11b8
our=$1^1
their=$1^2
base=$(git merge-base $our $their)

conflicting_files=$(git merge-tree $base $our $their | grep -A 3 "changed in both" | grep "base" | grep -Po "[^\s]+$")
for f in $conflicting_files; do
    diffuse -r $our -r $base -r $their $f
done

我使用的是Diffuse而不是Beyond Compare,因为第一个可以直接处理 Git 提交而不是本地文件;根据您的喜好更改参数的顺序。要使用 BC,您可能需要进行临时结帐;我也在考虑重做合并,应用已知的分辨率,并运行任何git mergetool配置过的东西,但是这两个想法都需要更多的工作才能不弄乱你的工作树并正确地进行清理。

于 2012-07-06T15:20:29.483 回答
2

我不知道如何在没有一些hackery的情况下在git中进行三向差异,但是对于双向差异我会使用meld. meld如果您签出项目的三个不同版本,按目录执行新的差异并选择“三向比较”选项,则能够进行三向比较。

首先安装融合

sudo apt-get install meld

然后将 meld 设置为 difftool

git config --global diff.tool meld

找到提交

git log | more

打开提交

git difftool <old-version>..HEAD

于 2012-06-19T01:48:35.443 回答
0

像 sschuberth 一样,我编写了一个脚本来帮助我找到合并提交中的更改。它使用 vimdiff 一次处理一个文件来显示父级和合并提交之间的差异。

#! /usr/bin/env ruby

require 'pp'
require 'tmpdir'

merge = ARGV[0] || abort("I need a merge commit as the first argument")
file = ARGV[1] || abort("I need a path as the second argument")
cmd = "vimdiff"

commits = `git log -n 1 #{merge} --format="%H %P"`.split(' ')
abort "expected three commits" unless commits.size == 3
commits[0], commits[1] = commits[1], commits[0]
tmpdir = Dir.mktmpdir
commits.each do |commit|
  tfile = "#{tmpdir}/#{commit[0..10]}"

  puts "git show #{commit}:./#{file} > #{tfile}"
  `git show #{commit}:./#{file} > #{tfile}`
  cmd += " #{tfile}"
end
puts cmd
exec(cmd)

它有点骇人听闻,但我发布它是因为它可以帮助某人。

于 2014-12-05T22:32:00.773 回答