Git
英语 ▾ 主题 ▾ 最新版本 ▾ git-update-index 最后更新于 2.46.0

名称

git-update-index - 将工作树中的文件内容注册到索引

概要

git update-index
	     [--add] [--remove | --force-remove] [--replace]
	     [--refresh] [-q] [--unmerged] [--ignore-missing]
	     [(--cacheinfo <mode>,<object>,<file>)…​]
	     [--chmod=(+|-)x]
	     [--[no-]assume-unchanged]
	     [--[no-]skip-worktree]
	     [--[no-]ignore-skip-worktree-entries]
	     [--[no-]fsmonitor-valid]
	     [--ignore-submodules]
	     [--[no-]split-index]
	     [--[no-|test-|force-]untracked-cache]
	     [--[no-]fsmonitor]
	     [--really-refresh] [--unresolve] [--again | -g]
	     [--info-only] [--index-info]
	     [-z] [--stdin] [--index-version <n>]
	     [--show-index-version]
	     [--verbose]
	     [--] [<file>…​]

描述

修改索引。每个提到的文件都将更新到索引中,任何未合并需要更新状态都将被清除。

有关在索引上执行一些最常见操作的更友好的方法,请参阅 git-add[1]

git update-index 处理其被告知的文件的方式可以使用各种选项进行修改

选项

--add

如果指定的文件不在索引中,则将其添加。默认行为是忽略新文件。

--remove

如果指定的文件在索引中,但已丢失,则将其删除。默认行为是忽略已删除的文件。

--refresh

查看当前索引并通过检查 stat() 信息来检查是否需要合并或更新。

-q

安静。如果 --refresh 发现索引需要更新,默认行为是出错。此选项使 git update-index 继续执行。

--ignore-submodules

不要尝试更新子模块。此选项仅在传递到 --refresh 之前才会生效。

--unmerged

如果 --refresh 在索引中发现未合并的更改,默认行为是出错。此选项使 git update-index 继续执行。

--ignore-missing

在 --refresh 期间忽略丢失的文件。

--cacheinfo <mode>,<object>,<path>
--cacheinfo <mode> <object> <path>

直接将指定的信息插入索引。为了向后兼容,你也可以将这三个参数作为三个单独的参数给出,但鼓励新用户使用单参数形式。

--index-info

从 stdin 读取索引信息。

--chmod=(+|-)x

设置更新文件的执行权限。

--[no-]assume-unchanged

当指定此标志时,不会更新为路径记录的对象名称。相反,此选项设置/取消设置路径的“假定不变”位。当“假定不变”位开启时,用户承诺不会更改文件,并允许 Git 假定工作树文件与索引中记录的内容匹配。如果你要更改工作树文件,你需要取消设置该位来告诉 Git。这在大型项目中使用具有非常缓慢的 lstat(2) 系统调用的文件系统(例如 cifs)时有时会有所帮助。

如果 Git 需要修改索引中的此文件(例如在合并提交时),它将(优雅地)失败;因此,如果假定未跟踪的文件在 upstream 被更改,则需要手动处理这种情况。

--really-refresh

类似于 --refresh,但无条件地检查 stat 信息,而不考虑“假定不变”设置。

--[no-]skip-worktree

当指定其中一个标志时,不会更新为路径记录的对象名称。相反,这些选项设置和取消设置路径的“跳过工作树”位。有关更多信息,请参阅下面的“跳过工作树位”部分。

--[no-]ignore-skip-worktree-entries

即使指定了 --remove 选项,也不要删除跳过工作树(又名“仅索引”)条目。

--[no-]fsmonitor-valid

当指定其中一个标志时,不会更新为路径记录的对象名称。相反,这些选项设置和取消设置路径的“文件系统监视器有效”位。有关更多信息,请参阅下面的“文件系统监视器”部分。

-g
--again

在索引条目与 HEAD 提交中的索引条目不同的路径上运行 git update-index 本身。

--unresolve

在合并期间恢复文件的未合并需要更新状态,如果它不小心被清除。

--info-only

不要为所有跟随此标志的 <file> 参数在对象数据库中创建对象;只需将它们的对象 ID 插入索引即可。

