GitHub 分支机构:区分大小写问题?

GitHub Branches: Case-Sensitivity Issue?

我似乎遇到了存储库不断在本地重新创建分支的问题,因为远程有一些分支。我在 Windows 机器上,所以我怀疑这是区分大小写的问题。

这是一对命令的示例:

$ git pull
From https://github.com/{my-repo}
 * [new branch]          Abc -> origin/Abc
 * [new branch]          Def -> origin/Def
Already up to date.

$ git pull -p
From https://github.com/{my-repo}
 - [deleted]             (none)     -> origin/abc
 - [deleted]             (none)     -> origin/def
 * [new branch]          Abc -> origin/Abc
 * [new branch]          Def -> origin/Def
Already up to date.

当做 git pull 时,有问题的分支是大写的。当我执行 git pull -p(用于修剪)时,它首先尝试删除分支的小写版本,然后创建大写版本。

远程分支是大写的(origin/Abcorigin/Def)。

我试图暂时更改我的 Git 配置,使 ignorecase=false(当前为 ignorecase=true)。但我注意到行为没有变化。我猜我这边有一些本地的东西目前正在抓住那些小写的分支。但是 git branch 不会在本地显示这些分支的任何版本。

如果没有完全删除存储库(单独文件夹中的新 git clone 在尝试 pulls/fetches 时不会提取这些幻影分支),我能做些什么吗?

在 Git 上,分支只是指向提交的指针。分支作为普通文件存储在您的 .git 存储库中。

例如,您可能在 .git/refs/heads 上有 abcdef 个文件。

$ tree .git/refs/heads/
.git/refs/heads/
├── abc
├── def
└── master

这些文件的内容就是分支指向的提交号。

我不确定,但我认为选项 ignorecase 只与您的工作目录相关,与 .git 文件夹无关。因此,要删除 奇怪的 大写分支,您可能只需要 remove/rename .git/refs/heads 中的文件。

除此之外,从本地分支到远程分支的上游link存储在.git/config文件中。在这个文件中你可能有这样的东西:

[branch "Abc"]
        remote = origin
        merge = refs/heads/abc

请注意,在此示例中,远程分支名为 Abc,但本地分支名为 abc(小写)。

为了解决您的问题,我会尝试:

  1. 修改.git/config文件
  2. 重命名 .git/refs/heads 中损坏的分支 例如 abc 重命名 abc-old
  3. 试试你的git pull

Git 对此感到精神分裂。1 部分 Git case-sensitive,所以分支 HELLO 和分支 hello 不同的 分支。 Git 的其他部分,无论如何在 Windows 和 MacOS 上,case-in 敏感,所以分支 HELLO 和分支 hello 相同分支。

结果是混乱。最好完全避免这种情况。

