浅层和稀疏的 GIT 存储库克隆

NOY*_*OYB 6 git clone repository sparse-checkout

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

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

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

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

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

Von*_*onC 8

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

\n

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

\n\n

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

\n

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

\n
\n

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

\n
\n
\n

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

\n
\n
\n

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

\n

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

\n
\n

cache-tree:不要延迟获取临时树

\n
\n
\n

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

\n

当引入lazy-fetch机制时,我们将这个“树是否存在?”转换为“树是否存在?” 错误地检查“如果没有,并且如果我们懒惰地克隆,看看遥控器是否有”调用。
\n由于此检查的全部目的是通过机会性地记录已经存在的树对象来修复缓存树,因此我们甚至不应该尝试从远程获取一个树对象。

\n

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

\n
\n
\n

使用 Git 2.25(2020 年第一季度),“git fetch ”代码路径有一个很大的“当我询问某些内容是否存在时不要延迟获取丢失的对象”开关。

\n

通过标记“这个东西存在吗?”已纠正此问题。调用“如果没有,请不要延迟获取它”标志。

\n

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

\n
\n

clone: 消除fetch_if_missing=0

\n

签署人: Jonathan Tan

\n
\n
\n

Commit 6462d5eb9a(“fetch:remove 2019-11-08)努力从获取机制中fetch_if_missing=0",删除对 的需求,因此尝试删除是合理的fetch_if_missing=0fetch_if_missing=0从克隆中删除也是合理的。但这样做会暴露一个错误 - 当服务器不发送ref 直接指向的对象,这应该是一个错误,而不是延迟获取的触发器。(获取机制中的这种情况由使用“git clone”而不是“git fetch”的测试覆盖,这就是为什么上述提交没有发现该错误。)

\n

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

\n
\n

和:

\n
\n

promisor-remote: 消除fetch_if_missing=0

\n

签署人: Jonathan Tan

\n
\n
\n

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

\n

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

\n

因此,当在获取期间不使用协商器时,不要对其进行初始化。然后,fetch_if_missing从 中删除promisor-remote

\n
\n
\n

通过Derrick Stolee的“通过稀疏结帐缩小单一仓库规模”了解更多内容

\n
\n

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

\n
\n
$ git clone --filter=blob:none --no-checkout https://github.com/derrickstolee/sparse-checkout-example\nCloning into \'sparse-checkout-example\'...\nReceiving objects: 100% (373/373), 75.98 KiB | 2.71 MiB/s, done.\nResolving deltas: 100% (23/23), done.\n \n$ cd sparse-checkout-example/\n \n$ git sparse-checkout init --cone\nReceiving objects: 100% (3/3), 1.41 KiB | 1.41 MiB/s, done.\n \n$ git sparse-checkout set client/android\nReceiving objects: 100% (26/26), 985.91 KiB | 5.76 MiB/s, done.\n
Run Code Online (Sandbox Code Playgroud)\n
\n

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

\n

参见讨论

\n
\n

我尝试用以下方法重现此内容

\n
empty_tree=$(git mktree </dev/null)\ngit init --bare x\ngit clone --filter=blob:none file://$(pwd)/x y\ncd y\necho hi >README\ngit add README\ngit commit -m \'nonempty tree\'\nGIT_TRACE=1 git diff-tree "$empty_tree" HEAD\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
\n

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

\n
\n

sha1-file: 消除OBJECT_INFO_SKIP_CACHED

\n

签署人: Jonathan Tan

\n
\n
\n

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

\n
git diff-tree 4b825d <a non-empty tree>\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n

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

\n

repo_has_object_file()可能是由于疏忽,从未更新过。
\nOBJECT_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) )的引入是为了保留空树处理中的这种差异,但现在可以将其删除。

\n
\n
\n

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

\n

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

\n
\n

sha1-file:记录如何使用pretend_object_file

\n

灵感来源:Junio C Hamano
\n签署人:Jonathan Nieder

\n
\n
\n

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

\n

添加注释,记录如何使用该函数而不冒此类问题的风险。

\n

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

\n
\n

所以现在的评论是

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

Git 2.25.1(2020 年 2 月)包含面向未来的功能,以确保测试不依赖于当前的实现细节。

\n

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

\n
\n

t5616:对 Delta 基础变化具有鲁棒性

\n

签署人: Jonathan Tan

\n
\n
\n

Commit 6462d5eb9a(“fetch:remove fetch_if_missing=0",2019-11-08)包含一个测试,该测试依赖于必须延迟获取 blob 的 delta 基数,但假设正在获取的树(作为测试的一部分)作为非增量对象。
\n这个假设将来可能不成立;例如,对象哈希长度的更改可能会导致树作为增量发送。

\n

通过依赖于延迟获取树的增量基数,并且不假设 Blob 是作为增量还是非增量发送,使测试更加稳健。

\n
\n
\n

Git 2.25.2(2020 年 3 月)修复了最近的更改所暴露的错误,使协议 v2 成为默认协议。

\n

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

\n
\n

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

\n

签署人:Derrick Stolee

\n
\n
\n

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

\n

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

\n

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

\n

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

\n
\n

使固定:

\n
\n

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

\n

6462d5eb9afetch:删除fetch_if_missing=0,2019-11-05、Git v2.25.0-rc0、Git v2.25.0-rc0)删除了一个全局变量,该变量阻止这些提取,转而使用位标志。但是,某些对象存在检查未更新为使用此标志。

\n

更新find_non_local_tags()OBJECT_INFO_SKIP_FETCH_OBJECT除了OBJECT_INFO_QUICK.
\n该_QUICK选项仅阻止重新准备包文件结构。_SKIP_FETCH_OBJECT当我们预计对象由于更新的引用而不存在时,我们需要非常小心地提供。

\n

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

\n
\n
\n

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

\n

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

  • @NOYB 确实如此:这仍在部署中,并且尚未得到主要 Git 存储库托管服务的支持。您需要使用最新的 Git 作为镜像运行自己的服务器,以便从该镜像克隆/推送/拉取。 (2认同)