简体中文 ▾ 主题 ▾ 最新版本 ▾ git-pack-objects 最后更新于 2.52.0

名称

git-pack-objects - 创建对象的打包归档

概要

git pack-objects [-q | --progress | --all-progress] [--all-progress-implied]
		   [--no-reuse-delta] [--delta-base-offset] [--non-empty]
		   [--local] [--incremental] [--window=<n>] [--depth=<n>]
		   [--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
		   [--cruft] [--cruft-expiration=<time>]
		   [--stdout [--filter=<filter-spec>] | <base-name>]
		   [--shallow] [--keep-true-parents] [--[no-]sparse]
		   [--name-hash-version=<n>] [--path-walk] < <object-list>

描述

从标准输入读取对象列表,并将指定基础名称的一个或多个打包归档写入磁盘,或将打包归档写入标准输出。

打包归档是一种在两个仓库之间高效传输一组对象的方式,也是一种访问高效的归档格式。在打包归档中,对象要么被存储为压缩的整体,要么作为与其他对象的差异。后者通常称为 delta。

打包归档格式(.pack)被设计成自包含的,以便无需额外信息即可解包。因此,delta 所依赖的每个对象都必须存在于 pack 中。

会生成 pack 索引文件(.idx),以实现对 pack 中对象的快速、随机访问。将索引文件(.idx)和打包归档(.pack)都放在 $GIT_OBJECT_DIRECTORY 的 pack/ 子目录中(或 $GIT_ALTERNATE_OBJECT_DIRECTORIES 中的任何目录),可以使 Git 从打包归档中读取。

git unpack-objects 命令可以读取打包归档,并将 pack 中包含的对象扩展为“一个文件一个对象”的格式;这通常由智能拉取命令完成,当 pack 为了通过其对等方进行高效网络传输而实时创建时。

选项

base-name

写入文件对(.pack 和 .idx),使用 <base-name> 来确定创建文件的名称。使用此选项时,一对文件将写入 <base-name>-<SHA-1>.{pack,idx} 文件。 <SHA-1> 是基于 pack 内容的哈希,并写入命令的标准输出。

--stdout

将 pack 内容(将被写入 .pack 文件的内容)输出到标准输出。

--revs

从标准输入读取修订参数,而不是单个对象名称。修订参数的处理方式与 git rev-list 使用 --objects 标志处理其 commit 参数来构建其输出的对象列表的方式相同。结果列表中的对象将被打包。除了修订,--not--shallow <SHA-1> 行也接受。

--unpacked

这隐含了 --revs。在处理从标准输入读取的修订参数列表时,将打包的对象限制为那些尚未打包的对象。

--all

这隐含了 --revs。除了从标准输入读取的修订参数列表外,还会假定 refs/ 下的所有引用都指定为包含在内。

--include-tag

如果它们引用的对象已包含在生成的 packfile 中,则包含未请求的注释标签。这对于将新标签发送到原生 Git 客户端可能很有用。

--stdin-packs[=<mode>]

从标准输入读取 packfile 的基名称(例如,pack-1234abcd.pack),而不是对象名称或修订参数。生成的 pack 将包含已包含 pack 中列出的所有对象(不以 ^ 开头的),排除任何已排除 pack 中列出的对象(以 ^ 开头的)。

mode 为 "follow" 时,来自未列出 pack 的对象将受到特殊处理。如果一个对象(1)可从包含的 pack 中访问,并且(2)不在任何已排除的 pack 中,则该对象将被包含。此模式对于例如恢复 cruft pack 中一度不可访问的对象以生成 pack 非常有用,这些 pack 在已排除 pack 设定的边界内是可访问的。

--revs 或隐含 --revs 的选项(例如 --all)不兼容,但与 --unpacked 兼容。

--cruft

将不可访问的对象打包到一个单独的“cruft” pack 中,通过存在一个 .mtimes 文件来表示。通常由 git repack --cruft 使用。调用者提供 pack 名称列表,并指示哪些 pack 将保留在仓库中,以及哪些 pack 将被删除(由 - 前缀指示)。cruft pack 的内容是所有不包含在已保留 pack 中且未超过宽限期(请参阅下面的 --cruft-expiration)的对象,或者已超过宽限期但可从尚未超过宽限期的其他对象访问的对象。

当输入列表包含一个 pack,该 pack 包含所有可访问对象(并将所有其他 pack 列为待删除)时,相应的 cruft pack 将包含所有不可访问的对象(mtime 新于 --cruft-expiration)以及任何 mtime 旧于 --cruft-expiration 但可从 mtime 新于 --cruft-expiration 的不可访问对象的可访问对象。

--unpack-unreachable--keep-unreachable--pack-loose-unreachable--stdin-packs 以及任何隐含 --revs 的选项不兼容。

--cruft-expiration=<approxidate>

如果指定,则从 cruft pack 中删除 mtime 早于 <approxidate> 的对象。如果未指定(且给出了 --cruft),则不会删除任何对象。

--window=<n>
--depth=<n>

这两个选项会影响 pack 中包含的对象如何使用 delta 压缩存储。对象首先按类型、大小和可选名称进行内部排序,并与 --window 内的其他对象进行比较,以查看使用 delta 压缩是否可以节省空间。--depth 限制了最大 delta 深度;过深的 delta 会影响解包器的性能,因为 delta 数据需要多次应用才能获得所需的对象。

--window 的默认值为 10,--depth 的默认值为 50。最大深度为 4095。

--window-memory=<n>

此选项在 --window 之上提供了额外的限制;窗口大小将动态缩放,以不超过 <n> 字节内存。这在包含大量和大对象混合的存储库中很有用,以避免使用大窗口时耗尽内存,同时仍能利用大窗口处理小对象。大小可以后缀 "k"、"m" 或 "g"。 --window-memory=0 使内存使用不受限制。默认值取自 pack.windowMemory 配置变量。

--max-pack-size=<n>

在不寻常的情况下,您可能无法在文件系统上创建大于特定大小的文件,此选项可用于告诉命令将输出 packfile 分割成多个独立的 packfile,每个 packfile 不大于给定大小。大小可以后缀 "k"、"m" 或 "g"。允许的最小大小限制为 1 MiB。默认是不限制,除非设置了配置变量 pack.packSizeLimit。请注意,此选项可能会导致存储库更大且更慢;请参阅 pack.packSizeLimit 中的讨论。

--honor-pack-keep

此标志会忽略对象是否已存在于本地 pack 中并具有 .keep 文件,即使它原本会被打包。

--keep-pack=<pack-name>

此标志会忽略对象是否已存在于指定的 pack 中,即使它原本会被打包。 <pack-name> 是 pack 文件名,不带前导目录(例如 pack-123.pack)。可以多次指定该选项以保留多个 pack。

--incremental

此标志会忽略对象是否已存在于 pack 中,即使它原本会被打包。

--local

此标志会忽略从备用对象存储借用的对象,即使它原本会被打包。

--non-empty

仅当打包归档包含至少一个对象时才创建它。

--progress

默认情况下,当标准错误流连接到终端时,会报告进度状态,除非指定了 -q。此标志强制报告进度状态,即使标准错误流未定向到终端。

--all-progress

当指定 --stdout 时,在对象计数和压缩阶段会显示进度报告,但在写入阶段会抑制。原因是,在某些情况下,输出流直接链接到另一个可能希望显示其自身进度的命令,该命令正在处理传入的 pack 数据。此标志与 --progress 类似,除了它即使在使用 --stdout 时也会强制显示写入阶段的进度报告。

--all-progress-implied

这用于在激活进度显示时隐含 --all-progress。与 --all-progress 不同,此标志本身不会强制显示任何进度。

-q

此标志使命令不报告标准错误流上的进度。

--no-reuse-delta

在仓库中创建打包归档时,如果存在现有 pack,命令会重用现有的 delta 以避免即时搜索新的 delta。这有时会导致 pack 稍有欠佳。此标志告诉命令不要重用现有 delta,而是从头开始计算它们。

--no-reuse-object

此标志告诉命令完全不重用现有的对象数据,包括非 delta 对象,强制重新压缩所有内容。这隐含了 --no-reuse-delta。仅在需要对打包数据进行整体强制不同压缩级别的情况下使用。

--compression=<n>

指定生成 pack 中新压缩数据的压缩级别。如果未指定,pack 压缩级别首先由 pack.compression 确定,然后由 core.compression 确定,如果两者都未设置,则默认为 -1(zlib 默认值)。添加 --no-reuse-object 以强制对所有数据使用统一的压缩级别,无论其来源如何。

--sparse
--no-sparse

切换 "sparse" 算法来确定在组合使用 "--revs" 选项时要包含在 pack 中的对象。此算法仅遍历引入新对象的路径中出现的树。在计算要发送小型更改的 pack 时,这可以带来显著的性能优势。但是,如果包含的提交包含某些类型的直接重命名,则可能会有额外的对象被添加到 pack-file 中。如果未包含此选项,则默认为 pack.useSparse 的值,该值为 true,除非另有指定。

--thin

通过省略发送方和接收方之间的公共对象来创建“thin” pack,以减少网络传输。此选项仅在与 --stdout 结合使用时才有意义。

注意:thin pack 通过省略必需的对象来违反打包归档格式,因此在不使其自包含的情况下无法被 Git 使用。使用 git index-pack --fix-thin(请参阅 git-index-pack[1])来恢复自包含属性。

--shallow

优化将提供给客户端的 shallow repository 的 pack。此选项与 --thin 结合使用,可以以速度为代价获得更小的 pack。

--delta-base-offset

打包归档可以将 delta 的基对象表示为 20 字节的对象名称或流中的偏移量,但旧版本的 Git 不理解后者。默认情况下,git pack-objects 为了更好的兼容性只使用前者。此选项允许命令使用后者来减小尺寸。根据平均 delta 链长度,此选项通常会使生成的 packfile 缩小 3-5%。

注意:porcelain 命令,如 git gc(请参阅 git-gc[1])、git repack(请参阅 git-repack[1])在将对象打包到 pack 文件时,在现代 Git 中默认会传递此选项。 git bundle(请参阅 git-bundle[1])在创建 bundle 时也会。

--threads=<n>

指定生成线程数量来搜索最佳 delta 匹配。这要求 pack-objects 使用 pthreads 进行编译,否则此选项将被忽略并发出警告。目的是减少多处理器机器上的打包时间。但是,delta 搜索窗口所需的内存量会乘以线程数。指定 0 将导致 Git 自动检测 CPU 数量并相应地设置线程数。

--index-version=<version>[,<offset>]

这仅供测试套件使用。它允许强制生成 pack 索引的版本,并强制 64 位索引条目应用于给定偏移量以上的对象。

--keep-true-parents

使用此选项,即使父母被 grafts 隐藏,也会被打包。

--filter=<filter-spec>

从生成的 packfile 中省略某些对象(通常是 blobs)。请参阅 git-rev-list[1] 以了解有效的 <filter-spec> 格式。

--no-filter

关闭任何先前的 --filter= 参数。

--missing=<missing-action>

一个用于帮助未来“部分克隆”开发的调试选项。此选项指定如何处理缺失的对象。

形式 --missing=error 要求 pack-objects 在遇到缺失对象时停止并报错。如果存储库是部分克隆,将在声明对象缺失之前尝试获取缺失的对象。这是默认操作。

形式 --missing=allow-any 允许在遇到缺失对象时继续对象遍历。不会尝试获取缺失的对象。缺失的对象将被静默地从结果中省略。

形式 --missing=allow-promisor 类似于 allow-any,但仅允许对于预期的 promisor 缺失对象继续对象遍历。不会尝试获取缺失的对象。意外的缺失对象将引发错误。

--exclude-promisor-objects

省略已知存在于 promisor 远程的对象。(此选项的目的是仅在本地创建的对象上操作,以便在我们重新打包时,仍然保持本地创建的对象[无 .promisor]与来自 promisor 远程的对象[带 .promisor]之间的区别。)这用于部分克隆。

--keep-unreachable

除了可访问且不在被标记为 *.keep 文件的 pack 中的对象外,还会将 --unpacked= 选项命名的 pack 中的引用所无法访问的对象添加到结果 pack 中。这隐含了 --revs

--pack-loose-unreachable

打包不可访问的 loose 对象(并移除它们的 loose 对等体)。这隐含了 --revs

--unpack-unreachable

将不可访问的对象保留为 loose 形式。这隐含了 --revs

--delta-islands

根据“islands”(岛屿)限制 delta 匹配。请参阅下面的 DELTA ISLANDS。

--name-hash-version=<n>

在执行 delta 压缩时,Git 会根据启发式方法使用对象的路径来对可能相似的对象进行分组。虽然按精确路径匹配分组对象对于具有许多版本的路径很有用,但在查找跨不同完整路径的 delta 对时也有好处。Git 按类型收集对象,然后按路径的“名称哈希”分组,再按大小分组,希望能将能够很好地压缩的对象组合在一起。

默认的名称哈希版本是 1,它通过考虑路径的最后字节作为对哈希函数提供最大幅度来优先考虑哈希局部性。此版本在区分短路径和查找跨目录的重命名方面表现出色。然而,哈希函数主要依赖于路径的最后 16 个字节。如果存储库中有许多路径具有相同的最后 16 个字节,并且仅在父目录上有所不同,那么此名称哈希可能会导致过多的冲突并导致结果不佳。目前,在写入具有 --write-bitmap-index 的可访问性位图文件时,需要此版本。

名称哈希版本 2 具有与版本 1 相似的局部性特征,但它分别考虑每个路径组件,并通过移位叠加哈希。这仍然优先考虑路径的最后字节,但还通过父目录名称“加盐”哈希的低位。此方法允许保留版本 1 的一些局部性优势,同时打破了在许多不同目录中出现的相似命名文件的大多数冲突。目前,在写入具有 --write-bitmap-index 的可访问性位图文件时,不允许使用此版本,它将被自动更改为版本 1

--path-walk

通过首先按路径组织对象,然后进行第二次跨路径正常压缩来执行压缩。这有可能改善 delta 压缩,尤其是在文件名导致 Git 默认名称哈希算法发生冲突的情况下。

--delta-islands--shallow--filter 不兼容。在存在 --path-walk 的情况下,--use-bitmap-index 选项将被忽略。

Delta 岛屿

在可能的情况下,pack-objects 会尝试重用现有的磁盘 delta,以避免即时搜索新的 delta。这是服务 fetches 的一项重要优化,因为它意味着服务器可以避免解压大部分对象,而只需直接从磁盘发送字节。当一个对象作为 delta 存储在一个接收方没有(并且我们还没有发送)的基对象上时,此优化无法生效。在这种情况下,服务器会“破坏”delta,必须寻找一个新的,这会带来很高的 CPU 成本。因此,对于性能来说,磁盘 delta 关系中的对象集与客户端将要获取的对象集相匹配非常重要。

在一个普通的存储库中,这通常会自动实现。对象大多可从分支和标签访问,这也是客户端获取的内容。在服务器上找到的任何 delta 都可能是在客户端拥有或将要拥有的对象之间。

但在某些存储库设置中,您可能拥有多个相关但独立的 ref 尖端组,而客户端倾向于独立地获取这些组。例如,假设您在一个共享对象存储中托管一个存储库的多个“fork”,并通过 GIT_NAMESPACE 或使用 alternates 机制的独立存储库允许客户端将它们视为单独的存储库。一个朴素的 repack 可能会发现一个对象的最佳 delta 是针对只存在于另一个 fork 中的基对象。但是当客户端获取时,他们将没有基对象,我们必须即时寻找一个新的 delta。

如果您在 refs/heads/refs/tags/ 之外拥有许多指向相关对象的引用(例如,某些托管提供商使用的 refs/pullrefs/changes),则可能存在类似的情况。默认情况下,客户端仅获取 heads 和 tags,而针对仅存在于那些其他组中的对象的 delta 不能按原样发送。

Delta 岛屿通过允许您将 ref 分组到不同的“岛屿”来解决此问题。Pack-objects 计算哪些对象可从哪些岛屿访问,并拒绝从一个对象 A 创建一个 delta,其基对象不存在于 A 的所有岛屿中。这会导致 pack 稍大(因为我们错过了一些 delta 机会),但保证获取一个岛屿不会因为跨越岛屿边界而需要即时重新计算 delta。

在与 delta 岛屿一起 repack 时,delta 窗口倾向于被配置所禁止的候选者堵塞。使用大的 --window 进行 repack 有所帮助(并且由于我们可以基于岛屿在任何计算之前拒绝一些对象对,因此花费的时间不会像其他情况那样长)。

岛屿通过 pack.island 选项进行配置,该选项可以重复指定。每个值都是一个左锚定的正则表达式,匹配 refname。例如

[pack]
island = refs/heads/
island = refs/tags/

将 heads 和 tags 放入一个岛屿(其名称为空字符串;有关命名,请参阅下文)。任何不匹配这些正则表达式的 ref(例如 refs/pull/123)都不在任何岛屿中。因此,仅从 refs/pull/(而不是 heads 或 tags)访问的任何对象都不是 refs/heads/ 的基对象的候选。

Ref 根据其“名称”分组到岛屿中,并且产生相同名称的两个正则表达式被视为属于同一个岛屿。名称是从正则表达式通过连接正则表达式的任何捕获组计算得出的,捕获组之间用破折号 - 分隔。(如果没有捕获组,则名称为空字符串,如上例所示。)这允许您创建任意数量的岛屿。但最多支持 14 个此类捕获组。

例如,假设您将每个 fork 的 ref 存储在 refs/virtual/ID 中,其中 ID 是一个数字标识符。然后,您可以配置

[pack]
island = refs/virtual/([0-9]+)/heads/
island = refs/virtual/([0-9]+)/tags/
island = refs/virtual/([0-9]+)/(pull)/

这将每个 fork 的 heads 和 tags 放入它们自己的岛屿(名称为“1234”或类似名称),并将每个 fork 的 pull refs 放入它们自己的“1234-pull”岛屿。

请注意,我们为每个正则表达式选择一个岛屿,使用“后一个优先”的顺序(这允许仓库特定的配置优先于用户范围的配置,依此类推)。

配置

各种配置变量会影响打包,请参阅 git-config[1](搜索“pack”和“delta”)。

值得注意的是,delta 压缩不用于大于 core.bigFileThreshold 配置变量的对象,以及属性 delta 设置为 false 的文件。

GIT

Git[1] 套件的一部分