qinghuan
← 回到知识探索

计算机趣闻 / 趣味知识

只改一个空格,Git 是怎么发现的?

从内容摘要、暂存区和比较对象三步,理解 Git 眼中的文件变化。

展开本文目录
  1. 内容有摘要,文件名另有记录
  2. “改了”必须先说是和谁比较
  3. 不必每次都从头检查所有字节
  4. 看起来一样,也要检查换行和处理规则
  5. 记住这三点
  6. 别把例子用过头
  7. 自己试一小步
  8. 查原始资料
  9. 找一份资料继续练
开始前,会这些就够了
  • 用过 git add 和 git status
  • 知道文件内容与文件名不同
遇到不熟悉的词,先看这 3 个解释
哈希
哈希用规定的计算方法,把输入数据变成便于比较的结果;常见摘要算法会输出固定长度。同样的输入得到同样的结果,但不同输入仍可能得到相同结果。
磁盘
日常使用中的磁盘通常指保存系统、应用和文件的硬盘类设备,包括机械硬盘和固态硬盘。与普通运行内存不同,它们不需要持续供电来维持已经写入的数据。
Git暂存区
暂存区记录你准备放进下一次提交的文件内容。把修改加入暂存区后,可以先检查这次准备提交的内容;继续编辑文件时,新修改不会自动替换已经暂存的版本。
打开完整术语小抄 ↗

一个文件有几千行,你只加了一个空格,Git 就把它列为已修改。可你又发现,改完再改回去,修改提示会消失。Git 不是在旁边记录每次键盘操作;它关心的是当前状态与某个已保存状态之间有什么差别。

内容有摘要,文件名另有记录

Git 把文件内容保存为数据对象,通常叫 blob,并根据对象内容和类型、长度等头部信息计算对象编号。相同字节内容在同一种对象格式下可复用同一个 blob。它不是只取文件名当编号,也不是把文件最后修改时间当成内容本身。

那文件名去了哪里?目录树对象记录名字、文件模式以及它指向的内容对象或子目录。提交对象再连接一次目录快照和历史信息。把内容与名字分开,就能解释为什么两条不同路径可以引用相同内容,也能解释文件内容未变时,改名仍属于项目状态变化。

“改了”必须先说是和谁比较

日常最重要的三处状态,是正在编辑的工作区、为下一次提交准备的暂存区,以及已经保存的提交。假设原文件写着 blue,你改成 green 后执行 git add,再改成 red。此时暂存区保留的是 green,工作区则是 red,不会因为继续编辑就自动同步暂存区。

所以这个文件可能同时出现在已暂存与未暂存改动里。普通 git diff 主要比较工作区和暂存区;git diff --cached 比较暂存区和已提交状态。两者都没有显示某段变化时,应先检查自己选的比较对象,而不是立刻认定 Git 漏记了编辑过程。

不必每次都从头检查所有字节

文件很多时,完整读取所有内容会花时间。Git 的索引除了记录内容对象,还会保存文件状态信息,并可利用文件系统提供的时间、大小等信息以及其他机制减少不必要的检查。这些是帮助筛选的线索,不能简单理解为“修改时间变了就一定有内容改动”。

当需要确认内容时,Git 会按相关规则比较它。你把一个已跟踪文件改了又完整改回原样,最终可能不再有内容差异,即使文件曾经被写过。屏幕上的红绿行则是把两份内容作差异展示的结果,不是仓库逐个保存了你打字、删除、撤销的动作录像。

看起来一样,也要检查换行和处理规则

空格、末尾换行和不同换行表示都可能影响字节内容。但 Git 又能按属性和配置把文本换行统一后保存,因此工作区的原始字节与仓库保存的字节未必完全相同。看到整篇都变红时,先检查是否换行格式或编码改变,比重新手工复制所有文字更有效。

理解机制后,可以养成一个简单习惯:提交前分别查看未暂存差异和已暂存差异,确认这次真正准备保存的内容。识别改动也不等于自动备份所有编辑;尚未保存到 Git 对象或提交中的内容不能靠“Git 应该看见过”来保证找回。

记住这三点

  • Git 主要比较状态,内容对象与文件名、目录结构分别保存。
  • 暂存之后再编辑,会形成新的未暂存差异;提交准备的是暂存区内容。
  • 时间和大小可帮助加速检查,换行与过滤规则也会影响内容表示。

别把例子用过头

  • 本文没有把对象编号说成任意内容绝对不碰撞的数学保证。
  • git diff 没输出,不等于工作区、暂存区与历史在所有方面都一致。
  • 这里讨论常见已跟踪普通文件;子模块、特殊索引标记等需要另看规则。

自己试一小步

怎样让同一个练习文件同时拥有已暂存和未暂存的修改?

  1. 在单独的练习仓库中,使用一个已经提交过的普通文本文件,不在工作项目上试验。
  2. 分两次修改不同文字,只在两次修改之间暂存该文件。
  3. 分别阅读 git status、git diff 和 git diff --cached,记录每条命令正在比较哪两处状态。

做到这些,就算完成

  • 能够指出下一次普通提交会包含哪个版本。
  • 解释时用工作区、暂存区、提交三处状态,而不是只说“旧文件”和“新文件”。
  • 只修改练习文件,不需要强制重置、清理目录或推送远端。

查原始资料

想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。

找一份资料继续练

先选一项,按下面的范围继续学;不必从头读完整门课程。