git diff命令用于比较文件之间的差异。如果文件被重命名/移动并且被修改,则会显示差异,但是可以跳过重命名/移动和相同的文件。

10

我正在使用:

git diff HEAD --diff-filter=R -M

使用meld外部差异工具显示已重命名/移动和修改的文件。我总是在提交之前执行git diff,以检查我的工作并正确组合提交消息。通常情况下,我会重命名/移动文件,这也需要对引用一些重命名/移动文件的文件进行一些路径更改。
我的问题是,为了显示已重命名然后修改的文件的diff,git diff也会弹出一堆meld窗口,用于已经被重命名但未被修改的文件。这可能非常烦人。如何让git diff跳过已重命名但未修改的文件?当我在输入git status时,我将以更清晰的方式看到列出所有这些文件已被重命名/移动,因此我不想使用git diff弹出与相同文件相关的弹出窗口。
1个回答

5

我遇到了同样的问题,不过我想出了一个别名解决了这个问题(我使用的是 git 2.8.3)

[alias]
    difftoolr = "!git difftool \"$@\" -- .  $((git diff \"$1\" -M100% --diff-filter=R --name-only & git diff \"$1\" -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"

如何使用:

difftoolr commit1..commit2 -M

(更多示例请见底部)

工作原理:

假设您有三个重命名的文件。其中一个文件内容实际上已更改(因此您想使用差异工具检查它),但其他两个除路径或名称外都相同(您想忽略它们)。

(different) path/file.old  -> newPath/file.new
(identical) path/fileB.old -> newPath/fileB.new
(identical) path/fileC.old -> newPath/fileC.new

Alias命令所做的是生成路径规范,明确地排除fileBfileC,即尽管文件名更改了但内容未改变的那些文件。
换句话说,我们正在生成这些文件规范:

-- . :(exclude)path/fileB.old :(exclude)newPath/fileB.new :(exclude)path/fileC.old :(exclude)newPath/fileC.new

注意(也许是最棘手的部分):必须同时显式地排除旧文件路径和新文件路径。
为此,我们使用以下指令发出git diff:
-M100%:跟随重命名。这意味着git假设进行了一些重命名,并将考虑此信息来进行成对比较。阈值为100%,这指示git将被视为已重命名那些具有完全相同内容但未更改的文件。
--diff-filter = R:仅列出git认为已重命名的文件,省略其他文件。
--names-only:仅输出文件名,没有其他信息
-R:反向。在脚本的一个部分中,我们交换了比较顺序(类似于交换左侧和右侧),因此它也将输出旧文件名。例如,-R指令将文件newPath/fileB.new列为path/fileB.old。
... sed ... :最后,我们在所有文件名的开头添加了排除指令:(exclude)。
为了处理其他情况,我创建了三个不同的别名(并不是非常优雅,我想要更灵活的东西),因此可以用于指定不同类型的比较。
git difftoolr0 -M
git difftoolr1 HEAD~1..HEAD -M
git difftoolr2 HEAD --cached -M

无论在哪种情况下,"比较的对象" (commits, --cached或其他) 必须作为第一个参数指定。例如,git difftoolr2 -M HEAD --cached 不起作用 (因为 -M 排在第一位)。
[alias]
# takes no parameter: sample usage:  git difftoolr0  -M
difftoolr0 = "!git difftool \"$@\" -- .  $((git diff -M100% --diff-filter=R --name-only & git diff -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"

# takes 1 parameter in first position: sample usage:  git difftoolr1 HEAD~1..HEAD -M
difftoolr1 = "!git difftool \"$@\" -- .  $((git diff \"$1\" -M100% --diff-filter=R --name-only & git diff \"$1\" -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"

# takes 2 parameters in first positions: sample usage:  git difftoolr2 HEAD --cached  -M
difftoolr2 = "!git difftool \"$@\" -- .  $((git diff \"$1\" \"$2\" -M100% --diff-filter=R --name-only & git diff \"$1\" \"$2\" -M100% --diff-filter=R --name-only -R) | sed 's/\\(.*\\)/:(exclude)\\1/g') #"

最后,BeyondCompare也可能适合你的需求(也适合我的需求)。
它很容易地将并排差异切换为“非结构化”差异。后者会剥离文件夹,只保留名称。如果文件名相同(但路径可能不同),则被视为同一文件的两个版本(例如path/file.pngnewPath/file.png)。在这种情况下,如果内容没有改变,则可以使用上方栏中的一个按钮轻松省略它们。
如果出现“命名”冲突(比较的同一侧有多个文件具有相同的名称,位于不同的路径下),它会选择其中一个进行比较,并忽略其他文件。

git difftool "$@" -- . $((git diff "$1" -M100% --diff-filter=R --name-only & git diff "$1" -M100% --diff-filter=R --name-only -R) | sed 's/\(.*\)/:(exclude)\1/g') #: 1: git difftool "$@" -- . $((git diff "$1" -M100% --diff-filter=R --name-only & git diff "$1" -M100% --diff-filter=R --name-only -R) | sed 's/\(.*\)/:(exclude)\1/g') #: Syntax error: Missing '))' - Christoph Thiede

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接