由于包对象失败,git fetch失败

时间:2014-01-26 04:39:47

标签: git git-clone git-fetch

当我将远程存储库添加为上游并尝试获取它时,它会失败,如下所示:

    $ git fetch upstream
    remote: Counting objects: 11901, done.
    remote: aborting due to possible repository corruption on the remote side.
    error: pack-objects died of signal 9
    error: git upload-pack: git-pack-objects died with error.
    fatal: git upload-pack: aborting due to possible repository corruption on the re
    mote side.
    fatal: protocol error: bad pack header

据我所知,由于存储库中存在大量文件(我们确实拥有),它失败了,但为什么克隆相同的存储库时它不会失败?因为我能够成功克隆存储库。不应该在克隆请求时打包相同的对象吗?

2 个答案:

答案 0 :(得分:12)

VonC's answer上展开一点......

首先,可能有助于注意signal 9引用SIGKILL并且往往会发生因为所讨论的远程主机是Linux主机并且Linux正在销毁该进程"OOM killer" (尽管一些非Linux系统的行为类似)。

接下来,我们来谈谈对象和包文件。 git“对象”是在git存储库中找到的四种类型的项目之一:“blob”(文件);一个“树”(一个blob列表,它们的模式,以及它们的名称 - 存储在一个目录中:即,当解压缩提交时将成为目录或文件夹的内容); “提交”(在其他数据中提供提交作者,消息和顶级树);和“标签”(带注释的标签)。对象可以存储为“松散对象”,文件中的一个对象全部存在;但是这些可能会占用大量的磁盘空间,因此可以将它们“打包”,将许多对象放入一个文件中并添加额外的压缩。

从大量松散的对象中制作一个包,进行这种压缩,是(或至少可以)一个cpu和内存密集型操作。所需的内存量取决于对象的数量及其基础大小:大文件占用更多内存。许多大文件占用了大量内存。

接下来,正如VonC所说,git clone跳过尝试使用“瘦”包(好吧,通常无论如何)。这意味着服务器只提供它已有的包文件。这是一种“内存便宜”的操作:文件已经存在,服务器只需要提供它们。

另一方面,git fetch尝试(如果可以),以避免发送客户端已有的大量数据。使用“智能”协议,客户端和服务器进行某种对话,您可以将其视为如下所示:

  • “我有对象A,需要B和C;你有B和C吗?我也有D,E和F.”
  • “我有B,但我需要C,我有D和E;请寄给我A,C和F.”

如此通知,服务器从原始包中提取“有趣”/“想要”的对象,然后尝试将它们压缩成新的(但“瘦”)包。这意味着服务器将调用git-pack-objects

如果服务器内存不足(“低”相对于git-pack-objects需要的量),则可能会调用“OOM杀手”。由于git-pack-objects是内存密集型的,因此该过程很可能成为杀死“OOM杀手”的候选者。然后,您会在客户端看到有关git-pack-objects signal 9SIGKILL)死亡的消息。

(当然,服务器的OOM杀手可能会完全杀掉其他东西,比如bug数据库服务器。:-))

答案 1 :(得分:3)

它可能取决于协议,但Documentation/technical/pack-heuristics.txt指出了克隆和提取之间的第一个区别。

  

另一方面,fetch,git-fetch-packgit-clone-pack在另一端调用git-upload-pack(通过ssh或与守护进程通话)。

     

有两种情况:

     
      
  • clone-packfetch-pack-k将保留下载的packfile而不展开,因此我们不使用精简包转移。
  •   
  • 否则,生成的包将在同一包中具有不带基础对象的delta。
  •   
     

但没有fetch-pack的{​​{1}}会将收到的包爆炸成单个对象,因此如果{{1}我们会自动询问-k give us a thin pack 支持它。

因此,就协议而言,Documentation/technical/pack-protocol.txt说明了一个fetch可以返回比git clone更多的数据。