Git 意外创建了一个大小写不同的重复分支(主分支),如何将其移回主分支?
在将数据从一个子分支移回Git 意外创建了一个大小写不同的重复分支(主分支),如何将其移回主分支?,git,branch,Git,Branch,在将数据从一个子分支移回主分支时,我意外地创建了一个主分支(大写M)。 Windows上的工具集似乎忽略了资本化的差异,在我的本地回购中,我只有两个分支: Directory of C:\Users\Me\source\repos\Me\MyProject\.git\logs\refs\remotes\origin [.] [..] 64ThreadsPerBlock HEAD master 6
主分支时,我意外地创建了一个主分支(大写M)。
Windows上的工具集似乎忽略了资本化的差异,在我的本地回购中,我只有两个分支:
Directory of C:\Users\Me\source\repos\Me\MyProject\.git\logs\refs\remotes\origin
[.] [..] 64ThreadsPerBlock HEAD master
64threadsPerBlock
Master
master
但是,在remote中,我有三个分支:
Directory of C:\Users\Me\source\repos\Me\MyProject\.git\logs\refs\remotes\origin
[.] [..] 64ThreadsPerBlock HEAD master
64threadsPerBlock
Master
master
如何解决问题,使遥控器没有主机,并且与本地主机保持同步?如果您使用的是Linux系统,这很容易,因为Git总是区分大小写:readme
和readme
是两个不同的文件,master
和master
是两个不同的分支
如果您在一个典型的Windows或macOS文件系统上,使用不区分大小写的本机文件名,1它会变得混乱:Git认为master
和master
是两个不同的名称,但有时将这些名称用作文件系统中的普通文件。然后,它期望这两个不同的名称保持不同,但操作系统坚持不这样做。但是,由于Git只是有时候这样做,所以有时候它会按照Git认为应该的方式工作
你可以利用两个事实:
另一个系统显然是将这两个名称视为不同的名称
Git实际上并不关心分支名称是什么以及如何拼写,等等,它只关心每个名称中存储的哈希ID
因此,解决问题的第一步是运行:
git ls-remote origin
这将输出几行或多行输出,例如:
e2850a27a95c6f5b141dd88398b1702d2e524a81机头
898f80736c75878acc02dc55672317fcc0e0a5a6参考/头部/维护
e2850a27a95c6f5b141dd88398b1702d2e524a81参考/头部/主
5d2a92d10f831493d4b0b258ee3cd18d4a7ae995参考/标题/下一页
4141ae219919d2e29f3939983be8501770f247a3参考/头部/视野
1637c5d31a0b0df8e3dcef7072720fe0381520ac参考/头部/待办事项
d5aef6e4d58cfe1549adef5b436f3ace984e8c86参考文献/标签/gitgui-0.10.0
3d654be48f65545c4d3e35f5d3bbed5489820930参考文献/tags/gitgui-0.10.0^{}
[…这里剪了很多标签]
在每一列中,左边是原始散列ID。这个原始散列ID是Git关心的。右边是另一个Git存储库存储原始散列ID的名称。refs/heads/*
名称是它们的分支名称
您可能希望将所有输出保存在一个文件中。还要注意的是,我们指望另一个Git存储库在工作时不会对其进行任何更改。如果它是一个高度活跃的存储库,那么最好使用Linux系统(或Linux虚拟机)并在其中执行普通的Git操作
(旁注:gitlsremote-horigin
将输出修剪为只包含分支名称,如果有许多标记,这将非常方便。)
1从技术上讲,区分大小写取决于每个文件系统。在macOS上,您可以轻松地设置区分大小写的磁盘映像,将其装载、克隆并修复其中的所有内容,而无需使用VM。Windows系统可能也有区分大小写的文件系统,但我不知道有没有,也不知道有没有像macOS“.dmg”这样相对简单的方法
步骤1之后要做什么
如果它们的master
和master
都存储相同的原始散列ID,您现在可以要求它们删除两个名称中的一个:
git push --delete origin Master
(假设您要删除的是一个大写的M
)。你现在完成了
如果它们的master
和master
存储了不同的原始散列ID,您现在必须弄清楚该怎么做。您将删除这两个名称中的一个。如果他们的母版
在他们的母版
之前,你可以做与他们相同的事情:只需删除他们的母版
。但是如果他们的主机
在他们的主机
后面,或者两者都在前面和后面,你就不可能做到这一点,至少不安全
理解这一点需要理解“前面”和“后面”的实际含义。提交哈希ID(Git)是有向无环图或DAG的一部分。我们需要一个关于图论和偏序集的简短的旁白
偏序集
大多数人都熟悉总顺序,比如整数:1在2之前,2在3之前。任何大于3的数字都位于所有这些之后
然而,在图形中,我们可以有一条简单的线:
A--B--C--D--...
或叉子:
然后您可以安全地删除Master
。他们现在将有:
...--G--H--I <-- master
例如,如果它们的主文件的哈希ID为死肉
,并且您选择名称立即保存
作为新的分支名称,则您将运行:
git push origin deadbeef:save-for-now
这将在他们的Git存储库中造成这种情况:
H <-- master
/
...--G
\
I <-- Master, save-for-now
要要求他们删除自己的姓名Master
:
H <-- master
/
...--G
\
I <-- save-for-now
(当然都在他们的Git存储库中)
既然已经解决了问题,只需运行git fetch--prune origin
现在,您可以让Git将存储库与其Git存储库重新同步。您可能必须运行这个git fetch--prune origin
两次,因为您的本地git可能会在更新Master
后删除名称Master
,并且您的git将该名称存储在一个文件中,您的git可能会删除这两个名称,但这是安全的,因为第二个git fetch
将恢复它。(一般来说,Git似乎是按ASCII顺序执行这些操作的,这样一次抓取就可以正常工作,但我不知道这是否保证适用于过去和将来的所有Git版本。)
如果以前所有提交都是安全的,这样您就可以安全地删除它们的主文件
,那么现在就有了一个正常的设置,可以正常地解决所有问题。如果他们
git push origin deadbeef:save-for-now
H <-- master
/
...--G
\
I <-- Master, save-for-now
git push origin --delete Master
H <-- master
/
...--G
\
I <-- save-for-now
git push origin <hash>:save-for-now
...--G--H <-- Master, master, save-for-now
...--G--H <-- master, save-for-now