git使用什么算法来检测工作树上的更改?
这是关于git使用什么算法来检测工作树上的更改?,git,Git,这是关于git的内部内容 我一直在阅读这本好书,并了解了一些git如何在内部工作(所有关于SHA1、BLOB、引用、树、提交等)。顺便说一句,这是一个相当聪明的建筑 因此,在上下文中,git将文件的内容引用为SHA1值,因此它能够通过比较哈希值来知道特定内容是否发生了更改。但我的问题是关于git如何检查工作树中的内容是否已更改 天真的方法会认为,每次以git status或类似命令的形式运行命令时,它都会搜索工作目录中的所有文件,计算SHA1并将其与上次提交的文件进行比较。但对于大型项目来说,这
git
的内部内容
我一直在阅读这本好书,并了解了一些git如何在内部工作(所有关于SHA1、BLOB、引用、树、提交等)。顺便说一句,这是一个相当聪明的建筑
因此,在上下文中,git将文件的内容引用为SHA1值,因此它能够通过比较哈希值来知道特定内容是否发生了更改。但我的问题是关于git如何检查工作树中的内容是否已更改
天真的方法会认为,每次以git status
或类似命令的形式运行命令时,它都会搜索工作目录中的所有文件,计算SHA1并将其与上次提交的文件进行比较。但对于大型项目来说,这似乎效率很低,比如Linux内核
另一个想法是检查文件的最后修改日期,但我认为git没有存储该信息(当您克隆存储库时,所有文件都有一个新的时间)
我确信它是以一种高效的方式实现的(git真的很快),有人知道这是如何实现的吗
PD:只是想添加一个关于git索引的有趣内容,特别指出索引保留了关于文件时间戳的信息,即使树对象没有 Git的索引维护Git上次将每个文件写入工作树的时间戳(并在从工作树或提交缓存文件时更新这些时间戳)。您可以通过git ls文件--debug查看元数据。除了时间戳之外,它还记录来自的大小、inode和其他信息,以减少误报的机会
当您执行git status时,它只需调用工作树中的每个文件并比较元数据,以便快速确定哪些文件没有更改。这在和下的文档中有描述。Git的索引维护Git上次将每个文件写入工作树的时间戳(并在从工作树或提交缓存文件时更新这些时间戳)。您可以通过git ls文件--debug查看元数据。除了时间戳之外,它还记录来自的大小、inode和其他信息,以减少误报的机会
当您执行git status时,它只需调用工作树中的每个文件并比较元数据,以便快速确定哪些文件没有更改。这在和下的文档中有描述。在unix文件系统上,文件信息会被跟踪,并可以使用方法进行访问。包含多个时间戳、大小信息等:
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 */
};
看起来最初Git只是依靠这个来决定文件是否被更改了():
在检查它们是否不同时,Git首先对文件运行lstat(2)
,并将结果与此信息进行比较
但是,报告了一个竞态条件(),该竞态条件发现文件是否以以下方式修改:
: modify 'foo'
$ git update-index 'foo'
: modify 'foo' again, in-place, without changing its size
(And quickly enough to not change it's timestamps)
这使文件处于已修改但无法被lstat检测到的状态
为了解决这个问题,现在在lstat状态不明确的情况下,Git比较文件的内容以确定它是否已被更改
注意: 如果有人像我一样困惑于,它是通过写入“超过零字节”来更新的,这意味着绝对更改
例如,在使用单个字符的文本文件
a
的情况下:如果a
更改为B
,则总字节大小的净变化为0,但st_mtime仍将更新(必须亲自尝试验证,使用ls-l
查看时间戳)。在unix文件系统上,文件信息被跟踪,可以使用方法访问。包含多个时间戳、大小信息等:
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 */
};
看起来最初Git只是依靠这个来决定文件是否被更改了():
在检查它们是否不同时,Git首先对文件运行lstat(2)
,并将结果与此信息进行比较
但是,报告了一个竞态条件(),该竞态条件发现文件是否以以下方式修改:
: modify 'foo'
$ git update-index 'foo'
: modify 'foo' again, in-place, without changing its size
(And quickly enough to not change it's timestamps)
这使文件处于已修改但无法被lstat检测到的状态
为了解决这个问题,现在在lstat状态不明确的情况下,Git比较文件的内容以确定它是否已被更改
注意: 如果有人像我一样困惑于,它是通过写入“超过零字节”来更新的,这意味着绝对更改 例如,对于一个只有单个字符的文本文件
a
:如果a
更改为B
,则总字节大小的净变化为0,但st_mtime仍将更新(必须亲自尝试验证,使用ls-l
查看时间戳).刚才我发现这个链接有一些额外的信息。谢谢刚才我发现这个链接有一些额外的信息。谢谢见:见: