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

标签 git rename move git-diff meld

我正在使用:

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

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

我的问题是,为了显示已重命名然后修改的文件的差异,git diff 还会为已重命名但未修改的文件 pop 一堆 merge 窗口。这可能非常烦人。如何让 git diff 跳过重命名但未修改的文件?当我以更简洁的方式输入 git status 时,我将看到所有这些文件被列为重命名/move ,所以我不希望使用 git diff pop 相同文件的窗口。

最佳答案

我遇到了同样的问题,想出了一个别名来解决问题(我使用的是 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

在所有情况下,“比较的边”(提交、--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 diff 重命名/move 和修改的文件但跳过重命名/move 和相同的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35367894/

相关文章:

c++ - 为什么调用 move 分配?

linux - 如何根据内容重命名文本文件?

android - 在android中从上到下 move 图像

c++ - 如何编写 move 以便它可以被优化掉?

git - 我的 git 存储库有一个巨大的 .pack 文件。有没有办法安全删除它?

linux - 有没有一种方法可以不使用重命名系统调用来更改文件名?

javascript - 重命名数组 JavaScript 中的重复项

git - 如何删除裸 `git` 存储库中的唯一分支?

git-svn 仅导入分支

git - 如何克隆一个 git repo 零碎的