"git diff" 中同一行的两个版本

Two versions of same line in "git diff"

我在切换 b运行ches 后遇到了 st运行ge 行为。我执行了 git checkout master,我立即将一个文件标记为已修改。我运行git reset --hard把它改掉了,但是没有效果。 git diff 给了我这样的输出:

diff --git a/Project/MYClass.cs b/Project/MYClass.cs
index 4f8405e..cb8ca4c 100644
--- a/Project/MYClass.cs
+++ b/Project/MYClass.cs
@@ -170,7 +170,7 @@ namespace Project
-            Logger.Warn(message);
+            Logger.Info(message);

但是当我手动改回它时,我得到:

diff --git a/Project/MyClass.cs b/Project/MyClass.cs
index cb8ca4c..4f8405e 100644
--- a/Project/MyClass.cs
+++ b/Project/MyClass.cs
@@ -170,7 +170,7 @@ namespace Project
-            Logger.Info(message);
+            Logger.Warn(message);

所以 git 无法确定是哪一个。为了让它更有趣,如果我把它改成完全不同的东西,我会得到:

diff --git a/Project/MYClass.cs b/Project/MYClass.cs
index 4f8405e..cb8ca4c 100644
--- a/Project/MYClass.cs
+++ b/Project/MYClass.cs
@@ -170,7 +170,7 @@ namespace Project
-            Logger.Warn(message);
+            Logger.Error(message);
diff --git a/Project/MyClass.cs b/Project/MyClass.cs
index cb8ca4c..4f8405e 100644
--- a/Project/MyClass.cs
+++ b/Project/MyClass.cs
@@ -170,7 +170,7 @@ namespace Project
-            Logger.Info(message);
+            Logger.Error(message);

当我 运行 git ls-tree -r master | Select-String "myclass.cs" 我得到这个:

100644 blob 4f8405e28faa09981a3f76775b1693db31b0bdad    Project/MYClass.cs
100644 blob cb8ca4c60f10f959422ecc2cbdb91d0e693ea380    Project/MyClass.cs

我看到并明白有些地方不对劲,但我不知道它是怎么发生的。

我知道如何以残酷的方式修复它,删除我的本地并从远程获取所有内容,但我想知道是什么原因造成的,以及如何正确修复它。

Git 认为您在 Project 目录/文件夹中有两个不同的文件:

  • MYClass.cs(大写M、大写Y、大写C、小写lass.cs
  • MyClass.cs(大写M,小写y,大写C,小写lass.cs

Git 分别打开每个文件名,写出该文件的内容,然后关闭它。

由于您在 Windows 上,它拒绝制作两个不同的文件,其名称仅在 case 中不同,您的 OS 用另一个文件覆盖 两个文件之一,只留下两个外壳中的一个。您的 OS 不会让 Git 在工作树中有两个文件。 Git 可以(并且确实)在索引中有两个文件,因为Git的索引实际上是一个数据文件,而不是目录/文件夹。由于 Git 从索引中提交,Git 可以进行新的提交,继续包含两个不同的文件,其名称仅在大小写上有所不同。

你必须更新你的索引,让它只包含一个这样的名字,否则你注定要在Windows(和MacOS)上永远与这个问题作斗争。简单的方法是在 Linux 或 Unix 系统上进行修复,其中索引和工作树保持同步,因为 OS 可以并且确实创建两个不同的文件,其名称仅在大小写上有所不同。

困难的方法是使用git rm --cached:给它一个你真正想要的名字。 Git 将从索引中删除该文件,而不会影响工作树。现在索引具有正确的大小写,您可以修复工作树中的大小写以匹配,但是在 Windows 上这样做——在其他系统上,通常的技巧是:

mv NameWithCASEISSUE x   # change the whole name a lot, using a safe name
mv x NameWithCaseIssue   # change it back, using the correct case this time

现在您可以将索引版本与工作树版本进行比较,并进行可能需要的任何调整。由于只有一个索引版本可以匹配工作树文件,无论大小写问题如何(现在没有任何问题,因为您已经仔细地使文件名大小写匹配),您可以完成工作。

真正不幸的情况(如果我可以使用那个词的话:-))发生在你真的确实想要两个文件名的时候,只是大小写不同,在索引和未来的承诺。没有很好的工具来处理这个问题。理论上可以围绕 git update-indexgit checkout-index 命令构建此类工具,但目前还不存在。

托瑞克!你为什么偷我的答案? :-P

正如 Torek 所解释的(比我要详细得多),问题是你有两个不同的文件用于 git.... 但是当 git 使用 Windows FS API,他们都在 FS 上击中同一个文件..... 这解释了整个问题。你是怎么解决的?如果您不介意继续解决问题,请保留您想要的真实文件和您想要的内容,并使用 git rm 删除另一个并提交。如果您想及时修复它,请查看第二个文件出现的位置,通过删除它来修改该修订版并在其上重写历史记录。