git 是否有内置方法*来检查工作目录中的文件是否神奇地**发生了变化***?
如果是这样:如何让 git 检查工作目录的完整性?
* 确定工作目录中哪些文件被跟踪、仅对它们进行哈希处理、删除它们、再次检出它们、再次对它们进行哈希处理并比较哈希值,这并不完全算作“内置”。
** 文件的内容因为宇宙射线撞击 HDD、独角兽在盘子上奔跑或其他不让 FS 知道发生变化的方式(例如编辑字符设备)而发生变化。
*** 在名称、内容或其他跟踪的属性中(如神奇地变为可执行)。
请注意,这个问题是另一个问题。回答这个问题(你目前正在阅读的那个)比较容易。如果这个问题解决了,我会在另一个问题中链接到这个问题,并指出另一个问题中这个问题下面的答案尚未解决的部分。
有人问,git status
和 我所要求的 之间有什么区别。git status
仅当 FS 告知它发生了更改时,它才会注意到更改。 如果文件被意外损坏,FS 不知道,因此git status
不会指示更改。当然git diff
, 、 等也不会。git add --all
响应使用建议git fsck
:它不起作用。
我做了什么:
christoph@christoph-laptop-16-04-2:/t$ dd if=/dev/zero bs=1M count=30 of=/tmp/con
30+0 records in
30+0 records out
31457280 bytes (31 MB, 30 MiB) copied, 0.0143967 s, 2.2 GB/s
christoph@christoph-laptop-16-04-2:/t$ mkfs.ext4 /tmp/con
mke2fs 1.42.13 (17-May-2015)
Discarding device blocks: done
Creating filesystem with 30720 1k blocks and 7680 inodes
Filesystem UUID: 9865efe8-fb30-42ab-ace7-a8f88330bdfd
Superblock backups stored on blocks:
8193, 24577
Allocating group tables: done
Writing inode tables: done
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done
christoph@christoph-laptop-16-04-2:/t$ sudo mount -t ext4 -o loop /tmp/con /mnt
[sudo] password for christoph:
christoph@christoph-laptop-16-04-2:/t$ cd /mnt
christoph@christoph-laptop-16-04-2:/mnt$ sudo chown christoph .
christoph@christoph-laptop-16-04-2:/mnt$ git init
Initialized empty Git repository in /mnt/.git/
christoph@christoph-laptop-16-04-2:/mnt$ echo "some contents" > file
christoph@christoph-laptop-16-04-2:/mnt$ git add file
christoph@christoph-laptop-16-04-2:/mnt$ git commit -m "a"
[master (root-commit) d29fbd5] a
1 file changed, 1 insertion(+)
create mode 100644 file
christoph@christoph-laptop-16-04-2:/mnt$ git status
On branch master
nothing to commit, working directory clean
christoph@christoph-laptop-16-04-2:/mnt$ cd ~
christoph@christoph-laptop-16-04-2:~$ sudo umount /mnt
此时,我打开/tmp/con
我最喜欢的十六进制编辑器,搜索单词“contents”,并将结尾的“s”换成“z”。
christoph@christoph-laptop-16-04-2:~$ sudo mount -t ext4 -o loop /tmp/con /mnt
christoph@christoph-laptop-16-04-2:~$ cd /mnt
christoph@christoph-laptop-16-04-2:/mnt$ git status
On branch master
nothing to commit, working directory clean
christoph@christoph-laptop-16-04-2:/mnt$ cat file
some contentz
christoph@christoph-laptop-16-04-2:/mnt$ git fsck
Checking object directories: 100% (256/256), done.
christoph@christoph-laptop-16-04-2:/mnt$ git status
On branch master
nothing to commit, working directory clean
christoph@christoph-laptop-16-04-2:/mnt$ cat file
some contentz
有人提议修改工作目录中的所有文件。更改它们的访问日期不会有太大问题,但这不会使 git 重新检查文件。更改它们的修改日期实际上确实会使 git 再次检查这些文件,但是,这还会引起其他麻烦:备份应用程序会再次备份文件。对于大型存储库,这可能是一个问题。
答案1
我正在阅读另一个问题的答案,关于如何让 git 确认你的新行尾偏好在 github 上,其中包括这颗宝石:
删除索引并强制 Git 重新扫描工作目录。
rm .git/index
重写 Git 索引以获取所有新的行尾。
git reset
显示重写的、规范化的文件。
git status
它建议保存您当前的状态,以防您还有其他关心的、可能相关的信息。
特别是因为 git reset 步骤将重写文件。
答案2
这个答案说:
Git 尽力仅从 lstat() 值来确信工作树与索引匹配,因为依赖文件内容的代价非常高昂。
换句话说,逐字节比较文件将花费相当长的时间,因此 git 尝试通过比较lstat
首先是功能。这包括文件大小和修改时间。如果这些没有改变,git 会假定文件没有被修改。正如您所证明的,这不是一种万无一失的方法,但它适用于 git 旨在处理的情况。
更改返回的任何值lstat
都会使 git 重新检查文件是否进行修改:
$ touch file
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: file
no changes added to commit (use "git add" and/or "git commit -a")