我感觉就像校长办公室里的一个孩子,解释说狗在截止日期前一天晚上吃了我的作业,但我正盯着一些疯狂的数据丢失错误,我不明白这是怎么发生的。我想知道 git 如何吃掉我的整个存储库!我已经多次对 git 进行绞尽脑汁,但它从来没有眨眼过。我用它把 20 Gig Subversion 存储库拆分为 27 个 git 存储库,并从它们中过滤分支 foo 以理清混乱,而且它从来没有丢失任何字节。 reflog 总是可以依靠的。这次地毯不见了!
从我的角度来看,我所做的只是运行git pull
,它摧毁了我的整个本地存储库。我并不是说它“搞乱了签出的版本”或“我所在的分支”或类似的东西。我是说一切都消失了。
这是事件发生时我的终端的屏幕截图:
让我带您了解一下。我的命令提示符包含有关当前 git 存储库的数据(使用 prezto 的 vcs_info 实现),以便您可以看到 git 存储库何时消失。第一个命令很正常:
» caleb » jaguar » ~/p/w/incil.info » ◼ zend ★ »
❯❯❯ git co master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
在那里你可以看到我在“zend”分支上,并检查了 master。到目前为止,一切都很好。您将在我的下一个命令之前的提示中看到它成功切换了分支:
» caleb » jaguar » ~/p/w/incil.info » ◼ master ★ »
❯❯❯ git pull
remote: Counting objects: 37, done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 37 (delta 25), reused 0 (delta 0)
Unpacking objects: 100% (37/37), done.
From gitlab.alerque.com:ipk/incil.info
+ 7412a21...eca4d26 master -> origin/master (forced update)
f03fa5d..c8ea00b devel -> origin/devel
+ 2af282c...009b8ec verse-spinner -> origin/verse-spinner (forced update)
First, rewinding head to replay your work on top of it...
>>> elapsed time 11s
就这样它就消失了。如果经过时间超过 10 秒,则在下一个提示之前输出经过时间标记。 Git 没有给出任何输出,除了通知它正在倒回重放之外。没有任何迹象表明它已经完成。
下一个提示不包含有关我们所在分支或 git 状态的数据。
我没有注意到它失败了,我无意中尝试运行另一个 git 命令,却被告知我不在 git 存储库中。请注意 PWD 未更改:
» caleb » jaguar » ~/p/w/incil.info »
❯❯❯ git fetch --all
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
之后环顾四周,发现我处于一个完全空的目录中。没有什么。没有“.git”目录,什么也没有。空的。
我本地的git版本是2.0.2。以下是我的 git 配置中的一些花絮,可能与弄清楚发生了什么有关:
[branch]
autosetuprebase = always
rebase = preserve
[pull]
rebase = true
[rebase]
autosquash = true
autostash = true
[alias]
co = checkout
例如,我git pull
设置为始终进行变基而不是合并,因此上面的输出部分是正常的。
我可以恢复数据。我认为除了一些不重要的存储之外没有任何 git 对象没有被推送到其他存储库,但是我想知道发生了什么事。
我已经检查过:
- dmesg 或 systemd 日志中的消息。没有任何相关的东西。
- 没有迹象表明驱动器或文件系统出现故障(LVM + LUKS + EXT4 看起来都正常)。失物招领中什么也没有。
- 我没有运行其他任何东西。上面没有显示任何历史记录,并且在此期间没有使用其他终端。没有
rm
可能在错误的 CWD 中执行的命令等。 - 戳另一个目录中的另一个 git repo 显示执行
git pull
s 没有明显的异常。
我还应该在这里寻找什么?
答案1
是的,git
吃了我的作业。所有的。
dd
事件发生后,我制作了这张磁盘的映像,并在稍后对其进行了修改。从系统日志中重构一系列事件,我推断发生的事情是这样的:
pacman -Syu
在此事件发生前几天,已发出系统更新命令 ( )。- 长时间的网络中断意味着它必须重新尝试下载软件包。由于缺乏互联网而感到沮丧,我会让系统进入睡眠状态然后上床睡觉。
- 几天后,系统被唤醒,并开始再次查找和下载软件包。
- 在我碰巧摆弄这个存储库之前的某个时候,软件包下载已经完成。
- 系统glibc安装在 之前
git checkout
和之后进行了更新git pull
。 - 二进制文件在启动后和完成前
git
被替换。git pull
- 第七天,
git
一切劳作都休息了。并删除了世界,所以其他人也必须休息。
我不知道确切地发生了什么竞争条件导致了这种情况的发生,但是在操作中间交换二进制文件肯定不是很好,也不是可测试/可重复的条件。通常,正在运行的二进制文件的副本存储在内存中,但这git
很奇怪,而且它重新生成自身版本的方式我确信导致了这种混乱。显然它应该死而不是毁灭一切,但事实就是这样。
答案2
可能是由于未能定义要删除的文件路径。
你的案例让我想起了美好的一天,当我的自制remove(path)
方法尝试删除根文件夹时,因为给定的参数是空字符串,操作系统将其纠正为根文件夹(!)。
这可能是一个类似的 git bug。这样:
- Rebase 命令想要删除一个文件,例如
remove(project_folder + file_path)
(伪代码) - 不知怎的,
file_path
当时是空的。 - 命令评估为类似的东西
remove(project_folder)
答案3
幸运的话,您可以使用以下命令修复此问题:
git reset --hard ORIG_HEAD
当潜在的危险更改开始时,git 会将您当前的状态存储在 ORIG_HEAD 中。使用它您可以撤消合并或变基。
答案4
看起来有人运行了git push --force
这个存储库,并且您撤下了这些更改。尝试克隆新的存储库,这应该会让您再次回到干净的工作状态。