--force-remove

即使工作目录中仍然存在该文件,也要从索引中删除该文件。(意味着 --remove。)

--replace

默认情况下,当索引中存在文件 path 时,git update-index 会拒绝尝试添加 path/file。类似地,如果存在文件 path/file,则不能添加文件 path。使用 --replace 标志,与要添加的条目冲突的现有条目会自动删除,并显示警告消息。

--stdin

不要从命令行获取路径列表,而是从标准输入读取路径列表。默认情况下,路径以 LF 分隔(即每行一个路径)。

--verbose

报告正在添加到索引和从索引中删除的内容。

--index-version <n>

将生成的索引以命名的磁盘格式版本写入。支持的版本为 2、3 和 4。当前默认版本为 2 或 3,具体取决于是否使用额外的功能,例如 git add -N。使用 --verbose,还会报告该命令之前和之后索引文件使用的版本。

版本 4 执行简单的路径名压缩,这会减少大型存储库的索引大小 30%-50%,从而缩短加载时间。Git 自 2012 年 10 月发布的版本 1.8.0 起支持它,并且在 2016 年为 libgit2 添加了对它的支持,在 2020 年为 JGit 添加了对它的支持。此手册页面的旧版本称其为“相对较年轻”,但现在应该将其视为成熟技术。

--show-index-version

报告磁盘索引文件使用的索引格式版本。请参阅上面的 --index-version

-z

仅在 --stdin--index-info 有意义;路径以 NUL 字符而不是 LF 分隔。

--split-index
--no-split-index

启用或禁用拆分索引模式。如果拆分索引模式已启用并且再次给出 --split-index,则 $GIT_DIR/index 中的所有更改将被推回到共享索引文件。

无论 core.splitIndex 配置变量的值如何,这些选项都会生效(请参阅 git-config[1])。但当更改与配置的值相矛盾时,会发出警告,因为配置的值将在下次读取索引时生效,这将消除选项的预期效果。

--untracked-cache
--no-untracked-cache

启用或禁用未跟踪缓存功能。请在启用它之前使用 --test-untracked-cache

无论 core.untrackedCache 配置变量的值如何,这些选项都会生效(请参阅 git-config[1])。但当更改与配置的值相矛盾时,会发出警告,因为配置的值将在下次读取索引时生效,这将消除选项的预期效果。

--test-untracked-cache

仅对工作目录执行测试,以确保可以使用未跟踪缓存。如果你真的要使用它,则必须使用 --untracked-cache--force-untracked-cachecore.untrackedCache 配置变量手动启用未跟踪缓存。如果测试失败,退出代码为 1,并且一条消息解释了什么没有按预期工作,否则退出代码为 0 并且会打印 OK。

--force-untracked-cache

--untracked-cache 相同。为了与旧版本的 Git 保持向后兼容性而提供,在旧版本的 Git 中,--untracked-cache 意味着 --test-untracked-cache,但此选项将无条件启用扩展。

--fsmonitor
--no-fsmonitor

启用或禁用文件系统监视器功能。无论 core.fsmonitor 配置变量的值如何(请参阅 git-config[1]),这些选项都会生效。但是,当更改与配置的值相冲突时,会发出警告,因为配置的值将在下次读取索引时生效,这将消除该选项的预期效果。

--

不再将任何参数解释为选项。

<file>

要执行操作的文件。请注意,以 . 开头的文件将被丢弃。这包括 ./filedir/./file。如果您不希望这样,请使用更清晰的名称。相同规则适用于以 / 结尾的目录和包含 // 的路径。

使用 --REFRESH

--refresh 不会计算新的 sha1 文件,也不会针对模式/内容更改更新索引。但它 **确实** 做的是将文件的 stat 信息与索引“重新匹配”,以便您可以刷新索引以查看未更改但 stat 条目过时的文件。

例如,您想要在执行 git read-tree 后执行此操作,以将 stat 索引详细信息与正确的文件关联起来。

使用 --CACHEINFO 或 --INFO-ONLY

--cacheinfo 用于注册当前工作目录中不存在的文件。这对最小检出合并很有用。

