git diff重命名/移动和修改过的文件,但跳过重命名/移动和相同的文件

时间:2016-02-12 16:44:18

标签: git rename move git-diff meld

我正在使用:

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

使用meld外部差异工具显示已重命名/移动和修改的文件。在提交检查我的工作和正确组装提交消息之前,我总是做一个git diff。通常我会重命名/移动文件,这也需要在引用某些重命名/移动文件的文件中进行一些路径更改。

我的问题是,为了显示已重命名然后修改的文件的差异,git diff还会为已重命名但未修改的文件弹出一堆meld窗口。这可能非常烦人。如何让git diff跳过重命名但未修改的文件?当我以更清晰的方式键入git status时,我将看到列出的所有文件被重命名/移动,所以我不希望弹出相同的文件与git diff。

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,并提出了一个别名的技巧(我正在使用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

(更多示例见底部)

工作原理:

想象一下,您有三个已重命名的文件。其中一个内容实际上已更改(因此您希望使用difftool检查它),但除路径或名称外,其他两个相同(并且您想忽略它们)。

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

别名的作用是生成明确排除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

在所有情况下,必须将“比较的两侧”(提交, - 缓存或其他)指定为第一个参数。例如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)。在这种情况下,如果内容没有改变,可以使用上方栏上的按钮轻松省略它们。

如果发生“命名”冲突(比较同一侧的几个文件在不同的路径下具有相同的名称),它将只选择其中一个用于比较,而忽略其他文件。