git difftool $BASE 和 $LOCAL 颠倒了

git difftool $BASE and $LOCAL are reversed

我用 --no-commit 将一个功能分支合并到 master 中。在执行 git diff 时,我看到了正确的更改:功能分支中添加了一些行。使用 git difftool 时,我得到相反的结果。该工具显示新行已经存在并且不再存在。

我检查了 git 配置,实际上 $BASE 指的是更改,$LOCAL 指的是原始版本。

[difftool "p4merge"]
path = C:\Program Files\Perforce\p4merge.exe
cmd = p4merge.exe $BASE $BASE

这实际上显示了双方工作目录中的所有新变化。

[difftool "p4merge"]
path = C:\Program Files\Perforce\p4merge.exe
cmd = p4merge.exe $LOCAL $LOCAL

这显示了两边的原始版本。

[difftool "p4merge"]
path = C:\Program Files\Perforce\p4merge.exe
cmd = p4merge.exe $BASE $LOCAL

这显示了我预期的结果,但顺序错误?

Eclipse 显示了预期的结果,而不是来自 difftool 的结果。 我还尝试了不同的工具:kdiff3 和 p4merge。

根据the documentation

When git difftool is invoked with this tool (either through the -t or --tool option or the diff.tool configuration variable) the configured command line will be invoked with the following variables available: $LOCAL is set to the name of the temporary file containing the contents of the diff pre-image and $REMOTE is set to the name of the temporary file containing the contents of the diff post-image. $MERGED is the name of the file which is being compared. $BASE is provided for compatibility with custom merge tool commands and has the same value as $MERGED.

稍微解压一下:

  • git difftool 首先需要两个提交的哈希 ID(或其他合适的东西;见下文)。我们称它们为差异的 "left" 和 "right" 面。当您使用:

    git diff commit1 commi2
    

    git difftool commit1 commit2
    

    我们的想法是获取说明,告诉您如何将 commit1 中的内容更改为 commit2 中的内容:如何将左侧的每个文件更改为右侧的每个文件.

  • 提交中的内容(快照中的冻结文件)的形式是 不是 Git 的任何程序都不能采用。所以 Git 将 提取 这些提交的文件到某个临时区域。这些文件可能有像 /tmp/a9ZF3xq 之类的乱七八糟的临时名称。

  • $LOCAL 具有左侧文件的狂野/不可预测的临时名称。

  • $REMOTE 具有右侧文件的狂野/不可预测的临时名称。

  • $MERGED 具有实际文件名,例如 src/sub/somefunc.py 或其他名称。如果此文件存在于磁盘上,其内容可能不是 左侧 右侧文件的内容! $MERGED 应该只用于显示文件的 name,而不是访问任何内容。

  • $BASE 确实不应该使用,但如果您有使用它的东西,它只会与 $MERGED.

    [ 相同=149=]

因此,读取名为 $BASE$MERGED 的文件的 内容 是不正确的,有时会导致错误的指令。不要使用任何一个——使用 $LOCAL$REMOTE$LOCAL 保存左侧内容,$REMOTE 保存右侧内容。

一些git diff/git difftool命令使用工作树

我在上面说过 git difftool——这与 git diff 基本相同——需要两个 提交的哈希 ID,但这并不完全正确.它真正需要的是两棵来比较。

每个提交都有一棵树,在 Git 中,因为每个提交都包含所有文件在您(或任何人)[=150= 时的状态的完整快照] 提交。但是您还可以使用另外两棵树:

  • index暂存区 包含您建议的下一次提交。也就是说,它有每个(待提交的)文件的副本。如果你现在 运行 git commit,新的提交将快照索引/暂存区中的文件。

  • 你的工作树是一个文件树,你可以使用git add,用来覆盖索引/暂存中的文件-面积.

git diffgit difftool 都可以使用索引 and/or 工作树作为左侧 and/or 右侧。如果将索引用作两侧之一,其文件与提交中的文件采用相同的 Git-only 格式,因此必须将这些文件复制到可能具有临时名称的临时文件。但是如果当你使用 work-tree 作为两个方面之一时,那么它的文件都是普通的日常文件。 Git 可以而且将会直接让合并工具直接查看这些文件。

这意味着 当您使用工作树作为边之一时(在这种情况下 ),$LOCAL$REMOTE 将包含工作树文件的名称,并且该工作树文件包含您的工具应该检查的内容。在这种情况下,$BASE$MERGED 将具有 相同的名称 。这种情况 很常见 因为,与 git diff 一样:

git difftool

with no arguments 表示 "compare the index contents to the work-tree contents"。使用 一个 参数:

git difftool HEAD

Git 将给定的提交与工作树进行比较。也就是说,在这两种情况下,右侧 "commit" 是工作树中的任何内容。所以在这里,$LOCAL 是一个临时文件名,包含 HEAD 提交或索引中的内容,但 $REMOTE$BASE$MERGE 都只是工作树文件的名称!

因此,当然:

<command-to-view> $LOCAL

将显示左侧的内容,因为 $LOCAL 是: 包含左侧内容的临时文件。与此同时:

<command-to-view> $BASE

将显示右侧的内容,因为 $BASE 匹配 $REMOTE 并且 $REMOTE 是包含右侧内容的文件的名称。使用:

<command-to-view/compare-both-of> $LOCAL $BASE

在这种情况下会起作用,但一般情况下不起作用。您必须使用:

<command-to-view/compare-both-of> $LOCAL $REMOTE

如果该命令可以说 "this is a comparison of the contents that were stored in a file named ____"(填空),您可以使用 $BASE.

填空