Git
English ▾ 主题 ▾ 最新版本 ▾ git-sparse-checkout 最后更新于 2.42.0

名称

git-sparse-checkout - 将您的工作树缩减到跟踪文件的子集

概要

git sparse-checkout (init | list | set | add | reapply | disable | check-rules) [<options>]

描述

此命令用于创建稀疏检出,它将工作树从包含所有跟踪文件更改为仅包含这些文件的一个子集。它还可以切换存在的文件的子集,或撤消并返回到在工作副本中存在所有跟踪文件的状态。

文件子集是通过在锥模式(默认模式)下提供目录列表,或在非锥模式下提供模式列表来选择的。

在稀疏检出中,其他 Git 命令的行为略有不同。例如,切换分支不会更新稀疏检出目录/模式之外的路径,并且git commit -a不会将稀疏检出目录/模式之外的路径记录为已删除。

此命令为实验性功能。其行为以及其他命令在存在稀疏检出时存在的行为可能会在将来发生变化。

命令

list

描述稀疏检出文件中的目录或模式。

set

如果尚未将必要的稀疏检出配置设置(core.sparseCheckoutcore.sparseCheckoutConeindex.sparse)设置为所需的值,则启用它们,从 set 子命令之后的参数列表中填充稀疏检出文件,并更新工作目录以匹配。

为了确保在工作树中调整稀疏检出设置不会更改其他工作树中的稀疏检出设置,set 子命令将升级您的存储库配置以使用特定于工作树的配置(如果尚未存在)。set 子命令的参数定义的稀疏性存储在特定于工作树的稀疏检出文件中。有关更多详细信息,请参阅git-worktree[1]以及git-config[1]extensions.worktreeConfig 的文档。

当提供--stdin选项时,目录或模式将从标准输入中读取为换行符分隔的列表,而不是从参数中读取。

