[英]Git sparse checkout with exclusion
根据这个线程,Git 的sparse-checkout
功能中的排除应该被实现。 是吗?
假设我有以下结构:
papers/
papers/...
presentations/
presentations/heavy_presentation
presentations/...
现在我想从结帐中排除presentations/heavy_presentation
,同时将 rest 留在结帐中。 我还没有设法让它运行。 正确的语法是什么?
遗憾的是,上述方法都不适合我,所以我花了很长时间尝试不同的sparse-checkout
文件组合。
就我而言,我想跳过带有 IntelliJ IDEA 配置的文件夹。
这是我所做的:
运行git clone https://github.com/myaccount/myrepo.git --no-checkout
运行git config core.sparsecheckout true
使用以下内容创建.git\info\sparse-checkout
!.idea/*
!.idea_modules/*
/*
运行 'git checkout --' 以获取所有文件。
使其工作的关键是在文件夹名称之后添加/*
。
我有 git 1.9
我本来希望像下面这样的工作:
/*
!presentations/heavy_presentation
但事实并非如此。 我确实尝试了许多其他组合。 我认为排除没有正确实施,并且周围存在错误(仍然)
就像是:
presentations/*
!presentations/heavy_presentation
确实有效,您将获得没有heavy_presentation文件夹的演示文件夹。
因此,解决方法是明确包含其他所有内容。
在 Git 2.25(2020 年第一季度)中,稀疏签出工作树的管理获得了专用的“ sparse-checkout
出”命令。
Git 2.37(2022 年第三季度)将锥形模式设为默认模式。 请参阅此答案的最后一部分。
首先,这是一个扩展示例,从使用--filter
选项的快速克隆开始:
git clone --filter=blob:none --no-checkout https://github.com/git/git
cd git
git sparse-checkout init --cone
# that sets git config core.sparseCheckoutCone true
git read-tree -mu HEAD
使用锥形选项(详细/记录在下面)意味着您的.git\info\sparse-checkout
将包含以下开头的模式:
/*
!/*/
含义:只有顶级文件,没有子文件夹。
如果你不想要top file,你需要避免cone模式:
# Disablecone mode in .git/config.worktree
git config core.sparseCheckoutCone false
# remove .git\info\sparse-checkout
git sparse-checkout disable
# Add the expected pattern, to include just a subfolder without top files:
git sparse-checkout set /mySubFolder/
# populate working-tree with only the right files:
git read-tree -mu HEAD
详细说明:
(请参阅Derrick Stolee的“ 使用sparse-checkout
将您的 monorepo 缩小到大小”中的更多信息)
因此,不仅排除子文件夹确实有效,而且使用稀疏结帐的“锥形”模式(使用 Git 2.25)可以更快地工作。
请参阅Ed Maste ( emaste
)的提交 761e3d2 (2019 年 12 月 20 日)。
请参阅提交 190a65f (2019 年 12 月 13 日),并提交 cff4e91 、 提交 416adc8 、 提交 f75a69f 、 提交 fb10ca5 、 提交 99dfa6f 、 提交 e091228 、 提交 e9de487 、 提交4dcd4de 、 提交 eb42fec 、 提交 af09ce2 、 提交 79321e 8 、 提交 7 、 提交7 7bffca9 , 提交 f6039a9 , 提交 d89f09c , 提交 bab3c35 , 提交 94c0956 (2019 年 11 月 21 日),作者Derrick Stolee ( derrickstolee
) 。
请参阅Jeff Hostetler ( Jeff-Hostetler
)的提交 e6152e3 (2019 年 11 月 21 日)。
(由Junio C Hamano -- gitster
--在提交 bd72a08中合并,2019 年 12 月 25 日)
sparse-checkout
: 添加“锥形”模式签字人:Derrick Stolee
随着索引中模式数量和条目数量的增长,稀疏签出功能可以具有二次性能。
如果有 1,000 个模式和 1,000,000 个条目,那么这个时间可能非常重要。创建一个新的布尔配置选项core.sparseCheckoutCone ,以指示我们希望稀疏结帐文件包含一组更有限的模式。
这是一个与core.sparseCheckout
分开的配置设置,以避免通过引入三态选项来破坏旧客户端。
config
手册页包括:
`core.sparseCheckoutCone`:
启用稀疏结帐功能的“锥形模式”。
当 sparse-checkout 文件包含一组有限的模式时,这种模式提供了显着的性能优势。
锥形图案套装
完整的模式集允许任意模式匹配和复杂的包含/排除规则。
在更新索引时,这些可能会导致O(N*M)
模式匹配,其中N
是模式数,M
是索引中的路径数。 为了解决这个性能问题,启用core.spareCheckoutCone
时允许使用更受限制的模式集。锥形模式集中接受的模式是:
- 递归:包含目录内的所有路径。
- 父级:包含一个目录中的所有文件。
除了上述两种模式外,我们还期望根目录下的所有文件都包括在内。 如果添加了递归模式,则所有前导目录都将添加为父模式。
默认情况下,当运行
git sparse-checkout init
时,根目录被添加为父模式。 此时,sparse-checkout 文件包含以下模式:/* !/*/
这表示“在根目录中包含所有内容,但在根目录下没有两层”。
如果我们随后将文件夹A/B/C
添加为递归模式,则文件夹A
和A/B
将添加为父模式。
生成的稀疏签出文件现在是/* !/*/ /A/ !/A/*/ /A/B/ !/A/B/*/ /A/B/C/
在这里,顺序很重要,因此负面模式会被文件中较低的正面模式覆盖。
如果
core.sparseCheckoutCone=true
,那么 Git 将解析期望这些类型的模式的稀疏检出文件。
如果模式不匹配,Git 会发出警告。
如果模式确实符合预期的格式,那么 Git 将使用更快的基于散列的算法来计算包含在sparse-checkout
中。
所以:
sparse-checkout
:初始化并设置为锥形模式帮助人:Eric Wong
帮助者:约翰内斯辛德林
签字人:Derrick Stolee
为了使锥形模式集易于使用,请更新“
git sparse-checkout (init|set)
”的行为。将“
--cone
”标志添加到“git sparse-checkout init
”以设置配置选项“core.sparseCheckoutCone=true
”。在锥形模式下运行“
git sparse-checkout set
”时,用户只需要提供递归文件夹匹配的列表。 Git 将自动为前导目录添加必要的父匹配项。
请注意, --cone
选项仅记录在 Git 2.26(2020 年第一季度)中
(由Junio C Hamano -- gitster
--在提交 ea46d90中合并,2020 年 2 月 5 日)
doc
:sparse-checkout
: 提到--cone
选项签字人:Matheus Tavares
委托方:Derrick Stolee
在af09ce2 ("
sparse-checkout
: init and set in cone mode", 2019-11-21, Git v2.25.0-rc0 -- merge ) 中,'----cone
' 选项被添加到'git sparse-checkout
init' .在
git sparse-checkout
中记录它:
那包含着:
当提供
--cone
时,还设置了core.sparseCheckoutCone
设置,允许使用有限的模式集获得更好的性能。
(上面介绍的“一组模式”,在这个答案的“ CONE PATTERN SET
”部分)
这种新的“锥形”模式会快多少?
sparse-checkout
: 使用 hashmaps 进行锥形模式帮助人:Eric Wong
帮助者:约翰内斯辛德林
签字人:Derrick Stolee
sparse-checkout 中的“锥形模式”选项允许的父模式和递归模式具有足够的限制性,我们可以避免使用正则表达式解析。 一切都基于前缀匹配,因此我们可以使用哈希集来存储稀疏签出文件中的前缀。 检查路径时,我们可以从路径中删除路径条目并检查哈希集是否完全匹配。
作为测试,我为 Linux 存储库创建了一个锥形模式稀疏签出文件,该文件实际上包含每个文件。 这是通过获取 Linux 存储库中的每个文件夹并在此处创建模式对来构建的:
/$folder/ !/$folder/*/
这导致了一个稀疏的签出文件 sith 8,296 个模式。
在此文件上运行“git read-tree -mu HEAD”具有以下性能:core.sparseCheckout=false: 0.21 s (0.00 s) core.sparseCheckout=true : 3.75 s (3.50 s) core.sparseCheckoutCone=true : 0.23 s (0.01 s)
根据
trace2
性能跟踪,上面括号中的时间对应于第一次clear_ce_flags()
调用所花费的时间。虽然此示例是人为设计的,但它演示了这些模式如何减慢稀疏结帐功能。
和:
sparse-checkout
:在锥形模式下尊重 core.ignoreCase签字人:Derrick Stolee
当用户在锥形模式下使用 sparse-checkout 功能时,他们使用“
git sparse-checkout set <dir1> <dir2> ...
”添加模式或使用“--stdin
”逐行提供目录在标准输入上。
这种行为自然看起来很像用户键入“git add <dir1> <dir2> ...
”的方式如果启用
core.ignoreCase
,那么“git add
”将使用不区分大小写的匹配来匹配输入。
对sparse-checkout
功能执行相同的操作。在
unpack_trees()
期间更新 skip-worktree 位时执行不区分大小写的检查。 这是通过更改散列算法和散列映射比较方法以可选地使用不区分大小写的方法来完成的。启用此选项后,散列算法的性能成本会很小。
为了梳理出最坏的情况,以下是在具有深层目录结构的 repo 上运行的:git ls-tree -d -r --name-only HEAD | git sparse-checkout set --stdin
'set' 命令在禁用或启用
core.ignoreCase
的情况下进行计时。
对于历史悠久的回购,数字是core.ignoreCase=false: 62s core.ignoreCase=true: 74s (+19.3%)
为了重现性,Linux 内核存储库上的等效测试具有以下数字:
core.ignoreCase=false: 3.1s core.ignoreCase=true: 3.6s (+16%)
现在,这并不是一个完全公平的比较,因为大多数用户将使用更浅的目录来定义他们的稀疏锥体,以及eb42feca97的性能改进(“unpack-trees: hashless in cone mode”2019-11-21,Git 2.25- rc0) 可以消除大部分哈希成本。 要进行更实际的测试,请从
ls-tree
命令中删除“-r
”以仅存储第一级目录。
在这种情况下,Linux 内核存储库在每种情况下都需要 0.2-0.25 秒,而深层存储库在每种情况下都需要 1 秒,正负 0.05 秒。因此,我们可以证明这种变化的成本,但它对任何合理的稀疏结账锥都不重要。
在 Git 2.25(2020 年第一季度)中,“ git sparse-checkout
list”子命令学会了在“锥形”模式生效时以更简洁的形式给出其输出。
请参阅Derrick Stolee ( derrickstolee
) 的commit 4fd683b和commit de11951 (2019 年 12 月 30 日)。
(由Junio C Hamano -- gitster
--在提交 c20d4fd中合并,2020 年 1 月 6 日)
sparse-checkout
:以锥形模式列出目录签字人:Derrick Stolee
当
core.sparseCheckoutCone
启用时,“git sparse-checkout set
”命令将目录列表作为输入,然后创建稀疏签出模式的有序列表,以便递归包含这些目录,并且父目录中的所有同级条目都是也包括在内。
列出模式不如目录本身对用户友好。在锥形模式下,只要模式与预期的锥形模式类型匹配,将“
git sparse-checkout list
”的输出更改为仅显示创建模式的目录。通过此更改,以下管道命令不会更改工作目录:
git sparse-checkout list | git sparse-checkout set --stdin
唯一不起作用的情况是
core.sparseCheckoutCone
为true
,但 sparse-checkout 文件包含与锥形模式的预期模式类型不匹配的模式。
最近在此版本中添加的代码以在稀疏锥模式下移动到索引中同一目录中的条目之外的条目,没有计算错误跳过的条目数,已在 Git 2.25.1 中更正(2020 年 2 月)。
请参阅Junio C Hamano ( gitster
)的提交 7210ca4 (2020 年 1 月 27 日)。
请参阅Derrick Stolee 通过 GitGitGadget (``) 提交的 4c6c797 (2020 年 1 月 10 日)。
(由Junio C Hamano -- gitster
--在提交 043426c中合并,2020 年 1 月 30 日)
unpack-trees
: 正确计算结果计数报告人:约翰内斯·辛德林
签字人:Derrick Stolee
clear_ce_flags_dir()
方法处理公共目录中的缓存条目。 返回的int
是该目录处理的缓存条目数。
在锥模式下使用稀疏签出功能时,我们可以跳过完全包含或完全排除的目录中的条目的模式匹配。eb42feca ("
unpack-trees
: hashless in cone mode", 2019-11-21, Git v2.25.0-rc0 -- merge列在第 #0 批中) 引入了这个性能特性。 旧机制依赖于调用clear_ce_flags_1()
返回的计数,但新机制通过从“cache
”中减去“cache_end
”来计算行数,以找到范围的大小。
然而,等式是错误的,因为它除以sizeof(struct cache_entry *)
。 这不是指针算术的工作原理!为 2.25.0 版本做准备的适用于 Windows 的 Git 的覆盖构建发现此问题并带有警告:
Pointer differences, such as `cache_end` - cache, are automatically scaled down by the size (8 bytes) of the pointed-to type (struct `cache_entry` *). Most likely, the division by sizeof(struct `cache_entry` *) is extraneous and should be eliminated.
这个警告是正确的。
在 Git 2.26(2020 年第一季度)中,稀疏结账功能中的一些粗糙边缘,尤其是在锥形模式周围,已被清理干净。
参见提交F998A3F , 提交D2E65F4 , 提交E53FFE2 , 提交E55682E , COMMAR BD64DE4 , 提交D585F0E , 提交4F52C2C , 提交9ABC60F (2020年1月31日)和提案9E6D3E , 提交41DE0C6 , 提交47DC6 ,dist 47DC11, dist 47DC11 , dist 32 , 2020 年 1 月),由Derrick Stolee ( derrickstolee
) 撰写。
请参阅Jeff King ( peff
)的commit 7aa9ef2 (2020 年 1 月 24 日)。
(由Junio C Hamano -- gitster
--在提交 433b8aa中合并,2020 年 2 月 14 日)
sparse-checkout
:修复锥模式行为不匹配报告人:芬恩·布莱恩特
签字人:Derrick Stolee
稀疏检出功能中特殊的“锥形模式”的目的是始终匹配与禁用锥形模式时相同的稀疏检出文件匹配的相同模式。
当在锥形模式下将文件路径提供给“
git sparse-checkout
set”时,锥形模式会不正确地将文件匹配为递归路径。
设置跳过工作树位时,文件不期望MATCHED_RECURSIVE
响应,因此这些被排除在匹配锥之外。通过在
MATCHED
之外检查MATCHED_RECURSIVE
并添加防止回归的测试来修复此错误。
该文档现在包括:
启用
core.sparseCheckoutCone
时,输入列表被视为目录列表,而不是稀疏检出模式。
该命令将模式写入 sparse-checkout 文件以包括包含在这些目录中的所有文件(递归地)以及作为祖先目录的兄弟的文件。
输入格式与git ls-tree --name-only
的输出相匹配。 这包括将以双引号 ("
) 开头的路径名解释为 C 风格的带引号的字符串。
在 Git 2.26(2020 年第一季度)中,“ git sparse-checkout
”学习了一个新的“ add
”子命令。
请参阅 Derrick Stolee (derrickstolee) 的提交 6c11c6a (2020 年 2 月 20 日)和提交 ef07659 、 提交 2631dc8 、 提交 4bf0c06 、 提交 6fb705a (2020 年 2 月 11 日derrickstolee
。
(由Junio C Hamano -- gitster
--在提交 f4d7dfc中合并,2020 年 3 月 5 日)
sparse-checkout
:创建“添加”子命令签字人:Derrick Stolee
使用稀疏结账功能时,用户可能希望逐步增长其稀疏结账模式集。
允许使用新的“添加”子命令添加模式。这与“set”子命令没有太大区别,因为我们仍然希望允许“
--stdin
”选项并将输入解释为在锥模式下的目录和模式,否则。在圆锥模式下,我们正在增长圆锥。
当A/B
已经是锥体中的目录时,这实际上可能会减少添加目录A
时的模式集。 测试不同的案例:兄弟姐妹、父母、祖先。当不处于锥形模式时,我们只能假设模式应该附加到 sparse-checkout 文件中。
和:
sparse-checkout
:使用 Windows 路径签字人:Derrick Stolee
使用 Windows 时,用户可以运行 '
git sparse-checkout
set A\B\C' to add the Unix-style path
A/B/C` 添加到他们的稀疏检出模式中。在我们将字符串“
A/B/C
”添加到递归哈希集之前,规范化输入路径会将反斜杠转换为斜杠。
稀疏签出模式长期以来一直被禁止排除所有路径,留下一棵空的工作树。
在 Git 2.27(2020 年第二季度)中,这一限制已被解除。
请参阅Derrick Stolee ( derrickstolee
) 的提交 ace224a (2020 年 5 月 4 日)。
(由Junio C Hamano -- gitster
--在提交 e9acbd6中合并,2020 年 5 月 8 日)
sparse-checkout
:停止阻止空工作目录报告人:Lars Schneider
签字人:Derrick Stolee
删除更新稀疏结帐时的错误条件会留下一个空的工作目录。
此行为是在9e1afb167中添加的(“稀疏结帐:禁止空工作树”,2009-08-20,Git v1.7.0-rc0 -- 合并)。
该评论已添加到a7bc906f2中(“添加解释为什么我们不允许稀疏结帐到空工作树”,2011-09-22,Git v1.7.8-rc0 -- 合并)以响应84563a624中的“可疑”评论(“
[
unpack-trees.c](https
):外观修复”,2010-12-22,Git v1.7.5-rc0 - - 合并)。使用最近的“锥形模式”和“
git sparse-checkout init [--cone]
”命令,通常设置一个合理的sparse-checkout模式集/* !/*/
仅匹配根目录下的文件。 如果存储库没有这样的文件,那么他们的“
git sparse-checkout init
”命令将会失败。现在我们希望这是一种常见的模式,我们不应该让命令在空工作目录上失败。
如果结果令人困惑,则用户可以使用“git sparse-checkout disable
”或“git sparse-checkout set
”来恢复。 这在使用锥形模式时尤其简单。
使用 Git 2.37(2022 年第三季度),弃用稀疏结帐功能的非锥形模式。
请参阅Elijah Newren ( newren
)的提交5d4b293 、提交a8defed 、 提交 72fa58e 、 提交 5d295dc 、 提交 0d86f59 、 提交 71ceb81 、 提交 f69dfef 、 提交 2d95707 、 提交 dde1358 (2022 年 4 月 22 日)。
(由Junio C Hamano -- gitster
--在提交 377d347中合并,2022 年 6 月 3 日)
sparse-checkout
: 将 --cone 设为默认值签字人:以利亚·纽伦
将锥形模式设为默认模式,并相应地更新文档。
git config
现在包含在其手册页中:
通过将此变量设置为“假”,可以请求“非锥形模式”以允许指定更灵活的模式。
git sparse-checkout
现在包含在其手册页中:
除非
core.sparseCheckoutCone
明确设置为false
,否则 Git 将解析期望这些类型的模式的 sparse-checkout 文件。 如果模式不匹配,Git 会发出警告。 如果模式确实与预期的格式匹配,那么 Git 将使用更快的基于哈希的算法来计算稀疏结账中的包含。
和:
git-sparse-checkout.txt
:锥形模式默认的措辞更新签字人:以利亚·纽伦
既然锥形模式是默认设置,我们希望关注设置/添加的参数是目录而不是模式,并且提供一个更早的提示可能是有意义的,即来自前导目录的文件也被包含在内。
git sparse-checkout
现在包含在其手册页中:
默认情况下,输入列表被视为目录列表,与
git ls-tree -d --name-only
的输出匹配。
这包括将以双引号 ("
) 开头的路径名解释为 C 风格的带引号的字符串。请注意,指定目录下的所有文件(任何深度)都将包含在稀疏检出中,以及作为给定目录或其任何祖先的兄弟文件的文件(有关更多详细信息,请参见下面的“CONE PATTERN SET”) .
过去,这不是默认设置,需要指定
--cone
或启用core.sparseCheckoutCone
。
我有同样的问题。 我用类似的东西修复了它:
!presentations/heavy_presentation
presentations/*
我如何理解它的工作原理:它逐条读取文件规则。 如果包含某些内容,它将包含包含该单词的所有路径,并且在稀疏结帐结束之前它不会再更改其状态。 如果您在包含之前添加排除规则,我认为它将首先删除文件,然后将所有文件标记为包含。
我不完全确定,这是我根据我的经验所设想的并且一直在为我工作。 我希望它会帮助某人。
简短的回答:
git sparse-checkout set /* !/presentations/heavy_presentation/
git sparse-checkout init [--cone]
--cone
选项:仅与少数模式/小型 repo 无关,但通常用于加速。 需要特定规范的模式顺序,如sparse-checkout
/ CONE PATTERN SET
文档所述)。 稍后也可以通过以下方式介绍:
git config core.sparseCheckoutCone true
使用 Git 2.37(2022 年 6 月发布)就容易多了。 要排除一个文件夹和一些与掩码匹配的文件(只是为了提供比问题要求更通用/有用的示例),我这样做了:
git sparse-checkout set --no-cone "/*" "!/folder/" "!/path/to/dist/*.map"
这非常直观(好吧,在花了几个小时找到这个公式之后)。 该folder
完全消失, path/to/dist
文件夹中的所有*.map
文件也消失了。 没有其他东西被触及。
几个重要的位:
如果它有任何未暂存/忽略的文件,我强烈建议在开始之前备份您的本地存储库。 我的第一次尝试(没有“/*”等)很可怕——好像我的大部分数据都消失了。 下面的#5 似乎有助于恢复一切,但你永远无法确定是否有大回购...
"/*"
是神奇的一块。 它要求 GIT 包括以后未排除的所有内容。 没有它就无法工作(删除大量回购内容)。 它必须在列表中排在第一位!
您可能需要set +H
才能使命令通过(bash 将!
视为特殊命令)。 然后set -H
以恢复默认的 bash 行为。
我建议通过键入以下内容来检查 GIT 对您使用的路径的解释:
cat.git/info/sparse-checkout
在为我的案例找到“公式”之前,我多次对结果感到惊讶(例如,参见#6)。
运行命令后执行ls
一些回购路径。 如果 go 错误,那么git sparse-checkout disable
应该可以恢复所有丢失的文件。 至少这对我来说效果很好。
最好为所有路径使用引号。 在 "/*" 中尤为重要。 这是我在不带引号的情况下使用 git/info/sparse-checkout 时得到的内容(每个都来自新行:由于某种原因,stackoverflow 的格式不太好):
/bin /dev /etc /home /lib /lib64 /opt /proc /root /run /sbin /tmp /usr /var.folder/ !path/to/dist/*.map
你可以想象这些模式不是我想说的......
注意到处都是斜杠( "!/folder/"
)。 如果省略 ( "!folder/"
),那么具有这样名称的文件夹将在层次结构中的所有位置被删除,而不仅仅是在顶层。
--no-cone
现在很重要。 这是过去的默认模式,当通过 inte.net 查看旧建议时,这可能会引起很多混乱! 如果您想更好地理解事物, GIT 文档对此进行了详细说明。
希望这对某人有帮助。
更新:在排除的路径中添加了前导斜杠,如上面#7 中所述。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.