要假装您在指定路径上有一个具有指定模式和 sha1 的文件,请执行以下操作

$ git update-index --add --cacheinfo <mode>,<sha1>,<path>

--info-only 用于注册文件而不将其放入对象数据库中。这对只读状态的存储库很有用。

--cacheinfo--info-only 的行为相似:索引会更新,但对象数据库不会更新。--cacheinfo 在对象位于数据库中但文件在本地不可用时很有用。--info-only 在文件可用但您不想更新对象数据库时很有用。

使用 --INDEX-INFO

--index-info 是一种更强大的机制,它允许您从标准输入中输入多个条目定义,并专门为脚本设计。它可以接受三种格式的输入

  1. mode SP type SP sha1 TAB path

    此格式用于将 git ls-tree 输出填充到索引中。

  2. mode SP sha1 SP stage TAB path

    此格式用于将更高阶的阶段放入索引文件中,并与 git ls-files --stage 输出相匹配。

  3. mode SP sha1 TAB path

    此格式不再由任何 Git 命令生成,但 update-index --index-info 现在支持并且将来会继续支持。

要将更高阶的阶段条目放入索引中,应首先通过为该路径提供一个 mode=0 的条目来删除该路径,然后以第三种格式提供必要的输入行。

例如,从以下索引开始

$ git ls-files -s
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 0       frotz

您可以将以下输入提供给 --index-info

$ git update-index --index-info
0 0000000000000000000000000000000000000000	frotz
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1	frotz
100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2	frotz

输入的第一行提供了 0 作为模式来删除该路径;SHA-1 不重要,只要它格式正确即可。然后,第二行和第三行提供了该路径的阶段 1 和阶段 2 条目。在执行上述操作之后,我们将得到以下结果

$ git ls-files -s
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1	frotz
100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2	frotz

使用“假设未更改”位

Git 中的许多操作都依赖于您的文件系统拥有高效的 lstat(2) 实现,以便可以廉价地检查工作树文件的 st_mtime 信息,以查看文件内容是否已从索引文件中记录的版本发生更改。不幸的是,有些文件系统拥有低效的 lstat(2)。如果您的文件系统是其中之一,您可以将“假设未更改”位设置为您未更改的路径,以使 Git 不执行此检查。请注意,在路径上设置此位并不意味着 Git 会检查文件内容以查看它是否已更改——它使 Git 省略任何检查并假设它 **未** 更改。当您更改工作树文件时,您必须通过删除“假设未更改”位来显式地告诉 Git,无论是在修改之前还是之后。

为了设置“假设未更改”位,请使用 --assume-unchanged 选项。要取消设置,请使用 --no-assume-unchanged。要查看哪些文件设置了“假设未更改”位,请使用 git ls-files -v(请参阅 git-ls-files[1])。

该命令会查看 core.ignorestat 配置变量。当此变量为 true 时,使用 git update-index paths... 更新的路径以及使用其他更新索引和工作树的 Git 命令(例如 git apply --indexgit checkout-index -ugit read-tree -u)更新的路径将自动标记为“假设未更改”。请注意,如果 git update-index --refresh 发现工作树文件与索引匹配,则 **不会** 设置“假设未更改”位(如果您想将它们标记为“假设未更改”,请使用 git update-index --really-refresh)。

有时用户会将假设未更改位与跳过工作树位混淆。请参阅下面“跳过工作树位”部分的最后一段,了解这两个位之间的区别。

示例

要仅更新和刷新已检出的文件

$ git checkout-index -n -f -a && git update-index --ignore-missing --refresh
在设置了 core.ignorestat 的低效文件系统上
$ git update-index --really-refresh              (1)
$ git update-index --no-assume-unchanged foo.c   (2)
$ git diff --name-only                           (3)
$ edit foo.c
$ git diff --name-only                           (4)
M foo.c
$ git update-index foo.c                         (5)
$ git diff --name-only                           (6)
$ edit foo.c
$ git diff --name-only                           (7)
$ git update-index --no-assume-unchanged foo.c   (8)
$ git diff --name-only                           (9)
M foo.c
  1. 强制 lstat(2) 为与索引匹配的路径设置“假设未更改”位。

  2. 标记要编辑的路径。

  3. 这将执行 lstat(2) 并发现索引与路径匹配。

  4. 这将执行 lstat(2) 并发现索引 **不** 与路径匹配。

  5. 将新版本注册到索引中会设置“假设未更改”位。

  6. 并且它被认为是未更改的。

  7. 即使您对其进行了编辑。

  8. 您可以在之后告知 Git 关于更改。

  9. 现在,它将使用 lstat(2) 检查并发现它已更改。

