首页 > 解决方案 > git status 是否真的计算并检查整个工作目录内容的 SHA?

问题描述

当我使用一些工具(例如HashCalc)对某个文件进行SHA1计算时,如果文件稍微大一点(例如1GB或更多),则需要一些时间。但是,如果我在 5GB 或更大大小的存储库上运行 git status,似乎 git status 检查文件的更改不超过几秒钟。

现在,问题是 git status 是否真的计算并检查文件的 SHA,或者它只是将文件最后修改的时间和日期与索引中的记录进行比较?

标签: gitsha

解决方案


git status命令不计算任何散列。1

什么git status是:

  • 打印有关当前分支的信息,这涉及读取HEAD文件,可能还有一些小文件;
  • 比较(如git diff --name-statusHEAD提交中的每个文件与索引中的每个文件;和
  • 比较(如git diff --name-status)索引中的每个文件与工作树中的每个文件。

git status显示要提交的更改和未暂存以进行提交的更改的输出部分只是两个git diff --name-status-es 结果的重新格式化版本。

这两个相对较大的git diffs可能需要很长时间,但它们不会。那有两个不同的原因:

  1. 使用--name-status,比较两个提交,或者一个提交和索引,可以非常快,因为提交的每个文件都是通过 Git 称为树对象的东西存储的,并且索引具有非常像扁平系列的形式树对象。提交中的文件和索引中的文件都具有预先计算的哈希值。差异操作可以只比较哈希来找出文件是否不同。(文件的存在与否决定了添加删除的状态。重命名检测,如果必须运行,可能会很慢。)

  2. 使用--name-status,索引和您的工作树的比较可以非常快,因为索引缓存了有关您的工作树的信息。2 对于缓存数据有效的每个文件,Git 不必查看工作树文件内部。对于缓存数据无效的文件,Git 有时可以立即知道文件的工作树副本与索引副本不匹配。这通常只留下一些棘手的情况,Git 确实必须验证工作树副本是否匹配索引副本。


1从技术上讲,索引中有一个一致性检查哈希,它确实读取了索引,所以只有一个哈希。但这是针对index的,它不是您可以提交的文件。

2这里的主要速度瓶颈是您的操作系统执行lstat系统调用的速度。或者至少,那应该是它所在的位置;某些版本的 Git 在某些极端情况下不小心引入了一些二次行为。如果 lstat 调用慢,您可以使用 禁用特定文件git update-index --assume-unchanged,尽管这意味着 Git 只是假设文件没有更改。这个“skip slow lstat”是它最初的目的。无论如何,Git 都可以统计文件,这就是为什么--skip-worktree建议隐藏工作树更改的原因。


推荐阅读