默认情况下,输入列表被视为目录列表,与git ls-tree -d --name-only的输出匹配。这包括将以双引号 (") 开头的路径名解释为 C 样式的带引号的字符串。请注意,指定目录(在任何深度)下的所有文件都将包含在稀疏检出中,以及作为给定目录或其任何祖先的同级文件(有关更多详细信息,请参阅下面的CONE 模式集)。过去,这不是默认设置,需要指定--cone或启用core.sparseCheckoutCone

当传递--no-cone时,输入列表被视为模式列表。此模式有一些缺点,包括不适用于一些选项,例如--sparse-index。如以下“非锥问题”部分所述,我们不建议使用它。

使用--[no-]sparse-index选项以使用稀疏索引(默认情况下不使用它)。稀疏索引会减小索引的大小,使其更紧密地与您的稀疏检出定义保持一致。这对于git statusgit add等命令可以带来明显的性能优势。此功能仍处于实验阶段。某些命令在与该功能正确集成之前,使用稀疏索引可能会变慢。

警告:使用稀疏索引需要修改索引,而外部工具对此并不完全了解。如果您遇到此兼容性问题,请运行git sparse-checkout init --no-sparse-index以重写您的索引,使其不为稀疏。旧版本的 Git 将无法理解稀疏目录条目索引扩展,并且在禁用它之前可能会无法与您的存储库交互。

add

更新稀疏检出文件以包含其他目录(在锥模式下)或模式(在非锥模式下)。默认情况下,这些目录或模式从命令行参数中读取,但可以使用--stdin选项从 stdin 读取。

reapply

将稀疏性模式规则重新应用于工作树中的路径。诸如合并或变基之类的命令可以具体化路径以执行其工作(例如,为了向您显示冲突),其他稀疏检出命令可能会无法使单个文件变得稀疏(例如,因为它具有未暂存的更改或冲突)。在这种情况下,在清理受影响的路径(例如,解决冲突、撤消或提交更改等)后,稍后运行git sparse-checkout reapply可能很有意义。

reapply命令还可以采用--[no-]cone--[no-]sparse-index标志,其含义与set命令中的标志相同,以便更改您正在使用的稀疏性模式,而无需也重新指定所有稀疏性路径。

disable

禁用core.sparseCheckout配置设置,并将工作目录恢复为包含所有文件。

init

已弃用的命令,其行为类似于未指定路径的set。将来可能会删除。

从历史上看,set没有处理所有必要的配置设置,这意味着必须同时调用initset。调用两者意味着init步骤将首先删除几乎所有跟踪文件(在锥模式下,还包括忽略的文件),然后set步骤将添加许多跟踪文件(但不包括忽略的文件)回来。除了丢失的文件外,此组合的性能和 UI 也很差。

此外,从历史上看,init实际上不会在稀疏检出文件已存在时初始化它。这意味着可以返回到稀疏检出,而无需记住要传递到后续的setadd命令的哪些路径。但是,--cone--sparse-index选项不会在禁用命令中记住,因此调用普通init的简单恢复实用程序降低了。

check-rules

检查稀疏性规则是否与一个或多个路径匹配。

默认情况下,check-rules从 stdin 读取路径列表,并且仅输出与当前稀疏性规则匹配的路径。输入应包含每行一个路径,与git ls-tree --name-only的输出匹配,包括以双引号 (") 开头的路径名被解释为 C 样式的带引号的字符串。

当使用--rules-file <file>标志调用时,输入文件将与<file>中找到的稀疏检出规则匹配,而不是当前规则。文件中的规则应采用与git sparse-checkout set --stdin接受的相同格式(特别是,它们必须是换行符分隔的)。

默认情况下,传递给--rules-file选项的规则被解释为锥模式目录。要使用--rules-file传递非锥模式模式,请将该选项与--no-cone选项结合使用。

当使用-z标志调用时,stdin 上的路径输入以及输出路径的格式为\0 终止且不带引号。请注意,这并不适用于使用--rules-file选项传递的规则的格式。

示例

git sparse-checkout set MY/DIR1 SUB/DIR2

更改为稀疏检出,工作副本中存在 MY/DIR1/ 和 SUB/DIR2/ 下的所有文件(在任何深度)(加上 MY/ 和 SUB/ 以及顶级目录下立即存在的所有文件)。如果已处于稀疏检出状态,请将工作副本中存在的文件更改为此新的选择。请注意,此命令还将删除不再存在跟踪文件或非忽略未跟踪文件的所有目录中的所有忽略文件。

git sparse-checkout disable

使用所有文件重新填充工作目录,禁用稀疏检出。

git sparse-checkout add SOME/DIR/ECTORY

将 SOME/DIR/ECTORY/ 下的所有文件(任意深度)以及 SOME/DIR/ 和 SOME/ 下的所有直接子文件添加到稀疏检出中。在使用此命令之前,必须已处于稀疏检出状态。

git sparse-checkout reapply

某些命令可能会以不尊重所选稀疏目录的方式更新工作树。这可能是由于 Git 之外的工具写入文件导致的,甚至可能影响 Git 命令,因为存在特殊情况(例如在合并/变基时遇到冲突),或者因为某些命令并未完全支持稀疏检出(例如,旧的 recursive 合并后端仅支持有限的功能)。此命令会重新应用现有的稀疏目录规范,使工作目录保持一致。

内部机制 — 稀疏检出

“稀疏检出”允许稀疏地填充工作目录。它使用 skip-worktree 位(请参阅 git-update-index[1])来告诉 Git 工作目录中的文件是否值得关注。如果设置了 skip-worktree 位,并且工作树中不存在该文件,则忽略其不存在。Git 将避免填充这些文件的内容,这使得在处理包含许多文件但只有少数文件对当前用户重要的存储库时,稀疏检出非常有用。

$GIT_DIR/info/sparse-checkout 文件用于定义 skip-worktree 参考位图。当 Git 更新工作目录时,它会根据此文件更新索引中的 skip-worktree 位。与文件中的模式匹配的文件将出现在工作目录中,其余文件将不会出现。

内部机制 — 非锥形模式问题

setadd 子命令填充的 $GIT_DIR/info/sparse-checkout 文件被定义为一系列模式(每行一个),使用与 .gitignore 文件相同的语法。在锥形模式下,这些模式被限制为匹配目录(用户只需要提供或查看目录名称),而在非锥形模式下,允许使用任何 gitignore 样式模式。在非锥形模式下使用完整的 gitignore 样式模式有一些缺点。

  • 从根本上说,它使得各种工作树更新过程(拉取、合并、变基、切换、重置、检出等)需要进行 O(N*M) 模式匹配,其中 N 是模式的数量,M 是索引中路径的数量。这扩展性很差。

  • 避免扩展性问题必须通过限制模式的数量来实现,方法是指定前导目录名称或通配符。

  • 在命令行上传递通配符容易出错,因为用户可能会忘记引用通配符,导致 shell 将其扩展为所有匹配的文件,并将它们全部单独传递给 sparse-checkout set/add。虽然这在例如“git grep — *.c”中也可能是一个问题,但 grep/log/status 的错误会立即出现在输出中。对于稀疏检出,错误会在运行 sparse-checkout 命令时记录下来,并且可能不会成为问题,直到用户稍后切换分支或变基或合并,从而在用户错误和他们有机会捕获/注意到错误之间产生延迟。

  • 与上一项相关,sparse-checkout 有一个 add 子命令,但没有 remove 子命令。即使添加了 remove 子命令,撤消意外的未引用通配符也会存在“删除过多”的风险,因为它可能会删除在意外添加之前已包含的条目。

  • 非锥形模式使用 gitignore 样式模式来选择要包含的内容(否定模式除外),而 .gitignore 文件使用 gitignore 样式模式来选择要排除的内容(否定模式除外)。关于 gitignore 样式模式的文档通常不会用匹配或不匹配来表达,而是用用户想要“排除”的内容来表达。这可能会导致试图学习如何指定稀疏检出模式以获得所需行为的用户感到困惑。

  • 其他每个想要提供某种“特殊路径模式匹配”的 git 子命令都使用路径规范,但稀疏检出的非锥形模式使用 gitignore 模式,这感觉不一致。

  • 它有一些边缘情况,其中“正确”的行为不清楚。两个例子

    First, two users are in a subdirectory, and the first runs
       git sparse-checkout set '/toplevel-dir/*.c'
    while the second runs
       git sparse-checkout set relative-dir
    Should those arguments be transliterated into
       current/subdirectory/toplevel-dir/*.c
    and
       current/subdirectory/relative-dir
    before inserting into the sparse-checkout file?  The user who typed
    the first command is probably aware that arguments to set/add are
    supposed to be patterns in non-cone mode, and probably would not be
    happy with such a transliteration.  However, many gitignore-style
    patterns are just paths, which might be what the user who typed the
    second command was thinking, and they'd be upset if their argument
    wasn't transliterated.
    Second, what should bash-completion complete on for set/add commands
    for non-cone users?  If it suggests paths, is it exacerbating the
    problem above?  Also, if it suggests paths, what if the user has a
    file or directory that begins with either a '!' or '#' or has a '*',
    '\', '?', '[', or ']' in its name?  And if it suggests paths, will
    it complete "/pro" to "/proc" (in the root filesystem) rather than to
    "/progress.txt" in the current directory?  (Note that users are
    likely to want to start paths with a leading '/' in non-cone mode,
    for the same reason that .gitignore files often have one.)
    Completing on files or directories might give nasty surprises in
    all these cases.
  • 过度的灵活性使得其他扩展基本上变得不切实际。--sparse-index 在非锥形模式下可能是不可能的;即使它以某种方式可行,实现它也会花费更多工作,并且在实践中可能太慢了。一些关于在部分克隆和稀疏检出之间添加耦合的想法也只有在使用更受限制的路径集时才切实可行。

由于所有这些原因,非锥形模式已弃用。请切换到使用锥形模式。

内部机制 — 锥形模式处理

“锥形模式”(默认模式)允许你仅指定要包含的目录。对于任何指定的目录,该目录下的所有路径都将包含在内,并且任何位于前导目录(包括顶级目录)下的直接路径也将包含在内。因此,如果你指定了目录 Documentation/technical/,那么你的稀疏检出将包含

  • 顶级目录中的所有文件

  • Documentation/ 下的所有直接子文件

  • Documentation/technical/ 下任意深度的所有文件

此外,在锥形模式下,即使未指定任何目录,顶级目录中的文件也将包含在内。

在锥形模式下更改稀疏检出模式时,Git 将检查不在稀疏检出锥体内的每个已跟踪目录,以查看它是否包含任何未跟踪的文件。如果所有这些文件都因 .gitignore 模式而被忽略,则将删除该目录。如果该目录内的任何未跟踪文件未被忽略,则该目录内不会发生任何删除,并且会显示警告消息。如果这些文件很重要,请重置你的稀疏检出定义以包含它们,使用 git addgit commit 存储它们,然后手动删除任何剩余的文件,以确保 Git 能够以最佳方式运行。

另请参阅“内部机制 — 锥形模式集”部分,了解目录在后台如何转换为稀疏检出的完整模式集的子集。

内部机制 — 完整模式集

完整模式集允许任意模式匹配和复杂的包含/排除规则。在更新索引时,这些规则会导致 O(N*M) 模式匹配,其中 N 是模式的数量,M 是索引中路径的数量。为了解决此性能问题,当启用 core.sparseCheckoutCone 时,允许使用更受限制的模式集。

稀疏检出文件使用与 .gitignore 文件相同的语法;有关详细信息,请参阅 gitignore[5]。但是,这里的模式通常用于选择要包含的文件,而不是要排除的文件。(但是,它可能会有点令人困惑,因为 gitignore 样式模式具有以开头的模式定义的否定,因此你也可以选择包含的文件。)

例如,要选择所有内容,然后删除文件 unwanted(以便工作树中将显示除名为 unwanted 的文件之外的所有文件)

git sparse-checkout set --no-cone '/*' '!unwanted'

这些模式只是按原样放置到 $GIT_DIR/info/sparse-checkout 中,因此此时该文件的内容将是

/*
!unwanted

另请参阅 git-read-tree[1] 的“稀疏检出”部分,以了解有关稀疏检出中使用的 gitignore 样式模式的更多信息。

内部机制 — 锥形模式集

在锥形模式下,仅接受目录,但它们会被转换为完整模式集中使用的相同 gitignore 样式模式。我们称这些模式类型为以下两种类型之一

  1. 递归:包含目录内的所有路径。

  2. 父级:包含目录内的所有直接文件。

由于锥形模式始终包含顶级文件,因此在不指定任何目录的情况下运行 git sparse-checkout set 时,顶级目录将作为父级模式添加。此时,稀疏检出文件包含以下模式

/*
!/*/

这表示“包含顶级目录下的所有直接子文件,但不包含该目录下任何级别的文件”。

在锥形模式下,git sparse-checkout set 子命令接受目录列表。命令 git sparse-checkout set A/B/C 将目录 A/B/C 设置为递归模式,目录 AA/B 将作为父级模式添加。生成的稀疏检出文件现在是

/*
!/*/
/A/
!/A/*/
/A/B/
!/A/B/*/
/A/B/C/

这里,顺序很重要,因此否定模式会被文件中出现的正模式覆盖。

除非 core.sparseCheckoutCone 显式设置为 false,否则 Git 将解析稀疏检出文件,期望这些类型的模式。如果模式不匹配,Git 将发出警告。如果模式与预期格式匹配,则 Git 将使用更快的基于哈希的算法来计算稀疏检出中的包含关系。如果它们不匹配,则无论其设置如何,git 的行为都将如同 core.sparseCheckoutCone 为 false 一样。

在锥形模式情况下,尽管完整模式写入 $GIT_DIR/info/sparse-checkout 文件,但 git sparse-checkout list 子命令将列出定义递归模式的目录。对于上面的稀疏检出文件示例,输出如下所示

$ git sparse-checkout list
A/B/C

如果 core.ignoreCase=true,则模式匹配算法将使用不区分大小写的检查。这会纠正 git sparse-checkout set 命令中大小写不匹配的文件名,以反映工作目录中的预期锥体。

内部机制 — 子模块

如果你的存储库包含一个或多个子模块,则子模块将根据与 git submodule 命令的交互进行填充。具体来说,git submodule init -- <path> 将确保 <path> 处的子模块存在,而 git submodule deinit [-f] -- <path> 将删除 <path> 处的子模块的文件(包括任何未跟踪的文件、未提交的更改和未推送的历史记录)。与稀疏检出从工作树中删除文件但仍保留索引中的条目类似,已取消初始化的子模块将从工作目录中删除,但在索引中仍保留条目。

由于子模块可能存在未推送的更改或未跟踪的文件,因此删除它们可能会导致数据丢失。因此,更改稀疏包含/排除规则不会导致已检出的子模块从工作副本中删除。换句话说,就像 checkout 即使在切换删除或添加子模块的分支之间也不会导致子模块自动删除或初始化一样,使用 sparse-checkout 减少或扩展“有趣”文件的范围也不会导致子模块自动取消初始化或初始化。

此外,上述事实意味着“已跟踪”文件可能不会出现在工作副本中的原因有多个:来自稀疏检出的稀疏模式应用和子模块初始化状态。因此,在工作副本中处理已跟踪文件的命令(如 git grep)可能会返回受这两个限制之一或两者限制的结果。

Git

git[1] 套件的一部分

scroll-to-top