设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
-
2.49.0
2025-03-14
- 2.48.1 无更改
-
2.48.0
2025-01-10
- 2.43.1 → 2.47.2 无更改
-
2.43.0
2023-11-20
- 2.38.1 → 2.42.4 无更改
-
2.38.0
2022-10-02
- 2.36.1 → 2.37.7 无更改
-
2.36.0
2022-04-18
- 2.33.1 → 2.35.8 无更改
-
2.33.0
2021-08-16
- 2.29.1 → 2.32.7 无更改
-
2.29.0
2020-10-19
- 2.25.1 → 2.28.1 无更改
-
2.25.0
2020-01-13
- 2.24.1 → 2.24.4 无更改
-
2.24.0
2019-11-04
- 2.21.1 → 2.23.4 无更改
-
2.21.0
2019-02-24
- 2.19.1 → 2.20.5 无更改
-
2.19.0
2018-09-10
- 2.17.0 → 2.18.5 无更改
-
2.16.6
2019-12-06
"Partial Clone"(部分克隆)功能是 Git 的一种性能优化,它允许 Git 在没有完整仓库副本的情况下运行。这项工作的目标是使 Git 能够更好地处理非常大的仓库。
在克隆和获取操作期间,Git 会下载仓库的完整内容和历史记录。这包括仓库整个生命周期中的所有提交、树和 blob。对于非常大的仓库,克隆可能需要数小时(或数天)并消耗 100+GiB 的磁盘空间。
通常,在这些仓库中,用户不需要许多 blob 和树,例如
-
树中用户工作区之外的文件。例如,在一个每次提交都有 50 万个目录和 350 万个文件的仓库中,如果用户只需要源树的一个狭窄的“锥形”区域,我们可以避免下载许多对象。
-
大型二进制资源。例如,在一个大型构建工件被检入树中的仓库中,我们可以避免下载这些不可合并的二进制资产的所有先前版本,而只下载实际引用的版本。
部分克隆允许我们在克隆和获取操作期间预先避免下载此类不需要的对象,从而减少下载时间和磁盘使用量。如果需要,以后可以“按需获取”丢失的对象。
以后可以提供丢失对象的远程仓库称为 promisor remote(承诺者远程仓库),因为它承诺在请求时发送对象。最初,Git 仅支持一个 promisor remote,即用户克隆的 origin remote,该远程仓库在 "extensions.partialClone" 配置选项中配置。后来实现了对多个 promisor remote 的支持。
使用部分克隆要求用户在线,并且 origin remote 或其他 promisor remote 可用于按需获取丢失的对象。这对用户来说可能有问题,也可能没有问题。例如,如果用户可以停留在预先选择的源树子集中,他们可能不会遇到任何丢失的对象。或者,如果用户知道他们要离线,他们可以尝试预先获取各种对象。
非目标
部分克隆是一种限制在给定提交范围内下载的 blob 和 tree 数量的机制,因此独立于且不打算与现有的 DAG 级别的机制冲突,这些机制用于限制请求的提交集(即浅克隆、单个分支或获取 *<refspec>*)。
设计概述
部分克隆逻辑上由以下部分组成
-
客户端向服务器描述不需要或不想要的对象的机制。
-
服务器从发送到客户端的 packfile 中省略此类不需要的对象的机制。
-
客户端优雅地处理丢失的对象(以前由服务器省略)的机制。
-
客户端根据需要反向填充丢失的对象的机制。
设计细节
-
一个新的 pack-protocol 功能 "filter" 被添加到 fetch-pack 和 upload-pack 协商中。
这使用现有的功能发现机制。请参阅 gitprotocol-pack[5] 中的 "filter"。
-
客户端将 "filter-spec" 传递给克隆和获取,该 "filter-spec" 传递给服务器以请求在 packfile 构造期间进行过滤。
有各种可用的过滤器来适应不同的情况。请参阅 Documentation/rev-list-options.adoc 中的 "--filter=<filter-spec>"。
-
在服务器上,pack-objects 在为客户端创建“过滤的” packfile 时应用请求的 filter-spec。
从传统意义上讲,这些过滤的 packfile 是不完整的,因为它们可能包含引用 packfile 中未包含且客户端尚未拥有的对象的对象。例如,过滤的 packfile 可能包含引用丢失的 blob 的树或引用丢失的树的提交。
-
在客户端上,这些不完整的 packfile 被标记为 "promisor packfile",并被各种命令以不同的方式处理。
-
在客户端上,本地配置中添加了一个仓库扩展,以防止旧版本的 Git 由于它们无法处理的丢失对象而导致操作中途失败。请参阅 git-config[1] 中的
extensions.partialClone
。
处理丢失的对象
-
对象可能由于部分克隆或获取而丢失,或者由于仓库损坏而丢失。为了区分这些情况,本地仓库专门将从 promisor remote 获取的此类过滤的 packfile 指示为 "promisor packfile"。
这些 promisor packfile 除了它们的 "<name>.pack" 和 "<name>.idx" 文件之外,还包含一个具有任意内容的 "<name>.promisor" 文件(如 "<name>.keep" 文件)。
-
本地仓库认为 "promisor object" 是一个它知道(尽其所能)promisor remote 承诺拥有的对象,或者是因为本地仓库在其 promisor packfile 之一中拥有该对象,或者是因为另一个 promisor object 引用了它。
当 Git 遇到丢失的对象时,Git 可以查看它是否是一个 promisor object 并适当地处理它。如果不是,Git 可以报告损坏。
这意味着客户端不需要显式维护一个难以修改的丢失对象列表。[a]
-
由于几乎所有 Git 代码目前都期望任何引用的对象都存在于本地,并且因为我们不想强制每个命令首先执行一次试运行,因此添加了一个回退机制,允许 Git 尝试从 promisor remote 动态获取丢失的对象。
当正常的对象查找无法找到对象时,Git 调用 promisor_remote_get_direct() 尝试从 promisor remote 获取该对象,然后重试对象查找。这允许对象在没有复杂的预测算法的情况下“fault in”。
出于效率原因,没有检查丢失的对象是否实际上是一个 promisor object。
动态对象获取往往很慢,因为对象一次获取一个。
-
checkout
(和任何其他使用unpack-trees
的命令)已被教导在一个批处理中批量预取所有必需的丢失 blob。 -
rev-list
已被教导打印丢失的对象。其他命令可以使用它来批量预取对象。例如,"git log -p A..B" 可能在内部首先想做一些类似于 "git rev-list --objects --quiet --missing=print A..B" 的事情,并批量预取这些对象。
-
fsck
已更新为完全了解 promisor object。 -
GC 中的
repack
已更新为完全不接触 promisor packfile,并且仅重新打包其他对象。 -
全局变量 "fetch_if_missing" 用于控制对象查找是否尝试动态获取丢失的对象或报告错误。
我们对这个全局变量不满意,并希望删除它,但这需要对对象代码进行重大的重构以传递一个额外的标志。
获取丢失的对象
-
对象的获取是通过调用 "git fetch" 子进程来完成的。
-
本地仓库发送一个包含所有请求的对象的哈希值的请求,并且不执行任何 packfile 协商。然后它接收一个 packfile。
-
因为我们正在重用现有的获取机制,所以获取当前会获取请求的对象引用的所有对象,即使它们不是必需的。
-
使用
--refetch
进行获取将从远程仓库请求一个完整的新过滤的 packfile,这可以用于更改过滤器,而无需动态获取丢失的对象。
使用多个承诺远程仓库
可以配置和使用多个承诺远程仓库。
例如,这允许用户拥有多个地理位置相近的缓存服务器,用于获取丢失的 blob,同时继续从中央服务器执行过滤的 git-fetch
命令。
当获取对象时,会依次尝试承诺远程仓库,直到获取所有对象。
被认为是“承诺”远程仓库的是由以下配置变量指定的那些:
-
extensions.partialClone = <name>
-
remote.<name>.promisor = true
-
remote.<name>.partialCloneFilter = ...
只能使用 extensions.partialClone
配置变量配置一个承诺远程仓库。 这个承诺远程仓库将是获取对象时最后尝试的一个。
我们决定将其设为最后一个尝试的,因为使用多个承诺远程仓库的人很可能是因为其他承诺远程仓库在某些方面更好(也许它们更近或对某些类型的对象更快)比 origin 仓库更好,并且 origin 仓库很可能由 extensions.partialClone 指定。
这种理由不是很充分,但必须做出一个选择,无论如何,长远计划应该是使顺序完全可配置。
但目前,其他的承诺远程仓库将按照它们在配置文件中出现的顺序进行尝试。
当前限制
-
除了承诺远程仓库在配置文件中出现的顺序之外,无法以其他方式指定尝试承诺远程仓库的顺序。
也无法指定从一个远程仓库获取时使用一个顺序,而从另一个远程仓库获取时使用不同的顺序。
-
无法仅将特定对象推送到承诺远程仓库。
无法以特定顺序同时推送到多个承诺远程仓库。
-
动态对象获取只会向承诺远程仓库请求丢失的对象。 我们假设承诺远程仓库拥有完整的存储库视图,并且可以满足所有此类请求。
-
Repack 本质上将承诺和非承诺的 packfile 视为 2 个不同的分区,并且不会将它们混合在一起。
-
动态对象获取会 **为每个项目** 调用 fetch-pack,因为大多数算法会偶然发现一个丢失的对象,并且需要在继续其工作之前解决它。 如果需要许多对象,这可能会导致显着的开销——以及多次身份验证请求。
-
动态对象获取当前使用现有的 pack 协议 V0,这意味着每个对象都是通过 fetch-pack 请求的。 当连接建立时,服务器将发送一整套 info/refs。 如果有大量引用,这可能会导致显着的开销。
未来工作
-
改进指定尝试承诺远程仓库顺序的方式。
例如,这可能允许明确指定类似以下内容:“从这个远程仓库获取时,我想按此顺序使用这些承诺远程仓库,但是,在推送到该远程仓库或从中获取时,我想按该顺序使用那些承诺远程仓库。”
-
允许推送到承诺远程仓库。
用户可能希望使用具有多个承诺远程仓库的三角工作流程,每个承诺远程仓库都具有存储库的不完整视图。
-
允许非基于路径名的过滤器利用 packfile 位图(如果存在)。 这只是初始实现中的一个疏忽。
-
研究使用长时间运行的进程来动态获取一系列对象,例如 [5,6] 中提出的那样,以减少进程启动和开销成本。
如果 pack 协议 V2 能够允许该长时间运行的进程通过单个长时间运行的连接发出一系列请求,那就太好了。
-
研究 pack 协议 V2 以避免每次与服务器建立连接以动态获取丢失对象时广播 info/refs。
-
调查处理松散的承诺对象的需求。
承诺 packfile 中的对象可以引用可以从服务器动态获取的丢失对象。 假设是松散对象仅在本地创建,因此不应引用丢失的对象。 如果我们动态获取一个丢失的树并将其存储为松散对象而不是单个对象 packfile,我们可能需要重新审视该假设。
这并不一定意味着我们需要将松散对象标记为承诺; 放宽对象查找或 is-promisor 函数可能就足够了。
非任务
-
每次出现“按需加载 blob”的主题时,似乎总会有人建议允许服务器“猜测”并发送可能与请求的对象相关的其他对象。
没有进行任何实际操作; 我们只是记录这是一个常见的建议。 我们不确定它是如何工作的,也没有计划对此进行研究。
服务器发送比请求的更多的对象是有效的(即使对于动态对象获取),但我们没有在此基础上进行构建。
脚注
[a] 难以修改的丢失对象列表:在部分克隆的设计早期,我们讨论了对丢失对象的单个列表的需求。 这本质上是一个已排序的线性 OID 列表,这些 OID 是在克隆或后续获取期间被服务器省略的。
需要在每次对象查找时将此文件加载到内存中。 需要在每个显式的 "git fetch" 命令 **和** 任何动态对象获取时读取、更新和重写它(就像 .git/index 一样)。
如果有很多丢失的对象,读取、更新和写入此文件的成本可能会给每个命令增加显着的开销。 例如,如果有 1 亿个丢失的 blob,则此文件在磁盘上至少为 2GiB。
使用“承诺”概念,我们根据引用它的 packfile 的类型 **推断** 丢失的对象。
相关链接
[0] https://crbug.com/git/2 Bug#2: Partial Clone
[1] https://lore.kernel.org/git/20170113155253.1644-1-benpeart@microsoft.com/
主题:[RFC] 添加对按需下载 blob 的支持
日期:Fri, 13 Jan 2017 10:52:53 -0500
[2] https://lore.kernel.org/git/cover.1506714999.git.jonathantanmy@google.com/
主题:[PATCH 00/18] Partial clone (从克隆到惰性获取,共 18 个补丁)
日期:Fri, 29 Sep 2017 13:11:36 -0700
[3] https://lore.kernel.org/git/20170426221346.25337-1-jonathantanmy@google.com/
主题:Git 存储库中缺少 blob 支持的建议
日期:Wed, 26 Apr 2017 15:13:46 -0700
[4] https://lore.kernel.org/git/1488999039-37631-1-git-send-email-git@jeffhostetler.com/
主题:[PATCH 00/10] RFC 部分克隆和获取
日期:Wed, 8 Mar 2017 18:50:29 +0000
[5] https://lore.kernel.org/git/20170505152802.6724-1-benpeart@microsoft.com/
主题:[PATCH v7 00/10] 将过滤器进程代码重构为可重用模块
日期:Fri, 5 May 2017 11:27:52 -0400
[6] https://lore.kernel.org/git/20170714132651.170708-1-benpeart@microsoft.com/
主题:[RFC/PATCH v2 0/1] 添加对按需下载 blob 的支持
日期:Fri, 14 Jul 2017 09:26:50 -0400