简体中文 ▾ 主题 ▾ 最新版本 ▾ 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 PATTERN SET)。过去,这并不是默认设置,需要指定 --cone 或启用 core.sparseCheckoutCone

当传递 --no-cone 时,输入列表被视为模式列表。此模式有许多缺点,包括与某些选项(如 --sparse-index)不兼容。如下面“非锥形模式问题”一节所述,我们不建议使用它。

使用 --[no-]sparse-index 选项来使用稀疏索引(默认是不使用)。稀疏索引减小了索引的大小,使其更接近你的稀疏检出定义。这对于 git statusgit add 等命令具有显著的性能优势。此功能仍处于实验阶段。某些命令在使用稀疏索引时可能会较慢,直到它们与该功能正确集成。

警告:使用稀疏索引需要以外部工具无法完全理解的方式修改索引。如果你在使用此兼容性时遇到问题,请运行 git sparse-checkout init --no-sparse-index 来重写你的索引,使其不再是稀疏的。旧版本的 Git 将无法理解稀疏目录条目索引扩展,并且可能无法与你的仓库交互,直到禁用它为止。

add(添加)

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

reapply(重新应用)

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

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

disable(禁用)

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

init(初始化)

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

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

此外,从历史上看,如果稀疏检出文件已经存在,init 命令实际上不会初始化它。这意味着可以在不记住要传递给后续 setadd 命令的路径的情况下返回到稀疏检出。然而,--cone--sparse-index 选项在禁用命令后不会被记住,因此调用简单的 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 的错误会立即出现在输出中。对于 sparse-checkout,错误在 sparse-checkout 命令运行时被记录,并且可能直到用户稍后切换分支、变基或合并时才出现问题,从而在用户错误和他们有机会发现/注意到错误之间造成延迟。

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

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

  • 所有其他想要提供某种“特殊路径模式匹配”的 git 子命令都使用 pathspecs,但 sparse-checkout 的非锥形模式使用 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 将使用更快的基于哈希的算法来计算稀疏检出中的包含。如果它们不匹配,无论 core.sparseCheckoutCone 的设置如何,Git 的行为都将如同它被设置为 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