简体中文 ▾ 主题 ▾ 最新版本 ▾ git-sparse-checkout 上次更新于 2.52.0

名称

git-sparse-checkout - 将工作目录限制为跟踪文件的一个子集

概要

git sparse-checkout (init | list | set | add | reapply | disable | check-rules | clean) [<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 或启用 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 命令中的标志相同,以便在无需重新指定所有稀疏路径的情况下更改您使用的稀疏模式。

clean

机会性地删除稀疏签出定义之外的文件。此命令需要锥形模式,才能使用递归目录匹配来确定应删除哪些文件。如果一个文件位于稀疏签出定义之外的跟踪目录中,则该文件将被考虑删除。

某些特殊情况,例如合并冲突或稀疏签出定义之外的已修改文件,可能会导致保留原本会被删除的文件。请解决冲突、暂存修改,并结合使用 git sparse-checkout reapplygit sparse-checkout clean 来处理这些情况。

此命令可用于确保稀疏索引高效工作,尽管它不需要通过 index.sparse=true 配置启用稀疏索引功能。

为防止意外删除工作目录文件,clean 子命令不会在没有 -f--force 选项的情况下删除任何文件,除非 clean.requireForce 配置选项设置为 false

--dry-run 选项将列出将被删除的目录而不实际删除它们。以这种模式运行有助于预测 clean 命令的行为或确定哪些类型的文件保留在稀疏目录中。

--verbose 选项将列出被考虑删除的目录中的每个文件。此选项有助于确定这些文件是否确实重要,或者解释为什么该目录尽管存在当前的稀疏签出仍然存在。

disable

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

init

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

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

此外,历史上,init 在稀疏签出文件已存在时不会真正初始化它。这意味着有可能在不记得要将哪些路径传递给后续的 setadd 命令的情况下返回到稀疏签出。但是,--cone--sparse-index 选项不会在 disable 命令之间保留,因此调用普通的 init 来轻松恢复其效用有所下降。

check-rules

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

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

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

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

当使用 -z 标志调用时,标准输入上的路径以及输出路径的格式将使用 \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 风格模式存在许多缺点。

  • 根本上,这使得各种工作树更新过程(pull, merge, rebase, switch, reset, checkout 等)需要 O(N*M) 次模式匹配,其中 N 是模式的数量,M 是索引中的路径数量。这种扩展性很差。

  • 要避免这种扩展性问题,必须通过指定前导目录名或 glob 来限制模式的数量。

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

  • 与上一项相关的是,sparse-checkout 有一个 add 子命令但没有 remove 子命令。即使添加了 remove 子命令,撤销意外的未引用 glob 也存在“移除过多”的风险,因为它可能会移除先前由于意外添加而包含的条目。

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

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

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

    首先,两个用户在子目录中,第一个用户运行

    git sparse-checkout set '/toplevel-dir/*.c'

    而第二个用户运行

    git sparse-checkout set relative-dir

    这些参数是否应该被转换成

    current/subdirectory/toplevel-dir/*.c

    current/subdirectory/relative-dir

    在插入稀疏签出文件之前?输入第一个命令的用户可能知道 set/add 命令的参数在非锥形模式下应该是模式,并且可能不会喜欢这种转换。然而,许多 gitignore 风格的模式只是路径,这可能就是输入第二个命令的用户所想的,如果他们的参数没有被转换,他们会感到不满。

    其次,对于非锥形模式的用户,bash 补全应该在 set/add 命令上补全什么?如果它建议路径,它是否会加剧上述问题?另外,如果它建议路径,用户是否有文件或目录以“!”或“#”开头,或者其名称中包含“*”、“\”、“?”、“[”或“]”?如果它建议路径,它会将“/pro”补全为“/proc”(在根文件系统中),而不是当前目录下的“/progress.txt”?(请注意,用户很可能希望在非锥形模式下以斜杠(/)开头路径,原因与 .gitignore 文件经常包含斜杠的原因相同。)在这些情况下,对文件或目录进行补全可能会带来令人不快的意外。

  • 过度的灵活性使得其他扩展基本上不切实际。在非锥形模式下,--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/CA/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] 套件的一部分