В файловой системе 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 */
};
Кажется, что изначально 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)
Это оставило файл в состоянии, которое было изменено, но не обнаружено lstat.
Чтобы исправить эту проблему, теперь в таких ситуациях, когда состояние lstat неоднозначно, Git сравнивает содержимое файлов, чтобы определить, было ли оно изменено.
Примечание:
Если кто-то запутался, как я, по поводу st_mtime description , в котором говорится, что оно обновляется записью «больше нуля байтов», это означает absolute изменить.
Например, в случае файла текстового файла с одним символом A
: если A
изменяется на B
, то общий размер байта изменяется на 0, но st_mtime все равно будет обновляться ( пришлось проверить это самому, чтобы проверить, используйте ls -l
, чтобы увидеть метку времени).