更正问题:

  1. 设置一些 附加的,私有的和临时的,分支或标签名称,你不会觉得混淆,记住你的任何提交哈希 ID真正关心的,在你自己的本地存储库中。然后 运行 git pack-refs --all 这样你所有的引用都被打包了。这将删除所有 文件名 ,将所有引用放入 .git/packed-refs flat-file,它们的名称是 case-sensitive。你的 Git 现在可以区分你的 Abc 和你的 abc,如果你两者都有的话。

    既然您的存储库是 de-confused,删除 任何错误的分支名称。您的临时名称包含您想记住的值。如果一个或两个可能被弄乱,您可以同时删除 abc Abc。你的remember-abc里面有正确的散列。

  2. 转到 Linux 服务器计算机,该计算机的分支仅在大小写上与您的分支不同。 (它始终是 Linux 机器;此问题永远不会发生在 Windows 或 MacOS 服务器上,因为它们足够早地执行 case-folding,您永远不会 创建 首先是问题。)在那里,重命名或删除有问题的坏名称。

    Linux 机器没有大小写问题——名称不同只是大小写不同的分支总是不同的——所以这里没有奇怪之处。可能需要几个步骤和一些 git branch 命令来列出所有名称,但最终,您将只得到清晰和不同的名称:不会有名为 Abc 和 [= 的分支18=]两者。

    如果Linux服务器上没有这样的问题,第2步就是"do nothing".

  3. 在您的本地系统上使用 git fetch --prune。您现在不再有任何错误的名称作为 remote-tracking 名称,因为在第 2 步中,您确保服务器(您的本地 Git 调用 origin 的系统)没有错误的名称,并且您的本地 Git 已使您的本地 origin/* 名称与其分支名称匹配。

  4. 现在 re-create 您在本地想要的任何分支名称,and/or 重命名您在步骤 1 中创建的临时名称。例如,如果您让 remember-abc 记住abc,你可以 运行 git branch -m remember-abc abc 移动 remember-abcabc.

    如果 abc 应该将 origin/abc 设置为其上游,请立即执行此操作:

    git branch --set-upstream-to=origin/abc abc
    

    (您可以在创建 remember-abc 时在步骤 1 中执行此操作,但我认为这里更有意义,因此我将其放在步骤 4 中。)

除了上述 4 个步骤之外,您还可以使用各种快捷方式。为了清楚起见,我以这种方式列出了所有四个步骤:每个步骤要完成的对你来说应该是显而易见的,如果你阅读了本文的其余部分,为什么 你正在做这一步。

出现问题的原因在nowox's answer中有概述:Git有时将分支名称存储在文件名中,有时将其作为字符串存储在数据文件中。由于 Windows(和 MacOS)倾向于使用 file-name-conflation,file-name 变体保留其原始大小写,但忽略了创建另一个 case-variant 名称的第二个文件的尝试,并且那么 Git 认为 Abcabc 在其他方面 相同 。 data-in-a-file 变体保留了 case-distinction 以及 value-distinction 并认为 Abcabc 是两个不同的分支,它们标识两个不同的提交。

git rev-parse refs/heads/abcgit rev-parse refs/remotes/origin/abc.git/packed-refs(包含字符串的数据文件)获取信息时,它会获取 "right" 信息。但是当它从文件系统获取信息时,尝试打开 .git/refs/heads/abc.git/refs/remotes/origin/abc 实际上会打开 .git/refs/heads/Abc(如果该文件现在存在)或 similarly-named remote-tracking 变体(如果该文件存在),并且 Git 获取 "wrong" 信息。

设置 core.ignorecase(任何设置)根本没有帮助,因为这会影响 Git 处理 case-folding 的方式work-tree。 Git 内部数据库中的文件不会受到任何影响。

如果 Git 使用真实的数据库来存储其 table,那么整个问题就不会出现了。在 Linux 上使用单个文件效果很好。它在 Windows 和 MacOS 上不能正常工作,反正不是这样。使用单个文件 可以 在那里工作 if Git 没有将它们存储在具有可读名称的文件中——例如,而不是 refs/heads/master,也许 Git 可以使用名为 refs/heads/6d6173746572 的文件,尽管这会将可用的 component-name 长度减半。 (练习:0x6d m、0x61 a 等等如何?)


1从技术上讲,这是一个错误的词。虽然它肯定是描述性的更好的词可能是 schizoid,如 one episode of The Prisoner, but it too has the wrong meaning. The root word here is really schism 的标题中所用,意思是分裂和有点 self-opposed,这就是我们在这里的目的。

and torek 提供的答案非常有帮助,但没有包含确切的解决方案。 .git/config 中对远程的现有引用和 git/refs/heads 中的文件不包含 abcdef.

的任何版本

相反,问题存在于 .git/refs/remotes/origin

我的 .git/refs/remotes/origin 目录引用了这些功能分支文件夹的小写版本。一些功能分支是在 abcdef 下使用小写版本创建的,但它们不再存在于远程。这些功能分支的创建者最近切换到远程使用 AbcDef。我删除了 .git/refs/remotes/origin/abc.git/refs/remotes/origin/def 然后执行了新的 git pull -p 命令。新文件夹 AbcDef 已创建,后续 pullfetch 正确显示 Already up to date.

感谢 nowox 和 torek 让我走上正轨!

我做了以下事情来解决我的问题:

  1. 我导航到 .git/refs/remotes/origin 文件夹。
  2. 我删除了带有 buggy 分支名称的文件夹。
  3. 我在终端做了git pull