git clone --filter
选项的语法是什么?
至少从 Git 2.27(2020 年第二季度)开始,这变得更加清晰了。
在此之前,以下是该命令的快速 TLDR 示例,与 (cone) 稀疏检出 结合使用:
git clone --filter=blob:none --no-checkout https://github.com/git/git
cd git
git sparse-checkout init --cone
git read-tree -mu HEAD
那只会带回顶层文件,排除默认的任何子文件夹。
由于
git clone --filter=blob:none --no-checkout
步骤,初始克隆仍然更快。
现在,让我们来看一下git clone --filter
选项的语法:
请参见提交4a46544(2020年3月22日)由Derrick Stolee (derrickstolee
)提交。
(由Junio C Hamano -- gitster
--在提交fa0c1eb中合并,2020年4月22日)
clone
: 文档 --filter
选项
签署者:Derrick Stolee
事实证明,“--filter=<filter-spec>
”选项在“git clone
”页面中没有任何文档记录,而是在“git rev-list”中详细介绍了它的不同用途。
在文档中添加有关此选项的一些内容。值得花费一些时间在“git clone”文档中创建一个有关部分克隆作为概念以及如何成为惊人体验的子章节。例如,“git checkout”可能会触发包下载。
git clone documentation现在包括:
--filter=<filter-spec>
:
使用部分克隆功能并请求服务器根据给定的对象过滤器发送可达对象的子集。
使用 --filter
时,提供的 <filter-spec>
用于部分克隆过滤器。
例如,--filter=blob:none
将过滤掉所有 blob(文件内容),直到 Git 需要它们。
此外,--filter=blob:limit=<size>
将过滤掉大小至少为 <size>
的所有 blob。
有关过滤器规范的更多详细信息,请参见 git rev-list
中的 --filter
选项。
那个选项不如我希望的有用(它不能用于组合“clone”和“filter-branch”)。然而,这种过滤机制是与克隆相关的一种扩展,用于实现在 Git 2.16 中引入的部分克隆(或窄克隆)。但您的 Git 存储库托管服务器必须支持协议 v2,目前(2018 年 10 月)仅由 GitLab 支持。这意味着您可以使用“--filter”与“git clone”,正如最近 Git 2.20 补丁所说明的那样(见下文)。
那个过滤器随后被添加到
git fetch
中
这个补丁系列。它是fetch-pack和upload-pack协商中新增的新的pack-protocol功能“
filter
”的一部分。请参见
文档/技术/pack-protocol中的“filter”,其中提到了
rev-list选项。
自 Git 2.20 (2018年第4季度) 开始,配置为懒惰获取缺失对象的部分克隆将按需向源存储库发出 "
git fetch
" 请求以填充尚未获取的对象。
该请求已经针对请求树对象进行了优化(而不是其中包含的叶子 blob 对象),通过告知源存储库不需要 blob。
请查看提交4c7f956, 提交12f19a9 (2018年10月3日) by Jonathan Tan (jhowtan
)。
(由Junio C Hamano -- gitster
--合并在提交fa54ccc,2018年10月19日)
fetch-pack
: 在惰性获取树对象时排除blob对象
可以使用"
git clone --filter=tree:none <repo>
"命令获取缺少树的部分克隆。在这样的存储库中,当需要惰性获取树时,任何直接或间接引用的树或blob都会被获取,而不管原始命令是否需要这些对象,或者本地存储库是否已经有了它们。
这是因为懒惰获取使用的提取协议不允许客户端请求只发送所需的对象,这将是理想的解决方案。此补丁实现了一个部分解决方案:指定"blob:none"过滤器,从而在一定程度上减少提取负载。
当惰性获取blob时,此更改没有影响(由于过滤器的工作方式)。如果惰性获取提交(这样的存储库很难构建,并且我们不太支持这种用例,但是可能会出现),则仍会获取引用的提交和树 - 只是不会获取blob。
您可以通过以下方式进行进一步优化:
请参见提交 e70a303, 提交 6ab4055, 提交 0177565, 提交 99bcb88 (2018年9月27日) 由Jonathan Tan (jhowtan
)提交。
(由Junio C Hamano -- gitster
--合并在提交 0527fba中,2018年10月19日)
传输:允许跳过引用列表
get_refs_via_connect()
函数既执行握手(包括确定协议版本)又获取远程引用列表。
然而,fetch 协议 v2 支持在不列出引用的情况下获取对象,因此通过创建新的 handshake()
函数,使用户可以跳过列表。
请注意,Git 2.21(2019年第一季度)更新了协议消息规范,使得语法已经发生/演变,只允许有限的比例使用。这是为了确保潜在的兼容性问题不会失控。
请查看提交 87c2d9d(2019年1月8日),作者为Josh Steadmon(steadmon
)。
请查看提交 8272f26,提交 c813a7c(2019年1月9日),作者为Matthew DeVore(matvore
)。
(由Junio C Hamano -- gitster
--在提交 073312b中合并,于2019年2月5日)
filter-options
: 扩展缩放数字
在与远程服务器或子进程通信时,使用扩展数字而不是带有缩放后缀的数字在对象过滤器规范中(例如 "limit:blob=1k
" 变为 "limit:blob=1024
")。
更新协议文档以指出客户端应始终执行此扩展,以允许更多服务器实现之间的兼容性。
作为旁注,Git 2.23(2019年第3季度)认为"
invalid filter-spec
"消息是面向用户的,而不是BUG,因此可以本地化。
请参见
提交5c03bc8(2019年5月31日),作者为
Matthew DeVore(matvore
)。
(由Junio C Hamano -- gitster
--合并于提交ca02d36,2019年6月21日)
list-objects-filter-options
: 错误可本地化
The "invalid filter-spec
" message is user-facing and not a BUG, so make
it localizeable.
For reference, the message appears in this context:
$ git rev-list --filter=blob:nonse --objects HEAD
fatal: invalid filter-spec 'blob:nonse'
自Git 2.24(2019年第四季度)起,http传输协议已得到修复,该协议缺乏一些优化,而本地传输协议则学会了避免不必要的ref广告。
请参见提交记录fddf2eb,提交记录ac3fda8(由Jonathan Tan (jhowtan
)于2019年8月21日提交)。
(由Junio C Hamano -- gitster
--合并于提交记录f67bf53,2019年9月18日)
传输助手:如果不必要,则跳过ls-refs
提交e70a303("fetch
: do not list refs if fetching only hashes",2018-10-07,Git v2.20.0-rc0)及其祖先告诉Git,作为一种优化,在协议v2获取期间不必要时跳过ls-refs
步骤
(例如,在部分克隆中懒惰地获取丢失的对象或运行“git fetch --no-tags <remote> <SHA-1>
”时)。
但这只适用于本地支持的协议;特别是,HTTP不受支持。
当使用支持连接或无状态连接的远程助手时,教Git跳过ls-refs
。
Git 2.24(2019年第四季度)中的另一个优化
请参见提交d8bc1a5 (由Jonathan Tan(jhowtan
)于2019年10月8日发布)。
(由Junio C Hamano -- gitster
--合并于提交c7d2ced,2019年10月15日)
Signed-off-by: Jonathan Tan
在构建要发送的包文件时,send_pack()
会得到一个用作排除项的远程引用列表。
对于每个引用,它首先检查该引用是否存在于本地,如果存在,则使用"^
"前缀将其传递给pack-objects
。
但是,在部分克隆中,此检查可能会触发惰性获取。
在这种获取期间获得的附加提交祖先信息可能显示已知服务器上已经有了某些将要发送的对象,从而导致发送较小的包。
但这是以从许多可能不相关的引用获取为代价的,并且惰性获取在客户端与正在推送的分支的上游保持最新的典型情况下根本没有帮助。
确保不会发生这些惰性获取。
最后,Git 2.24(2019年第四季度)包括一个临时解决方案,用于解决懒惰抓取故障,这说明了filter
语法的一种用法。
请参见提交 c7aadcc(由Jonathan Tan (jhowtan
)于2019年10月23日提交)
(由Junio C Hamano -- gitster
--合并于提交 c32ca69,2019年11月4日)
fetch
: 延迟执行 fetch_if_missing=0
直到配置完成
签名:Jonathan Tan
Suppose, from a repository that has ".gitmodules
", we clone with --filter=blob:none
:
git clone --filter=blob:none --no-checkout \
https://kernel.googlesource.com/pub/scm/git/git
Then we fetch:
git -C git fetch
This will cause a "unable to load config blob object
", because the fetch_config_from_gitmodules()
invocation in cmd_fetch()
will attempt to load ".gitmodules
" (which Git knows to exist because the client has the tree of HEAD) while fetch_if_missing
is set to 0.
fetch_if_missing
is set to 0 too early - ".gitmodules
" here should be lazily fetched.
Git must set fetch_if_missing
to 0 before the fetch because as part of the fetch, packfile negotiation happens (and we do not want to fetch any missing objects when checking existence of objects), but we do not need to set it so early.
Move the setting of fetch_if_missing
to the earliest possible point in cmd_fetch()
, right before any fetching happens.
随着Git 2.25(2020年第一季度)的推出,对于懒惰克隆的调试支持有所改进。
git fetch
v2现在更好地利用了保证文件。
请参见提交5374a29(由Jonathan Tan (jhowtan
)于2019年10月15日提交)。
(由Junio C Hamano -- gitster
--于提交026587c中合并,2019年11月10日)
Signed-off-by: Jonathan Tan
Acked-by: Josh Steadmon
在
partial-clone.txt
中,承诺者包文件的规范说明伴随packfiles一起的
.promisor
文件无关紧要(就像
.keep
文件一样),所以每当从承诺者远程获取packfile时,Git都会写入空的
.promisor
文件。但这些文件可能包含更有用的信息。因此,不要写空文件,而是将获取的引用写入这些文件。这使得调试部分克隆问题更容易,因为我们可以确定在下载packfile时获取了哪些引用(及其相关哈希),如果必要,可以将这些哈希与现在的承诺者远程报告进行比较。通过教授
fetch-pack
,实现了当它知道pack的锁定文件名时编写自己的非空
.promisor
文件。这涵盖了用户使用内部协议或HTTP协议v2(
fetch_refs_via_pack()
在
transport.c
中设置
lock_pack
)和使用HTTP协议v0/v1(
fetch_git()
在
remote-curl.c
将"
--lock-pack
"传递给 "
fetch-pack
")的情况。
在 Git 2.29(2020年第四季度)之前,从懒惰克隆的存储库中获取会导致服务器端尝试获取客户端已经拥有的懒惰获取对象,其中许多在任何情况下都不可用于第三方。
请参见
提交77aa094 (由
Jonathan Tan (jhowtan
) 于2020年7月16日提交)。
(由 Junio C Hamano -- gitster
-- 合并于 提交37f382a,2020年7月30日)
签名作者:Jonathan Tan
当
upload-pack
接收到包含“
have
”哈希的请求时,它(除其他事项外)会检查服务端存储库是否具有相应的对象。然而,它不使用
OBJECT_INFO_SKIP_FETCH_OBJECT
标志进行检查,因此如果提供部分克隆,则首先将触发惰性获取。
这是在
$DAYJOB
发现的,当用户从部分克隆中获取时(进入另一个部分克隆 - 尽管如果要获取的仓库不是部分克隆,也会发生这种情况)。
因此,每当检查“
have
”哈希是否存在时,请传递
OBJECT_INFO_SKIP_FETCH_OBJECT
标志。
同时添加
OBJECT_INFO_QUICK
标志以提高性能,因为这样的对象通常不存在于服务端存储库中,而假阴性的后果很小(通常是发送稍大的包)。
使用 Git 2.29(2020年第四季度),响应 "
git fetch
"
(man) 请求的组件变得更加可配置,以有选择地允许或拒绝用于部分克隆的对象过滤规范。
请看 提交 6cc275e (2020年8月5日) 由 Jeff King (peff
) 提交。
请看 提交 5b01a4e, 提交 6dd3456 (2020年8月3日),以及 提交 b9ea214 (2020年7月31日) 由 Taylor Blau (ttaylorr
) 提交。
(由 Junio C Hamano -- gitster
-- 合并于 提交 73a9255,2020年8月11日)
协助者:Jeff King
签名:Taylor Blau
Git客户端可以向服务器请求一部分对象,其中被请求的对象集由一个或多个对象过滤器提炼。服务器管理员可以配置“git upload-pack”(man)允许或禁止这些过滤器,通过将“uploadpack.allowFilter”变量分别设置为“true”或“false”。然而,使用位图的管理员可能希望允许某些类型的对象过滤器,但禁止其他类型的对象过滤器。特别是,他们可能希望允许通过位图进行优化的对象过滤器,而拒绝其他不能通过位图进行优化的对象过滤器,因为这会导致性能下降(以及服务器负载增加)。引入两个新的配置变量,允许在逐个情况下配置“git upload-pack”支持对象过滤器:'uploadpackfilter.allow'和'uploadpackfilter..allow',其中''可以是'blobNone'、'blobLimit'、'tree'等中的任何一个有效值。为任何有效的''值设置第二个配置变量显式地允许或禁止限制该对象过滤器的类型。如果客户端请求对象过滤器,并且相应的配置值未设置,“'git upload-pack'(man)”将默认使用“uploadpackfilter.allow”的值,默认为“true”,以保持向后兼容性。请注意,这与控制是否向广告'filter'功能的“uploadpack.allowfilter”不同。
git config
现在在其手册页面中包括:
uploadpackfilter.allow
为未指定的对象过滤器(参见:下面的配置变量)提供默认值。
默认为true
。
uploadpackfilter.<filter>.allow
明确允许或禁止与<filter>
相对应的对象过滤器,其中<filter>
可以是以下之一:blob:none
,blob:limit
,tree
,sparse:oid
或combine
。
如果使用组合过滤器,则必须允许combine
和所有嵌套的过滤器种类。
默认为uploadpackfilter.allow
。
在 Git 2.30(2021年第一季度)中,修复了响应部分克隆请求时可能出现的服务器端资源释放问题。
参见 提交8d133f5,提交aab179d(由 Taylor Blau (ttaylorr
) 于2020年12月03日提交)。
(由 Junio C Hamano -- gitster
-- 在 提交21127fa 中合并,于2020年12月17日)
签名:Taylor Blau
为了跟踪哪些对象过滤器是允许的或不允许的,'
git upload-pack
'
(man)将每个过滤器的名称存储在
string_list
中,并将其
->util
指针设置为0或1,表示它是否被禁止或允许。稍后,我们尝试清除该列表,但我们错误地要求也释放
util
指针。这种行为(在
6dd3456a8c ("
[
upload-pack.c
](https
://github.com/git/git/blob/8d133f500a5390a089988141cdec8154a732764d/upload-pack.c): allow banning certain object filter(s)", 2020-08-03, Git v2.29.0-rc0 --
merge listed in
batch #6)中引入),导致无效的free,并导致崩溃。为了触发这个问题,需要从至少允许一个对象过滤器的服务器获取,并发出包含允许的过滤器子集的提取请求(即,我们不能要求被禁止的过滤器,因为这会导致我们在命中虚假的
string_list_clear()
之前
die()
)。在这种情况下,存在的任何被禁止的过滤器都将导致
free()
无操作(因为这些
->util
指针设置为0),但我们尝试释放的第一个允许的过滤器将使我们崩溃。我们在测试中从未注意到这一点,因为我们没有一个设置'uploadPackFilter'配置变量并随后进行有效提取请求的示例。第一个新的'
git clone
'
(man)在这里防止了进一步的回归。另外,还要添加一个检查与树深度大于0的相同行为的测试,以确保代码质量。
最近的 "
git clone
"
(man) 修复在传输层返回失败时留下了一个临时目录。
这在 Git 2.33 (Q3 2021) 中已得到纠正。
查看 提交 6aacb7d(2021年5月19日),由Jeff King (peff
)完成。
(由Junio C Hamano -- gitster
--合并于提交 f4f7304,2021年6月14日)
clone
: 在 transport_fetch_refs()
失败后清理目录
签名:Jeff King
git-clone
(man)现在开始尊重来自传输子系统的错误,这是从aab179d开始的(“builtin/clone.c
:不要忽略transport_fetch_refs()
错误”,2020年12月3日,Git v2.30.0-rc1 -- merge)。
然而,该提交并没有完全正确地处理文件系统的清理。
cmd_clone()
创建的目录的清理是通过一个atexit()
处理程序完成的,我们使用一个标志来控制它。
它最初为JUNK_LEAVE_NONE
(“清理所有内容”),然后在我们知道有一个有效的仓库但没有工作树时进展到JUNK_LEAVE_REPO
,最后在成功检出后变成JUNK_LEAVE_ALL
。