`git pull` 是怎么吃掉我的作业的?

Cal*_*leb 53 debugging git data-recovery

我感觉就像校长办公室里的一个孩子,解释说我的作业在到期前一天晚上被狗吃掉了,但我正盯着脸上的一些疯狂的数据丢失错误,我无法弄清楚它是怎么发生的。我想知道 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'.
Run Code Online (Sandbox Code Playgroud)

在那里你可以看到我在 '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
Run Code Online (Sandbox Code Playgroud)

就这样它消失了。如果超过 10 秒,则经过时间标记在下一个提示之前输出。除了正在倒带重放的通知之外,Git 没有给出任何输出。没有迹象表明它完成了。

下一个提示不包含有关我们所在的分支或 git 状态的数据。

没有注意到它失败了,我无意中尝试运行另一个 git 命令却被告知我不在 git repo 中。注意 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).
Run Code Online (Sandbox Code Playgroud)

之后环顾四周,发现我在一个完全空的目录中。没有。没有“.git”目录,什么都没有。空的。

我的本地 git 版本为 2.0.2。以下是我的 git 配置中的一些花絮,可能与弄清楚发生了什么有关:

[branch]
        autosetuprebase = always
        rebase = preserve
[pull]
        rebase = true
[rebase]
        autosquash = true
        autostash = true
[alias]
        co = checkout
Run Code Online (Sandbox Code Playgroud)

例如,我已git pull设置为始终执行变基而不是合并,因此上面的部分输出是正常的。

我可以恢复数据。我认为除了一些没有被推送到其他存储库的不重要的隐藏之外,没有任何 git 对象,但我想知道发生了什么

我已经检查过:

  • dmesg 或 systemd 日志中的消息。甚至没有任何相关性。
  • 没有驱动器或文件系统故障的迹象(LVM + LUKS + EXT4 看起来都正常)。在lost+found中没有任何东西。
  • 我没有运行其他任何东西。上面没有我没有显示的历史记录,在此期间没有使用其他终端。没有rm可能在错误的 CWD 中执行的命令,等等。
  • 戳另一个目录下的另一个git repo,执行git pulls没有明显异常。

我还应该在这里寻找什么?

Cal*_*leb 6

是的,git吃了我的作业。所有的。

dd在事件发生后制作了这张磁盘的图像,后来又把它弄乱了。从系统日志中重建一系列事件,我推断发生的事情是这样的:

  1. 系统更新命令 ( pacman -Syu) 已在此事件发生前几天发出。
  2. 长时间的网络中断意味着它不得不重新尝试下载软件包。由于缺乏互联网而感到沮丧,我让系统进入睡眠状态并上床睡觉。
  3. 几天后系统被唤醒,它再次开始查找和下载软件包。
  4. 包下载在我碰巧弄乱这个存储库之前的某个时间完成了。
  5. 系统glibc安装git checkoutgit pull.
  6. git二进制得到更换后git pull开始,之前完成。
  7. 到了第七天,git就歇了一切劳碌。并删除了世界,所以其他人也不得不休息。

我不知道究竟是什么竞争条件导致了这种情况发生,但是在操作中间换出二进制文件肯定不是很好,也不是可测试/可重复的条件。通常,正在运行的二进制文件的副本存储在内存中,但git很奇怪,而且关于它重新生成自身版本的方式,我肯定会导致这种混乱。显然它应该死而不是摧毁一切,但这就是发生的事情。