4

我有一个超过 1 GB 的浅克隆 git 存储库。我对所需的文件/目录使用稀疏签出。

如何将存储库克隆减少为稀疏的签出文件/目录?

最初,我能够通过在克隆时禁用签出来将克隆的存储库限制为仅稀疏签出。然后在进行初始结帐之前设置稀疏结帐。这将存储库限制为仅约 200 MB。更易于管理。但是,在将来的某个时间更新远程分支信息会导致其余文件和目录包含在存储库克隆中。将 repo 克隆大小发送回超过 1 GB,我不知道如何只处理稀疏的签出文件和目录。

简而言之,我想要的是一个浅而稀疏的存储库克隆。不仅仅是浅层回购克隆的稀疏结帐。完整的回购是对空间的浪费,并且某些任务的性能会受到影响。

希望有人可以分享解决方案。谢谢。

4

1 回答 1

4

浅而稀疏的意思是“部分”或“狭窄”。

部分克隆(或“狭义克隆”)在理论上是可行的,并于 2017 年 12 月首次使用 Git 2.16 实现,如此处所示
但:

这在 Git 2.20(2018 年第四季度)中得到了进一步优化,因为在将从原始存储库中延迟补充的部分克隆中,我们通常希望避免“这个对象是否存在(本地)?” 在我们创建(部分/稀疏)克隆时故意省略的对象上。
然而,缓存树代码路径(用于从索引中写入树对象)坚持该对象存在,即使对于部分检出区域之外的路径也是如此。
代码已更新以避免此类检查。

