【问题标题】:git diff renamed/moved and modified files but skip renamed/moved and identical filesgit diff 重命名/移动和修改的文件,但跳过重命名/移动和相同的文件
【发布时间】:2016-05-23 21:57:47
【问题描述】:

我正在使用:

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

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

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

【问题讨论】:

    标签: git rename move git-diff meld


    【解决方案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
    

    在所有情况下,“比较的双方”(提交、--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)。在这种情况下,如果内容没有改变,可以使用上栏的按钮轻松省略。

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

    【讨论】:

      猜你喜欢
      • 2011-08-09
      • 1970-01-01
      • 1970-01-01
      • 2021-02-21
      • 2014-04-26
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 2016-09-29
      相关资源
      最近更新 更多