Git 如何监控文件变更
Table of Contents
内容主要来自引文1,该文提供了更为详实的说明和性能对比实例。
git status 如何监控文件变更
Git 仓库包含三块区域,已提交内容(Repository),暂存区(Index, Staging Directory)以及工作目录(Worktree, Working Directory)。
在 worktree 中文件按是否被 Git 追踪,分为 tracked 和 untracked
文件;对于 untracked 文件,可能存在被
.gitignore 定义忽略的文件;对于 tracked
文件,它可能存在三个版本,已提交的版本,修改并提交到暂存区的版本,worktree
中的版本。
Staged changes
Tracked
文件已提交部分(commit)与被提交到暂存区(index)的部分使用 Git
的内部数据结构存储,这部分的差异内容一般称为 *staged
changes*,对应执行 git status 时看到的
Changes to be committed.
这些数据结构针对内容比较设计,这部分的差异比较性能较高。
Unstaged changes
Tracked 文件在 index 区与 worktree 中版本的对比性能相对低下,理论上需要遍历每个 tracked 文件,计算对应文件在 worktree 中当前内容的 hash,与 index 中存储的 hash 对比,判断是否一致,不一致则认为对应文件存在 unstaged changes.
对于一个大型仓库,tracked 文件数量极大,这个过程性能比较低下,Git 从早期版本开始就引入对这个过程的优化,目前主要有三个优化:
-
lstat()优化2在 Git 较早版本就引入了,它通过文件的最近修改时间(last modification time, mtime) 判断文件是否改变,通过lstat()系统调用可以获取文件的修改时间;如果 mtime 未改变,Git 认为文件内容未改变,如果 mtime 改变,仍要进行 hash 计算;这个优化大大减少需要执行的计算量,不过它仍需要遍历每个 tracked 文件,针对它们执行lstat() -
preload优化3是在lstat()基础上做的改进,充分利用多核,开启多个线程对于文件系统进行并发遍历 -
FSMonitor(core.fsmonitor) 最终引入一个对于文件系统监控的后台进程,它监控、记录来自操作系统包括创建、删除和修改在哪的文件系统事件,Git 在执行如git status命令时会通过它获取这些事件用于优化查找变化文件的过程
Untracked files
对于 untracked 文件的发现,理论上需要
- 遍历得到 worktree 中所有的文件路径
- 对于每个路径,判断其在 index 中是否存在,忽略掉存在的文件(即 tracked file)
-
对于剩下的路径,执行
.gitignore检测,只保留未 ignore 的 - 最终剩下的就是 untracked file
由于目录是一类特殊文件,它的内容是
(filename, i-node)
元组的集合,当元组发生改变,也即目录下文件存在新增、移除、重命名,目录的
mtime (last modification time)将发生改变4,因此 untracked file 可以缓存所有目录的 untracked
文件计算结果来节省大量的目录读取操作。这个优化也即
core.untrackedcache 特性。另外,
FSMonitor 优化开启后,也会被用于优化此项操作。
git status 执行结果示例
可以通过 git status 查看仓库当前的状态,比如下面
git status --ignored
的执行结果:
On branch masterChanges to be committed:(use "git restore --staged <file>..." to unstage)modified: a.cChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)modified: a.cUntracked files:(use "git add <file>..." to include in what will be committed)b.cIgnored files:(use "git add -f <file>..." to include in what will be committed)a.o