简体中文 ▾ 主题 ▾ 最新版本 ▾ git-update-index 最后更新于 2.52.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>…​]

描述

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

另请参阅 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

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

--assume-unchanged
--no-assume-unchanged

指定此标志时,路径记录的对象名称不会更新。相反,此选项会设置/取消路径的“假定未改变 (assume unchanged)”位。当该位开启时,用户承诺不更改文件,并允许 Git 假定工作树文件与索引中记录的一致。如果你想更改工作树文件,则需要取消该位来告诉 Git。这在处理大型项目且文件系统 lstat(2) 系统调用非常慢(例如 cifs)时有时很有用。

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

--really-refresh

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

--skip-worktree
--no-skip-worktree

指定这些标志之一时,路径记录的对象名称不会更新。相反,这些选项会设置和取消路径的“skip-worktree”位。有关更多信息,请参阅下面的“Skip-worktree bit”部分。

--ignore-skip-worktree-entries
--no-ignore-skip-worktree-entries

即使指定了 --remove 选项,也不要移除 skip-worktree(又称“仅索引”)条目。

--fsmonitor-valid
--no-fsmonitor-valid

指定这些标志之一时,路径记录的对象名称不会更新。相反,这些选项会设置和取消路径的“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 版本起支持它,libgit2 在 2016 年添加了支持,JGit 在 2020 年添加了支持。旧版本的手册页称其为“相对年轻”,但如今它应被视为成熟技术。

--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 向后兼容,在旧版本中 --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 OR --INFO-ONLY

--cacheinfo 用于注册不在当前工作目录中的文件。这对于最小化检出 (minimum-checkout) 合并非常有用。

要假装在路径 path 处有一个具有指定 mode 和 sha1 的文件,请输入:

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

--info-only 用于注册文件而不将其放入对象数据库中。这对于仅限状态 (status-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

    此格式用于将更高阶的暂存级 (stage) 放入索引文件,并匹配 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 只要格式正确就不重要。然后第二行和第三行馈送该路径的 stage 1 和 stage 2 条目。完成上述操作后,我们将得到:

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

使用 “ASSUME UNCHANGED” 位

Git 中的许多操作取决于你的文件系统是否具有高效的 lstat(2) 实现,以便可以廉价地检查工作树文件的 st_mtime 信息,以查看文件内容是否已从索引文件中记录的版本发生更改。不幸的是,某些文件系统的 lstat(2) 效率低下。如果你的文件系统是其中之一,你可以对尚未更改的路径设置“假定未改变 (assume unchanged)”位,使 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)。

有时用户会将 assume-unchanged 位与 skip-worktree 位混淆。请参阅下面“Skip-worktree 位”部分的最后一段以了解区别。

示例

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

$ 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. 事后你可以告知更改。

  9. 现在它通过 lstat(2) 检查并发现它已被更改。

SKIP-WORKTREE 位

Skip-worktree 位可以用一句话定义:告诉 git 在合理可能的情况下避免将文件写入工作目录,并在文件不在工作目录中时将其视为未更改。

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

与 skip-worktree 位相关的 update-index 标志和 read-tree 功能早于 git-sparse-checkout[1] 命令的引入,后者提供了一种更简单的方法来配置和处理 skip-worktree 位。如果你想缩减工作树以仅处理仓库中文件的子集,我们强烈建议使用 git-sparse-checkout[1],而不是低级的 update-index 和 read-tree 原语。

skip-worktree 位的主要目的是启用稀疏检出 (sparse checkouts),即让工作目录仅存在部分路径。当设置了 skip-worktree 位时,Git 命令(如 switchpullmerge)将避免写入这些文件。然而,在某些重要情况下,如合并或变基期间的冲突,这些命令有时仍会写入这些文件。Git 命令还会避免将此类文件的缺失视为有意删除;例如 git add -u 不会为这些文件暂存删除,git commit -a 也不会提交删除它们的操作。

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

拆分索引 (SPLIT INDEX)

此模式专为具有超大索引的仓库设计,旨在减少重复写入这些索引所需的时间。

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

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

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

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

未追踪缓存 (UNTRACKED CACHE)

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

此功能通过记录工作树目录的 mtime 来工作,然后省略读取目录以及对 mtime 未发生更改的目录中的文件执行 stat 调用。为此,如果目录中的文件被添加、修改或删除,底层操作系统和文件系统必须更改目录的 st_mtime 字段。

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

如果你想启用(或禁用)此功能,使用 core.untrackedCache 配置变量(参见 git-config[1])比在每个仓库中使用 git update-index--untracked-cache 选项更容易,尤其是如果你想在你使用的所有仓库中都这样做,因为你只需在 $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" 以清除残留的错误数据。

文件系统监视器 (FILE SYSTEM MONITOR)

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

它使 git 能够与文件系统监视器(参见 git-fsmonitor--daemon[1]githooks[5] 的“fsmonitor-watchman”部分)协同工作,后者可以告知 git 哪些文件已被修改。这使 git 能够避免通过 lstat() 每个文件来查找修改过的文件。

当与未追踪缓存结合使用时,它可以避免扫描整个工作目录寻找新文件的开销,从而进一步提高性能。

如果你想启用(或禁用)此功能,使用 core.fsmonitor 配置变量(参见 git-config[1])比在每个仓库中使用 git update-index--fsmonitor 选项更容易,尤其是如果你想在你使用的所有仓库中都这样做,因为你只需在 $HOME/.gitconfig 中设置一次配置变量,即可影响你涉及的所有仓库。

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

配置

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

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

该命令会查看 core.ignorestat 配置变量。请参阅上面的“使用 'assume unchanged' 位”部分。

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

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

注意事项

用户经常尝试使用 assume-unchanged 和 skip-worktree 位来告诉 Git 忽略对已追踪文件的更改。这并不能达到预期效果,因为 Git 在执行某些操作时仍可能根据索引检查工作树文件。通常,Git 不提供忽略已追踪文件更改的方法,因此建议采用替代解决方案。

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

GIT

Git[1] 套件的一部分