跳过工作树位

跳过工作树位可以用一句话(很长)来定义:告诉 git 在合理的情况下避免将文件写入工作目录,并在文件不存在于工作目录中时将其视为未更改。

请注意,并非所有 git 命令都会关注此位,并且有些命令只部分支持它。

与跳过工作树位相关的 update-index 标志和 read-tree 功能早于 git-sparse-checkout[1] 命令的引入,该命令提供了一种更简单的方法来配置和处理跳过工作树位。如果您想将您的工作树缩减为只处理存储库中的部分路径,我们强烈建议您使用 git-sparse-checkout[1] 而不是低级 update-index 和 read-tree 原语。

跳过工作树位的首要目的是启用稀疏检出,即让工作目录只包含部分路径。当设置了跳过工作树位时,Git 命令(例如 switchpullmerge)将避免写入这些文件。但是,这些命令有时会在重要情况下(例如合并或变基期间的冲突)写入这些文件。Git 命令还会避免将这些文件的缺失视为故意删除;例如 git add -u 不会为这些文件暂存删除操作,git commit -a 也不会提交删除这些文件的操作。

虽然此位看起来与假设未更改位类似,但它的目标不同。假设未更改位用于将文件保留在工作树中,但让 Git 省略对其更改的检查并假设文件未更改(尽管如果它可以在不使用 stat 的情况下确定它已更改,它可以自由记录这些更改)。跳过工作树告诉 Git 忽略文件缺失,在可能的情况下避免使用通常更新大部分工作目录的命令(例如 checkoutswitchpull 等)来更新它,并且不将它的缺失记录到提交中。请注意,在稀疏检出(通过 git sparse-checkout 设置或通过将 core.sparseCheckout 配置为 true 设置)中,如果索引中将文件标记为跳过工作树,但它在工作树中被发现,Git 将清除该文件的跳过工作树位。

拆分索引

此模式专为索引非常大的存储库而设计,旨在减少重复写入这些索引所需的时间。

在此模式下,索引被拆分为两个文件:$GIT_DIR/index 和 $GIT_DIR/sharedindex.<SHA-1>。更改累积在 $GIT_DIR/index(拆分索引)中,而共享索引文件包含所有索引条目并保持不变。

当拆分索引中的条目数量达到 splitIndex.maxPercentChange 配置变量(请参阅 git-config[1])指定的级别时,拆分索引中的所有更改都会被推回共享索引文件中。

每次创建新的共享索引文件时,如果旧的共享索引文件的修改时间早于 splitIndex.sharedIndexExpire 配置变量(请参阅 git-config[1])指定的修改时间,则会将其删除。

为了避免删除仍在使用的共享索引文件,每次创建或读取基于共享索引文件的新拆分索引时,都会将它的修改时间更新为当前时间。

未跟踪的缓存

此缓存旨在加快涉及确定未跟踪文件的命令的速度,例如 git status

此功能通过记录工作树目录的 mtime 来实现,然后省略读取目录和针对那些 mtime 未更改的目录中的文件的 stat 调用。为了使此功能正常工作,底层操作系统和文件系统必须在目录中添加、修改或删除文件时更改目录的 st_mtime 字段。

您可以使用 --test-untracked-cache 选项测试文件系统是否支持该功能。--untracked-cache 选项过去在旧版本的 Git 中隐式执行该测试,但现在不再是这样。

如果您想启用(或禁用)此功能,使用 core.untrackedCache 配置变量(请参阅 git-config[1])比在每个存储库中使用 --untracked-cache 选项来运行 git update-index 更容易,尤其是在您想在所有使用的存储库中执行此操作时,因为您可以在 $HOME/.gitconfig 中将配置变量设置为 true(或 false)一次,它就会影响您访问的所有存储库。

