当我将远程存储库添加为上游并尝试获取它时,它会失败,如下所示:
$ 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
据我所知,由于存储库中存在大量文件(我们确实拥有),它失败了,但为什么克隆相同的存储库时它不会失败?因为我能够成功克隆存储库。不应该在克隆请求时打包相同的对象吗?
答案 0 :(得分:12)
在VonC's answer上展开一点......
首先,可能有助于注意signal 9
引用SIGKILL
并且往往会发生因为所讨论的远程主机是Linux主机并且Linux正在销毁该进程"OOM killer" (尽管一些非Linux系统的行为类似)。
接下来,我们来谈谈对象和包文件。 git“对象”是在git存储库中找到的四种类型的项目之一:“blob”(文件);一个“树”(一个blob列表,它们的模式,以及它们的名称 - 存储在一个目录中:即,当解压缩提交时将成为目录或文件夹的内容); “提交”(在其他数据中提供提交作者,消息和顶级树);和“标签”(带注释的标签)。对象可以存储为“松散对象”,文件中的一个对象全部存在;但是这些可能会占用大量的磁盘空间,因此可以将它们“打包”,将许多对象放入一个文件中并添加额外的压缩。
从大量松散的对象中制作一个包,进行这种压缩,是(或至少可以)一个cpu和内存密集型操作。所需的内存量取决于对象的数量及其基础大小:大文件占用更多内存。许多大文件占用了大量内存。
接下来,正如VonC所说,git clone
跳过尝试使用“瘦”包(好吧,通常无论如何)。这意味着服务器只提供它已有的包文件。这是一种“内存便宜”的操作:文件已经存在,服务器只需要提供它们。
另一方面,git fetch
尝试(如果可以),以避免发送客户端已有的大量数据。使用“智能”协议,客户端和服务器进行某种对话,您可以将其视为如下所示:
如此通知,服务器从原始包中提取“有趣”/“想要”的对象,然后尝试将它们压缩成新的(但“瘦”)包。这意味着服务器将调用git-pack-objects
。
如果服务器内存不足(“低”相对于git-pack-objects
需要的量),则可能会调用“OOM杀手”。由于git-pack-objects
是内存密集型的,因此该过程很可能成为杀死“OOM杀手”的候选者。然后,您会在客户端看到有关git-pack-objects
signal 9
(SIGKILL
)死亡的消息。
(当然,服务器的OOM杀手可能会完全杀掉其他东西,比如bug数据库服务器。:-))
答案 1 :(得分:3)
它可能取决于协议,但Documentation/technical/pack-heuristics.txt
指出了克隆和提取之间的第一个区别。
另一方面,fetch,
git-fetch-pack
和git-clone-pack
在另一端调用git-upload-pack
(通过ssh或与守护进程通话)。有两种情况:
clone-pack
和fetch-pack
与-k
将保留下载的packfile而不展开,因此我们不使用精简包转移。- 否则,生成的包将在同一包中具有不带基础对象的delta。
但没有
fetch-pack
的{{1}}会将收到的包爆炸成单个对象,因此如果{{1}我们会自动询问-k
give us a thin pack 支持它。
因此,就协议而言,Documentation/technical/pack-protocol.txt
说明了一个fetch可以返回比git clone更多的数据。