请参阅Jonathan Tan ( ) 的提交 2f215ff(2018 年 10 月 9 日(由Junio C Hamano 合并 -- --提交 a08b1d6中,2018 年 10 月 19 日)jhowtan
gitster

cache-tree: 在部分克隆中跳过一些 blob 检查

在部分克隆中,每当发生稀疏检出时,都会验证索引中是否存在所有 blob,无论它们是包含在规范中还是排除在.git/info/sparse-checkout规范中。
这会显着降低性能,因为每当检查是否存在丢失的 blob 时就会发生延迟提取。


在 Git 2.24(2019 年第四季度)中,cache-tree代码被教导在尝试查看其计算的树对象是否已存在于存储库中时不那么激进。

请参阅Jonathan Tan ( ) 的提交 f981ec1(2019 年 9 月 3 日(由Junio C Hamano 合并 -- --提交 ae203ba中,2019 年 10 月 7 日)jhowtan
gitster

cache-tree:不要懒惰获取试探树

cache-tree数据结构用于加速 HEAD 和 index 之间的比较,并且当索引由樱桃挑选更新时(例如),将构建一个表示目录中索引中路径的树对象 -核心,查看对象存储中是否已经存在这样的树对象。

当引入惰性获取机制时,我们转换了这个“树存在吗?” 错误地检查“如果没有,如果我们懒惰地克隆,看看远程是否有它”调用。
由于这个检查的重点是通过机会性地记录一个已经存在的树对象来修复缓存树,我们甚至不应该尝试从远程获取一个。

传递OBJECT_INFO_SKIP_FETCH_OBJECT标志以确保我们只检查本地对象存储中的存在而不触发延迟获取机制。


在 Git 2.25(2020 年第一季度)中,“ git fetch”代码路径有一个很大的“当我询问是否存在某些东西时不要懒惰地获取丢失的对象”开关。

这已通过标记“这件事存在吗?”得到纠正。带有“如果不是请不要懒惰地获取它”标志的调用。

请参阅Jonathan Tan ( ) 的提交 603960b提交 e362fad(2019 年 11 月 13 日)和提交 6462d5e(2019 年 11 月 5 日(由Junio C Hamano 合并——提交 fce9e83中,2019 年 12 月 1 日)jhowtan
gitster

clone: 消除fetch_if_missing=0

签字人:Jonathan Tan

提交6462d5eb9a ("fetch: remove fetch_if_missing=0",2019-11-08) 努力fetch_if_missing=0从获取机制中删除fetch_if_missing=0对引用直接指向的对象,这应该是错误,而不是延迟获取的触发器。(获取机制中的这种情况被使用“git clone”而不是“git fetch”的测试覆盖,这就是为什么上述提交没有发现错误。)

可以通过在连接检查期间抑制延迟获取来修复该错误。修复此错误,并fetch_if_missing从克隆中删除。

和:

promisor-remote: 消除fetch_if_missing=0

签字人:Jonathan Tan

提交6462d5eb9a ("fetch: remove fetch_if_missing=0",2019-11-08) 努力fetch_if_missing=0从获取机制中删除对的需求,因此尝试fetch_if_missing=0从惰性获取机制中删除也是合理的promisor-remote

但是这样做会暴露一个错误——当服务器没有发送一个标签对象指向的对象时,就会发生一个无限循环:Git 尝试获取丢失的对象,这会导致所有 refs 的延迟(用于协商),这会导致懒惰地获取那个丢失的对象,等等。
这个错误是因为在延迟获取期间不必要地使用了 fetch negotiator - 它在初始化后没有使用,但它仍然被初始化(这会导致所有 refs 的取消引用)。

因此,当在获取期间不使用协商器时,请避免对其进行初始化。然后,fetch_if_missingpromisor-remote.


使用Derrick Stolee的“通过稀疏结账缩小您的 monorepo 规模”了解更多信息

将稀疏结帐与部分克隆功能配对可以进一步加速这些工作流程。
这种组合加快了数据传输过程,因为您不需要每个可访问的 Git 对象,而是可以只下载您需要的那些以填充工作目录的锥体

$ git clone --filter=blob:none --no-checkout https://github.com/derrickstolee/sparse-checkout-example
Cloning into 'sparse-checkout-example'...
Receiving objects: 100% (373/373), 75.98 KiB | 2.71 MiB/s, done.
Resolving deltas: 100% (23/23), done.
 
$ cd sparse-checkout-example/
 
$ git sparse-checkout init --cone
Receiving objects: 100% (3/3), 1.41 KiB | 1.41 MiB/s, done.
 
$ git sparse-checkout set client/android
Receiving objects: 100% (26/26), 985.91 KiB | 5.76 MiB/s, done.

在 Git 2.25.1(2020 年 2 月)之前,has_object_file()说“ no”给定一个通过 注册到系统的对象pretend_object_file(),使其与 不一致read_object_file(),导致延迟获取尝试从 Promisor 远程获取空树。

见讨论

我试图用

empty_tree=$(git mktree </dev/null)
git init --bare x
git clone --filter=blob:none file://$(pwd)/x y
cd y
echo hi >README
git add README
git commit -m 'nonempty tree'
GIT_TRACE=1 git diff-tree "$empty_tree" HEAD

事实上,看起来 Git 甚至可以从不包含它的存储库中为空树提供服务。

请参阅Jonathan Tan ( ) 的提交 9c8a294(2020 年 1 月 2 日(由Junio C Hamano 合并 -- --提交 e26bd14中,2020 年 1 月 22 日)jhowtan
gitster

sha1-file: 消除OBJECT_INFO_SKIP_CACHED

签字人:Jonathan Tan

在部分克隆中,如果用户将空树的哈希(“ ” - 对于 SHA-1,这是 4b825d...)提供给需要解析该对象的命令,例如:git mktree </dev/null

git diff-tree 4b825d <a non-empty tree>

然后 Git 将不必要地懒惰地获取空树,因为解析该对象会调用repo_has_object_file(),这不会对空树进行特殊处理。

相反,教repo_has_object_file()咨询find_cached_object()(它处理空树),从而使其与其余object-store-accessing功能保持一致。
成本是repo_has_object_file()现在oideq每次调用都需要,但与文件系统查找或无论如何都需要的包索引搜索相比,这是微不足道的。(如果find_cached_object()因为之前对 的调用而需要做更多的事情pretend_object_file(),那么在我们是否呈现缓存对象方面更有理由保持一致。)

作为历史记录,现在已知的函数在346245a1bb(“硬编码空树对象”,2008-02-13,Git v1.5.5-rc0 -- merge)中repo_read_object_file()被教导了空树,现在已知的函数正如c4d9986f5f中所教的空树(“ :也检查商店”,2011-02-07,Git v1.7.4.1)。oid_object_info()sha1_object_infocached_object

repo_has_object_file()从未更新,也许是由于疏忽。
该标志OBJECT_INFO_SKIP_CACHED,后来在dfdd4afcf9(“ sha1_file:教sha1_object_info_extended更多标志”,2017-06-26,Git v2.14.0-rc0)中引入并用于e83e71c5e1(“ sha1_file:重构has_sha1_file_with_flags”,2017-06-26,Git v2.14.0-rc0) , 被引入以保留空树处理中的这种差异,但现在可以将其删除。


Git 2.25.1 还将警告程序员,pretend_object_file()这允许代码暂时使用内核对象。

请参阅Jonathan Nieder ( ) 的提交 60440d7(2020 年 1 月 4 日(由Junio C Hamano 合并 -- --提交 b486d2e中,2020 年 2 月 12 日)artagnon
gitster

sha1-file: 记录如何使用pretend_object_file

灵感来源:Junio C Hamano
签字人:Jonathan Nieder

与内存中的替代一样,pretend_object_file它包含一个粗心的陷阱粗心的调用者可以使用它来创建对磁盘对象存储中不存在的对象的引用

添加注释以记录如何使用该功能而不冒此类问题的风险。

当前唯一的调用者是 blame,它用于pretend_object_file创建表示工作树状态的内存中提交。在讨论如何在“git merge”之类的操作中安全地使用此功能时注意到,与责备不同,它不是只读的。

所以现在的评论是

/*
 * Add an object file to the in-memory object store, without writing it
 * to disk.
 *
 * Callers are responsible for calling write_object_file to record the
 * object in persistent storage before writing any other new objects
 * that reference it.
 */
int pretend_object_file(void *, unsigned long, enum object_type,
            struct object_id *oid);

Git 2.25.1(2020 年 2 月)包括一个 Futureproofing,以确保测试不依赖于当前的实现细节。

请参阅Jonathan Tan ( ) 的提交 b54128b(2020 年 1 月 13 日(由Junio C Hamano 合并 -- --提交 3f7553a中,2020 年 2 月 12 日)jhowtan
gitster

t5616: 使增量基础变化更加稳健

签字人:Jonathan Tan

提交6462d5eb9a ("fetch: remove fetch_if_missing=0",2019-11-08) 包含一个测试,该测试依赖于必须延迟获取 blob 的增量基础,但假设要获取的树(作为测试的一部分)作为非delta object.
这个假设在未来可能不成立;例如,对象散列长度的变化可能导致树被作为 delta 发送。

通过依赖于必须懒惰地获取树的增量基础,并且不对 blob 是作为增量还是非增量发送的假设,使测试更加健壮。


Git 2.25.2(2020 年 3 月)修复了最近更改为将协议 v2 设为默认值所揭示的错误。

请参阅Derrick Stolee ( ) 的提交 3e96c66提交 d0badf8(2020 年 2 月 21 日(由Junio C Hamano 合并 -- --提交 444cff6中,2020 年 3 月 2 日)derrickstolee
gitster

partial-clone: 查找对象时避免获取

签字人:Derrick Stolee

在测试部分克隆时,我注意到一些奇怪的行为。我正在测试一种运行“ git init”的方法,然后手动配置远程以进行部分克隆,然后运行“ git fetch”。
令人惊讶的是,我看到 ' git fetch' 进程开始向服务器询问多轮包文件下载!当稍微调整一下情况时,我发现我可能会导致遥控器因错误而挂断。

添加两个测试来演示这两个问题。

在第一个测试中,我们发现当使用 blob 过滤器从以前没有任何标签的存储库中提取时,' git fetch --tagsorigin' 命令失败,因为服务器发送“多个过滤器规格无法组合”。这仅在使用协议 v2 时发生。

在第二个测试中,我们看到git fetch带有多个 ref 更新的“原始”请求会导致多个包文件下载。
这一定是由于 Git 试图在 refs 指向的对象中出错。让这件事特别讨厌的是,这是通过do_oid_object_info_extended()方法,所以谈判中没有“有”。
这导致远程从每个新的 ref 发送每个可达的提交和树,提供二次数据传输!如果我们恢复6462d5eb9a(获取:删除fetch_if_missing=0,2019-11-05,Git v2.25.0-rc0),则此测试已修复,但该恢复会导致其他测试失败。
真正的修复需要更多的关注。

使固定:

使用部分克隆时,find_non_local_tags()inbuiltin/fetch.c检查每个远程标记以查看其对象是否也存在于本地。不期望对象在本地存在,但是如果对象不存在,此函数仍然会触发延迟获取。当请求提交时,这可能会非常昂贵,因为我们完全从不存在的对象的上下文中删除,因此在请求中不提供“拥有”。

6462d5eb9a ( fetch: remove fetch_if_missing=0,2019-11-05, Git v2.25.0-rc0, , Git v2.25.0-rc0) 删除了一个全局变量,该变量阻止了这些获取以支持位标志。但是,某些对象存在检查未更新为使用此标志。

更新find_non_local_tags()以使用OBJECT_INFO_SKIP_FETCH_OBJECTOBJECT_INFO_QUICK.
_QUICK选项仅防止重新准备包文件结构。_SKIP_FETCH_OBJECT当我们期望一个对象由于更新的 refs 而不存在时,我们需要非常小心地提供。

这解决了一个损坏的测试t5616-partial-clone.sh.


通过“”自动跟踪标签的逻辑git clone --single-branch不小心避免延迟获取不必要的标签,这已在 Git 2.27(2020 年第二季度)中得到纠正,

请参阅Jeff King ( ) 的提交 167a575(2020 年 4 月 1 日(由Junio C Hamano 合并 -- --提交 3ea2b46中,2020 年 4 月 22 日)peff
gitster

clone:在关注标签时使用“快速”查找

签字人:杰夫·金

当使用 进行克隆时--single-branch,我们实现了git fetch通常的标签跟随行为,抓取指向我们本地对象的任何标签对象。

但是,当我们是部分克隆时,我们的has_object_file()检查实际上会延迟获取每个标签。

这不仅违背了--single-branch.
这对于浅克隆来说更糟糕,这意味着--single-branch,因为即使是彼此超集的标签也会被单独获取。

我们可以通过传递OBJECT_INFO_SKIP_FETCH_OBJECT给调用来解决这个问题,这就是git fetch在这种情况下所做的。

同样,让我们​​包含OBJECT_INFO_QUICK,,因为它就是这样git fetch做的。
基本原理在5827a03545中进行了讨论(获取:使用“快速”has_sha1_file进行标签跟踪,2016-10-13,Git v2.10.2),但这里的权衡将更加适用,因为克隆不太可能与另一个进程重新打包竞争我们新创建的存储库。

即使在非部分情况下,这也可能提供非常小的加速,因为我们会避免调用reprepare_packed_git()每个标签(尽管在实践中,我们只有一个包文件,因此重新准备应该非常便宜)。


在 Git 2.27(2020 年第二季度)之前,当客户端需要发出后续请求以例如自动关注时,使用在线协议版本 2 为“ git fetch”客户端提供“ git://”和“ ”协议在服务器端存在错误ssh://标签。

请参阅Christian Couder ( ) 的提交 08450ef(2020 年 5 月 8 日(由Junio C Hamano 合并 -- --提交 a012588中,2020 年 5 月 13 日)chriscool
gitster

upload-pack: 清除filter_options每个 v2 fetch 命令

帮助者:Derrick Stolee
帮助者:Jeff King
帮助者:Taylor Blau
签字者:Christian Couder

由于协议 v2 的请求/响应模型,该upload_pack_v2()函数有时在同一个进程中被调用两次,而“struct list_objects_filter_options filter_options”在“”开头被声明为静态upload-pack.c

这使得 check in list_objects_filter_die_if_populated()(由 调用process_args())第二次upload_pack_v2()调用失败,因为filter_options第一次已填充。

要解决这个问题,filter_options不再是静态的。它现在由upload_pack(). 它现在也是 'struct upload_pack_data' 的一部分,因此它间接地由upload_pack_v2().

从长远来看,我们的目标是也有upload_pack()使用 'struct upload_pack_data',所以添加filter_options到这个结构比让它直接拥有更有意义upload_pack_v2()

这修复了d0badf8797记录的 2 个错误中的第一个(“ partial-clone:在部分提取中演示错误”,2020 年 2 月 21 日,Git v2.26.0-rc0 -批次 #8中列出的合并)。


在 Git 2.29(2020 年第四季度)中,该pretend-object机制会在决定将数据保留在核心之前检查给定对象是否已存在于对象存储中,但该检查会触发从承诺者远程延迟获取此类对象。

请参阅Jonathan Tan ( ) 的commit a64d2aa(2020 年 7 月 21 日(由Junio C Hamano 合并 -- --提交 5b137e8中,2020 年 8 月 4 日)jhowtan
gitster

sha1-file:pretend_object_file()不预取

签字人:Jonathan Tan

pretend_object_file()使用不存在的对象调用时(典型情况下),不需要从承诺者远程获取任何内容,因为调用者已经知道该对象应该包含什么。因此,抑制取指。(OBJECT_INFO_QUICK出于同样的原因添加了标志。)

在对未提交修改的文件运行$DAYJOB“”时注意到了这一点。blame

于 2018-09-26T22:12:41.767 回答