core.untrackedCache 配置变量发生更改时,下次命令读取索引时,未跟踪的缓存将被添加到索引中或从索引中删除;而当使用 --[no-|force-]untracked-cache 时,未跟踪的缓存会立即被添加到索引中或从索引中删除。

在 2.17 之前,未跟踪的缓存存在一个错误,即用指向另一个目录的符号链接替换目录会导致它错误地将 Git 跟踪的文件显示为未跟踪的文件。请参阅 git.git 中的“status: add a failing test showing a core.untrackedCache bug”提交。对此的解决方法是(这可能适用于将来的其他未发现的错误)

$ git -c core.untrackedCache=false status

此错误也被证明会影响将目录替换为文件的非符号链接情况,涉及未跟踪缓存的内部结构,但尚未报告任何导致“git status”输出错误的情况。

还有一些情况,即在 2.17 之前的 Git 版本中写入的现有索引将引用不再存在的目录,这可能会导致“git status”上出现许多“could not open directory”警告。这些是针对以前被静默丢弃的现有问题的新的警告。

与上面描述的错误一样,解决方法是一次性使用 core.untrackedCache=false 运行“git status”来清除遗留的错误数据。

文件系统监控

此功能旨在加快具有大型工作目录的仓库的 Git 操作。

它使 Git 能够与文件系统监控器协同工作(参见 git-fsmonitor--daemon[1]githooks[5] 中的“fsmonitor-watchman”部分),监控器可以告知 Git 哪些文件已修改。这使 Git 能够避免必须对每个文件执行 lstat() 操作来查找已修改的文件。

当与未跟踪缓存一起使用时,它可以通过避免扫描整个工作目录以查找新文件的成本,进一步提高性能。

如果要启用(或禁用)此功能,使用 core.fsmonitor 配置变量(参见 git-config[1])比在每个仓库中使用 --fsmonitor 选项来 git update-index 更容易,特别是如果希望在所有使用的仓库中执行此操作,因为可以将配置变量在您的 $HOME/.gitconfig 中设置一次,并使其影响您接触的所有仓库。

当更改 core.fsmonitor 配置变量时,文件系统监控器将在下次命令读取索引时添加到索引或从索引中删除。当使用 --[no-]fsmonitor 时,文件系统监控器会立即添加到索引或从索引中删除。

配置

该命令遵守 core.filemode 配置变量。如果仓库位于其可执行位不可靠的文件系统上,则应将其设置为 false(参见 git-config[1])。这会导致命令忽略索引中记录的文件模式与文件系统上的文件模式之间的差异,如果它们仅在可执行位上有所不同。在这样的不幸的文件系统上,您可能需要使用 git update-index --chmod=

类似地,如果 core.symlinks 配置变量设置为 false(参见 git-config[1]),符号链接将作为普通文件检出,并且此命令不会将记录的文件模式从符号链接修改为普通文件。

该命令查看 core.ignorestat 配置变量。请参见上面的“使用“假设未更改”位”部分。

该命令还查看 core.trustctime 配置变量。当 inode 更改时间定期被 Git 之外的某些内容修改时(文件系统爬虫和备份系统使用 ctime 标记已处理的文件),这将很有用(参见 git-config[1])。

未跟踪缓存扩展可以通过 core.untrackedCache 配置变量启用(参见 git-config[1])。

备注

用户通常尝试使用 assume-unchanged 和 skip-worktree 位告诉 Git 忽略对已跟踪文件的更改。这不会按预期工作,因为 Git 仍然可能在执行某些操作时检查工作树文件与索引。通常,Git 不提供忽略对已跟踪文件更改的方法,因此建议使用其他解决方案。

例如,如果您要更改的文件是某种配置文件,则仓库可以包含一个示例配置文件,然后可以将其复制到忽略的名称中并进行修改。仓库甚至可以包含一个脚本,将示例文件视为模板,自动对其进行修改和复制。

Git

git[1] 套件的一部分

scroll-to-top