6

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

    $ 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

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

4

2 回答 2

12

为了扩展VonC 的答案......

首先,它可能有助于注意,因为signal 9SIGKILL讨论的远程是 Linux 主机,并且该进程正在被 Linux “OOM 杀手”破坏(尽管某些非 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 9( SIGKILL) 的消息。

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

于 2014-01-26T10:33:29.280 回答
3

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

在另一个方向,获取,git-fetch-pack并在另一端git-clone-pack调用git-upload-pack(通过 ssh 或通过与守护进程交谈)。

有两种情况:

  • clone-pack并且fetch-packwith-k将保持下载的包文件不展开,所以我们不使用瘦包传输。
  • 否则,生成的包将在同一个包中包含没有基础对象的增量。

但是fetch-pack没有-k会将收到的包分解为单个对象,因此如果支持它,我们会自动要求upload-pack我们一个薄包。upload-pack

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

于 2014-01-26T08:34:13.203 回答