这是关于内部的git.
我一直在阅读伟大的'Pro Git'一书,并学习一下git如何在内部工作(所有关于SHA1,blob,引用,tress,提交等等).顺便说一句,相当聪明的建筑.
因此,为了放入上下文,git将文件的内容引用为SHA1值,因此只需比较哈希值就能知道特定内容是否已更改.但我的问题是git如何检查工作树中的内容是否发生了变化.
天真的方法是认为,每次运行命令git status或类似命令时,它都会搜索工作目录中的所有文件,计算SHA1并将其与最后一次提交的文件进行比较.但对于大型项目来说,这似乎是非常低效的,就像Linux内核一样.
另一个想法可能是检查文件的最后修改日期,但我认为git不存储该信息(当您克隆存储库时,所有文件都有新的时间)
我确信它是以有效的方式进行的(git非常快),有人如何实现这一目标?
PD:只是添加一个关于git索引的有趣链接,特别声明索引保存有关文件时间戳的信息,即使树对象没有.
Jos*_*Lee 34
Git的索引维护git最后一次将每个文件写入工作树的时间戳(并在文件从工作树或提交中缓存时更新这些时间戳).您可以看到元数据git ls-files --debug.除了时间戳,它还会记录lstat的大小,inode和其他信息,以减少误报的可能性.
当您执行git-status时,它只是在工作树中的每个文件上调用lstat并比较元数据以便快速确定哪些文件不变.这在racy-git和update-index下的文档中有所描述.
bco*_*rso 10
在unix文件系统上,跟踪文件信息并使用lstat方法进行加密.该stat结构包含多个时间戳,大小信息,以及更多:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
Run Code Online (Sandbox Code Playgroud)
看起来Git最初只是依靠这种统计结构来决定文件是否已被更改(参见参考资料):
检查它们是否不同时,Git首先运行
lstat(2)文件并将结果与此信息进行比较
但是,报告了一个竞争条件(racy-git),它发现文件是否按以下方式修改:
: modify 'foo'
$ git update-index 'foo'
: modify 'foo' again, in-place, without changing its size
(And quickly enough to not change it's timestamps)
Run Code Online (Sandbox Code Playgroud)
这使文件处于已修改但lstat无法检测到的状态.
为了解决这个问题,现在在lstat状态不明确的情况下,Git会比较文件的内容以确定它是否已被更改.
注意:
如果有人像我一样感到困惑,关于st_mtime描述,它表明它是通过"超过零字节"的写入来更新的,这意味着绝对的改变.
例如,对于具有单个字符的文本文件文件A:如果A更改为B总字节大小有0个净更改,但st_mtime仍将更新(必须自己尝试验证,用于ls -l查看时间戳) ).