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
查看时间戳).

刚才我发现这个链接有一些额外的信息。谢谢刚才我发现这个链接有一些额外的信息。谢谢见:见: