我似乎遇到了一个问题,即存储库不断在本地重新创建分支,因为远程上有一些分支。我在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/Abc
和origin/Def
)。
我试图暂时更改我的Git配置,使ignorecase=false
(它目前是ignorecase=true
)。但我发现行为没有变化。我猜我现在有一些本地的东西,目前正在抓住这些小型分支机构。但git branch
没有在本地显示这些分支的任何版本。
没有完全删除存储库(一个单独的文件夹中的新鲜git clone
在尝试拉取/取出时不会拉动这些幻影分支),有什么我可以做的吗?
在Git上,分支只是提交的指针。分支在.git
存储库中作为普通文件存储。
例如,你可能在abc
上有def
和.git/refs/heads
文件。
$ tree .git/refs/heads/
.git/refs/heads/
├── abc
├── def
└── master
这些文件的内容只是分支指向的提交编号。
我不确定,但我认为选项ignorecase
仅与您的工作目录相关,而不是.git
文件夹。因此,要删除奇怪的大写分支,您可能只需要删除/重命名.git/refs/heads
中的文件。
除此之外,从本地分支到远程分支的上游链接存储在.git/config
文件中。在这个文件中你可能有类似的东西:
[branch "Abc"]
remote = origin
merge = refs/heads/abc
请注意,在此示例中,远程分支名为Abc
,但本地分支是abc
(小写)。
要解决您的问题,我会尝试:
.git/config
文件.git/refs/heads
中损坏的分支,如abc
更名为abc-old
git pull
Git是关于此的精神分裂症.Git的部分区分大小写,因此分支HELLO
和分支hello
是不同的分支。无论如何,在Windows和MacOS上,Git的其他部分不区分大小写,因此分支HELLO
和分支hello
是相同的分支。
结果是混乱。这种情况最好完全避免。
要纠正问题:
git pack-refs --all
以便打包所有引用。这将删除所有文件名,将所有引用放入.git/packed-refs
平面文件中,其名称区分大小写。如果你有两个,你的Git现在可以从你的Abc
告诉你的abc
。
现在您的存储库被解除混淆,删除任何错误的分支名称。您的临时名称包含您要记住的值。你可以删除abc
和Abc
,如果其中一个或两个可能搞砸了。你的remember-abc
中有正确的哈希值。git branch
命令列出所有名称,但最终,你将只有明确和不同的名称:没有名为Abc
和abc
的分支。
如果Linux服务器上没有这样的问题,第2步是“什么都不做”。git fetch --prune
。您现在不再有任何坏名称作为远程跟踪名称,因为在第2步中,您确保服务器 - 您的本地Git调用origin
的系统没有错误名称,并且您的本地Git已使您的本地origin/*
名称匹配他们的分支名称。remember-abc
记住abc
,你可以运行git branch -m remember-abc abc
将remember-abc
移动到abc
。
如果abc
应该将origin/abc
设置为其上游,请立即执行此操作:
git branch --set-upstream-to=origin/abc abc
(当你创建remember-abc
时,你可以在第1步中执行此操作,但我认为这更有意义,所以我将它放在第4步中。)您可以使用各种快捷方式,而不是上述4个步骤。为了清楚起见,我以这种方式列出了所有这四个方面:对于每个步骤要完成的内容应该是显而易见的,如果您阅读其余内容,那么为什么要执行该步骤。
问题发生的原因在nowox's answer中概述:Git有时将分支名称存储在文件名中,有时将其作为字符串存储在数据文件中。由于Windows(和MacOS)倾向于使用文件名混淆,文件名变体保留其原始情况,但忽略尝试创建另一个案例变体名称的第二个文件,然后Git认为Abc
和abc
是否则一样。文件中的数据变体保留了区分大小和区分值,并认为Abc
和abc
是两个不同的分支,用于标识两个不同的提交。
当git rev-parse refs/heads/abc
或git rev-parse refs/remotes/origin/abc
从.git/packed-refs
获取其信息时 - 包含字符串的数据文件 - 它获得“正确”的信息。但是当它从文件系统获取其信息时,尝试打开.git/refs/heads/abc
或.git/refs/remotes/origin/abc
实际上会打开.git/refs/heads/Abc
(如果该文件现在存在)或类似命名的远程跟踪变体(如果该文件存在),并且Git获取“错误的“信息。
设置core.ignorecase
(对任何东西)根本没有帮助,因为这只影响Git在工作树中处理大小写折叠的方式。 Git内部数据库中的文件不受任何影响。
如果例如Git使用真实数据库来存储其<reference-name,hash-ID>表,则整个问题永远不会出现。使用单个文件在Linux上运行正常。它在Windows和MacOS上无法正常工作,不管怎么说都不行。如果Git没有将它们存储在具有可读名称的文件中,那么使用单个文件可以在那里工作 - 例如,而不是refs/heads/master
,也许Git可以使用名为refs/heads/6d6173746572
的文件,尽管这会将可用的组件名称长度减半。 (练习:0x6d m
,0x61 a
怎么样,依此类推?)
1技术上,这是错误的词。但它确实具有描述性。一个更好的词可能是精神分裂,正如one episode of The Prisoner的标题中所使用的那样,但它也有错误的含义。这里的根词真的是schism,意思是分裂和有点自相矛盾,这就是我们在这里开车的原因。
nowox和torek提供的答案非常有用,但没有包含确切的解决方案。在.git/config
中对远程的现有引用,以及git/refs/heads
中的文件不包含任何版本的abc
或def
。
相反,问题存在于.git/refs/remotes/origin
。
我的.git/refs/remotes/origin
目录引用了这些功能分支文件夹的小写版本。一些特征分支是在abc
和def
下使用小写版本制作的,但它们不再存在于遥控器上。这些功能分支的创建者最近切换到在远程使用Abc
和Def
。我删除了.git/refs/remotes/origin/abc
和.git/refs/remotes/origin/def
,然后执行了新的git pull -p
命令。创建了新文件夹Abc
和Def
,随后pull
s或fetch
es正确显示Already up to date.
感谢nowox和torek让我走上正轨!