这里的另一个答案不太正确,尽管这样:
但在我们的 gitlab 服务器上,它显示分支就像什么都没发生一样。
很有希望,因此您可能有一个简单的方法来解决问题。
我将展示一个我销毁自己的 master 分支的示例(当然是在克隆中)。由于这个特定的系统是区分大小写的,我只是手动删除了master 分支(在 Git 的后面,就像它一样)。
Git 错误:分支名称区分大小写,除非它们不是
这是 Git 中的一个错误:它设法删除了您所在的分支。
出现问题是因为 Git 区分大小写:就 Git 而言,分支 exif 与分支 Exif 完全分开。当您要求 Git 删除 exif 时,本质上是检查:
- 我在分支
exif 上吗?
- 如果是这样,请拒绝尝试,因为它会搞砸一切。
- 否则,请继续删除
exif。
Git 检查了一下,发现你当前的分支是Exif,而不是exif。好吧,对于 Git,这些显然是不同,删除它一定是安全的!只是......他们不是,也不是。 The truth is complicated,但在 Windows 和 MacOS 系统上,Git 要么需要一些实现更改——以便分支名称真正可以始终区分大小写——要么 Git 需要停止相信 它们区分大小写,因为它们有时(通常在这些系统上)不区分大小写。
修复它
与此同时,棘手的部分是恢复您的分支。这需要对 Git 内部进行一些研究。
两部分
在 Git 中,当前分支有两个关键组件。一个是文件.git/HEAD。该文件包含一个简单的字符串:
$ cat .git/HEAD
ref: refs/heads/master
$
也就是说,这个文件包含(作为纯文本:不是“富文本”,不是Unicode,不是Windows UCS-2格式,只是简单的ASCII文本)文字字符串ref: refs/heads/,refs/heads/之前有一个空格,后跟分支名称,后跟换行符。该文件完好无损!
另一半更复杂。好消息是大多数复杂性都消失了,因为如果没有,分支名称将区分大小写“在剩下的路上”,你可能(或可能不会)仍然可以。但是这个:
$ git log
fatal: your current branch 'Exif' does not have any commits yet
证明分支值仅存储在文件.git/refs/heads/<em>branchname</em>中。
也就是说,你曾经有一个文件名为:
.git/refs/heads/Exif
其中有一些散列值,类似于这个(但具有不同的散列):
$ cat .git/refs/heads/master
3ab228137f980ff72dbdf5064a877d07bec76df9
我们需要做的是将该文件放回原处,并具有相同的值。
修复它:如果你有价值(或它的一部分)
如果你可以看到这个值——甚至只是它的一部分——在某个地方,例如,在一个现有的窗口中,这就足以取回整个值。例如,如果我有 3ab228 在某处显示,我可以这样做:
$ git rev-parse 3ab228
3ab228137f980ff72dbdf5064a877d07bec76df9
这让我可以这样做来解决问题:
$ git rev-parse 3ab228 > .git/refs/heads/master
我们完成了。 (请参阅下面关于 reflog 的最后一项。)
修复它:如果你有它作为远程跟踪分支
如果你之前已经成功推送了分支,那么你的值可能是远程跟踪分支:
$ git rev-parse origin/master
3ab228137f980ff72dbdf5064a877d07bec76df9
在这种情况下,您可以将其放回原处:
$ git rev-parse origin/master > .git/refs/heads/master
你就完成了。 (请参阅下面关于 reflog 的最后一项。)
修复它:如果你的上游有它
在您的情况下,听起来像名为origin 的远程在名称exif(全部小写)下具有正确的哈希ID,即,由于某种原因它忽略了git push --delete 命令。在这种情况下,您可以向遥控器询问该值。请注意,从那时起,其他任何人可能已对其进行了更新:
$ git ls-remote origin master
454cb6bd52a4de614a3633e4f547af03d5c3b640 refs/heads/master
(显然我的遥控器已经移动,所以我无法使用它,但如果你幸运的话,你的没有)。确保值是好的:
$ git rev-parse 454cb6bd
454cb6bd
fatal: ambiguous argument '454cb6bd': unknown revision or path
not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
(所以这对我不起作用,因为他们确实已经继续前进了)。
作为最后的手段,你可以运行:
$ git fsck --unreachable
这可能会吐出一大堆unreachable 消息:
unreachable commit fcfbe9a1165e38467b4d24d41b3166a20c1dfb80
unreachable commit c8056a11ef8eee1bfaaaa2e32a9cc92a02eae2e0
unreachable blob 010a1a22a90b2bd78e6b87a3922c3324c44a8a9b
unreachable commit c1163ad1eeff0c86f030483907ea8cedcdd431e3
unreachable commit f35fc21adeb21e1a4800ccebd5719317efb968dc
忽略除“提交”之外的所有内容:其中一个是正确的。要找出是哪一个,请在每一个上运行git show,也许有一些东西可以帮助缩短它们,例如:
$ git show --pretty=oneline --no-patch fcfbe9a1165e38467b4d24d41b3166a20c1dfb80
fcfbe9a1165e38467b4d24d41b3166a20c1dfb80 WIP on precious: e59f6c2 The last
minute bits of fixes
(这表明这个特定的项目实际上是一个git stash 提交)。
找到合适的后,可以将其放入.git/refs/heads/Exif 以恢复值,您的存储库将大部分恢复原状。 git rev-parse 方法在这里也可以使用,尽管由于您拥有完整的原始哈希,因此您实际上不必rev-parse 它。
reflog 消失了;以及你可能会在哪里看
恢复分支文件修复分支,让一切重新准备就绪,例如:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
但是,分支的 reflog 现在已经消失了:
$ git reflog master
$
HEAD 的 reflog 仍然有效,一旦您在分支上执行更多操作,分支的 reflog 将重新创建。
如果您的文件系统得到备份(例如,通过 MacOS Time Machine,或通过在 Windows 网络驱动器上创建快照等),您可以查看系统备份。如果幸运的话,您可能会在这些备份中找到分支文件和 reflog。
在这种情况下,您可以简单地将它们还原到位。这与找到正确的哈希具有相同的效果,但通过恢复 reflog,您可以恢复您的 reflog。