索引有三个名称:“索引”(您在此处使用的那个)、暂存区域(在某种意义上更好,因为它描述了它的功能)和缓存。这是适用于此的姓氏。
是什么使索引成为索引或缓存,而不仅仅是一个暂存区,它索引并缓存了工作树的内容。缓存的目的是加快速度。但是缓存总是有一个问题:在某些时候,缓存中的部分或全部数据变得无效。缓存提供对真实、实际、正确数据的快速/快捷访问,不再反映现实。缓存必须被丢弃或重新填充正确的数据。
现在,Git 的索引保存了工作树中的文件副本,或者至少当时存在git checkout
于工作树中。1 如果您以某种方式更改了文件,Git 如何知道缓存的副本无效?
Git 的答案是与缓存副本一起存储有关stat
该文件的一些信息,包括文件的大小和您观察到的两个时间戳。如果你以某种方式修改文件——即使只是改变它的模式,它不会触及文件的内容(所以大小和 mtime 保持不变)——ctime 时间戳将被更新,Git 会知道某些东西已经改变了。当然如果你修改了内容或者改变了大小,Git 也会知道的。
1从技术上讲,索引保存文件的干净副本,准备提交。如果您有行尾设置和/或涂抹和/或清洁过滤器,则清洁后的副本实际上可能与工作树副本不匹配。
你注意到:
当文件被签出时,它不使用 mtime [这里未完成的想法]
我认为您观察到的是 Git 的其他优化之一。如果您git checkout <commit-specifier>
在空的情况下运行(例如,克隆操作的第一次签出),Git 必须第一次完全填充索引和工作树。但是,一旦你这样做了,如果你现在运行不同 git checkout
的代码来签出其他提交,Git 可以优化签出:
- 索引包含当前提交的所有文件,存储在工作树中。
- 您想要签出的新提交有许多与当前提交 100% 相同的文件。
- 因此,Git 只需要替换索引和工作树中的不同文件。
结果,工作树中两次提交之间相同的文件的 mtime 保持不变,因为这些文件根本没有被触及。
这只是缓存进行缓存的另一个方面。但是,它确实发挥了切换分支的能力,同时在索引和/或工作树中进行了一些修改。有关详细信息,请参阅在当前分支上有未提交的更改时签出另一个分支。