【问题标题】:Git Diff problems after bulk rename批量重命名后的 Git Diff 问题
【发布时间】:2015-07-03 18:56:05
【问题描述】:

在将批量重命名应用于大型项目(略低于 10,000 个文件)后,我在处理 Git 历史记录时遇到了很多麻烦。我通过将文件从Project/src/.... 移动到Project/src/main/java/.... 来更改项目布局。我还在同一个提交中修改了一些移动的文件。

让我们看一下这样的文件:

$ git logc PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java
* commit 6e7a960f99b0e6164d2713a4cbca2107034d8bbd
  Author: moffats <moffats@ec78347f-1a2b-0410-964c-a7254f1fcdc6>
  Date:   Thu Apr 23 21:24:30 2015 +0000

      merge gradle branch to the trunk

好的,看来我们需要使用 --follow 来告诉 Git 遵循重命名:

$ git logc --follow PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java
...
* commit 6e7a960f99b0e6164d2713a4cbca2107034d8bbd
| Author: moffats <moffats@ec78347f-1a2b-0410-964c-a7254f1fcdc6>
| Date:   Thu Apr 23 21:24:30 2015 +0000
| 
|     merge gradle branch to the trunk
|     
...
* commit ce0c98d4b78e2f006ead16a030b3c5f0d7ec3ac0
  Author: perches <perches@ec78347f-1a2b-0410-964c-a7254f1fcdc6>
  Date:   Thu Mar 22 21:29:41 2012 +0000

      Updates for JSF 2.0 upgrade

我们去吧。现在让我们比较两个版本:

$ git diff -M -l0 ce0c98d4b78e2f006ead16a030b3c5f0d7ec3ac0..HEAD PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java
diff --git a/PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java b/PINSSUserPasswordUtil/src/main/java/
new file mode 100644
index 0000000..acc4d40
--- /dev/null
+++ b/PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java
@@ -0,0 +1,186 @@
+package ca.gc.agr.pinss.userPasswordUtil;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
... etc ...

Git 显然没有检测到重命名。它没有找到文件的旧位置,并告诉我添加了整个文件内容。 请注意,它将现有文件与/dev/null 进行比较,而不是旧文件路径,应该是:

PINSSUserPasswordUtil/src/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java

好的,让我们看看重命名的提交是什么样子的:

$ git show --stat=180 6e7a960f99b0e6164d2713a4cbca2107034d8bbd | grep UserPasswordReseter
 PINSSUserPasswordUtil/src/{ => main/java}/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java               |   10 +-

这看起来不错,所以这就是我卡住的地方。获得所需差异的唯一方法是明确告诉 Git 以前的旧文件路径是什么

$ git diff ce0c98d4b78e2f006ead16a030b3c5f0d7ec3ac0:PINSSUserPasswordUtil/src/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java HEAD:PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java

-- a/ce0c98d4b78e2f006ead16a030b3c5f0d7ec3ac0:PINSSUserPasswordUtil/src/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java
+++ b/HEAD:PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java
@@ -29,18 +29,18 @@ public class UserPasswordReseter {
        private static final Log log = LogFactory.getLog(UserPasswordReseter.class);

        private static final String DATASOURCE_BEAN_NAME = "dataSource";
-       private static final String USER_PROPERTIES = "configuration/users.properties";
+       private static final String USER_PROPERTIES = "/users.properties";

现在我得到了我想要的。

那么为什么我之前的“git diff -M -l0”命令不起作用?我认为这个问题也会导致 Eclipse 中的 EGit 和“git instaweb”等工具不再工作,这意味着我失去了使用强大的 GUI 工具访问预重命名历史记录的能力。

目前我不确定如何修复它。任何建议,将不胜感激。

git 版本 1.9.1

编辑:正如 cmets 中指出的,此命令:

git diff -M -l0 ce0c98d4b78e2f006ead16a030b3c5f0d7ec3ac0..HEAD PINSSUserPasswordUtil/src/main/java/ca/gc/agr/pinss/userPasswordUtil/UserPasswordReseter.java

没用,b/c 我们需要在整个存储库上运行差异,以便重命名检测工作。所以像这样的命令可以正常工作:

$ git diff -M -l0 ce0c98d4b78e2f006ead16a030b3c5f0d7ec3ac0 HEAD

当然,现在我需要在整个提交的大差异输出中寻找我感兴趣的文件,但这确实省去了我输入新旧路径的麻烦。仍远未达到理想状态,但比以前更好。

【问题讨论】:

    标签: git rename instaweb


    【解决方案1】:

    重命名检测的计算成本很高(请参阅下一段),因此 git 将其限制为您配置的任何内容。如果您不配置特定值,git 已经内置了默认值,这些默认值随着各种版本的增加而增加(从 100 到 200,现在是 400)。

    特别是,当比较任何两个修订版(或更准确地说,两棵树)时,出现在“旧”树而不是“新”树中的路径名提供重命名的源候选文件,而路径名出现在“新”树中但不在“旧”树中提供重命名的目标候选者。为了检测实际的重命名,git 必须将每个可能的来源与每个可能的目的地进行比较。

    据我所知,git (当前)没有“重命名目录,文件名的尾部部分相同”的启发式方法来减少列表的大小。如果这样做的话,这将有很大帮助。如果没有它,您可以尝试将重命名限制设置得非常高(根据需要设置尽可能多的路径名),使用 -l 选项到 git diffdiff.renameLimit 配置变量。将其设置为显式 0 意味着“无限制”(内部实际上是 32767,因此不是完全无限制)。

    【讨论】:

    • 感谢您的详细解释。这是有道理的,但是将“-l0”传递给我的 diff 命令什么也没做。如我原来的帖子所示,它会立即返回不正确的差异结果。我还能错过什么?
    • 我不确定-l 0 是否有效(它可能应该,但是,好吧,git 是 git :-)),试试-l 32767 看看是否有区别。还要确保将-M 标志提供给git diff(我知道,每次编辑,你就是这样,我会把它留在评论中,以防其他人以后遇到这个问题)。
    • 这是我正在尝试的命令:“git diff -M -l 32767 ce0c98d4b78e2f006ead16a030b3c5f0d7ec3ac0..HEAD UserPasswordReseter.java”它立即返回错误信息。
    • 啊哈:使用文件名参数它不会有重命名检测的完整列表。我不知道如何让它为一个文件做一个完整的差异和 then 过滤器(此时应用了重命名检测);可能您需要一个后差异过滤器步骤来提取有趣的路径。
    • 是的,不指定路径,而是执行完整的 repo diff,正确地挑选出 UserPasswordReseter.java 中的更改。现在我只需要弄清楚如何过滤输出以将其缩小到我感兴趣的文件。
    猜你喜欢
    • 2011-12-07
    • 2014-02-06
    • 1970-01-01
    • 2013-04-14
    • 2012-03-15
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多