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 master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: a.c
Changes 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.c
Untracked files:
(use "git add <file>..." to include in what will be committed)
b.c
Ignored files:
(use "git add -f <file>..." to include in what will be committed)
a.o