有人可以解释一下 git 是如何在内部知道文件 X、Y 和 Z 已更改的吗?识别文件尚未添加或已修改的幕后过程是什么?我之所以问是因为,使用 Subversion 很容易发现它通过在每个文件夹下都有一个目录来跟踪这些事情.svn
,但是对于 git,我似乎无法找到对其内部工作的描述。我怀疑它会扫描所有子目录以进行更改,因为它非常快。
那么,如果出于好奇,它的内部工作原理是什么?
有人可以解释一下 git 是如何在内部知道文件 X、Y 和 Z 已更改的吗?识别文件尚未添加或已修改的幕后过程是什么?我之所以问是因为,使用 Subversion 很容易发现它通过在每个文件夹下都有一个目录来跟踪这些事情.svn
,但是对于 git,我似乎无法找到对其内部工作的描述。我怀疑它会扫描所有子目录以进行更改,因为它非常快。
那么,如果出于好奇,它的内部工作原理是什么?
确定文件状态的机制相当简单。要知道哪些文件已暂存,只需将HEAD
树与索引进行比较。仅出现在索引中的任何项目都已暂存以供添加,任何仅出现在索引中的项目HEAD
已被删除,并且任何不同的项目已暂存。
类似地,可以通过将索引与工作目录进行比较来检测未暂存的更改。
您的问题特别询问这怎么会如此之快(毕竟,计算文件的 SHA1 散列并不是很快。)这就是索引 - 也称为缓存- 再次发挥作用的地方。该索引还具有文件大小和文件修改时间字段。因此,可以简单地stat(2)
在磁盘上创建一个文件,并与索引的文件大小和文件修改时间进行比较,以了解是否对文件进行哈希处理。
您可以在免费书籍 Pro-Git 的Git 内部章节中找到答案
本章解释了 git 如何在幕后工作。
正如 Leo 所说,git 检查文件的 SHA1 以查看它是否已更改,您可以像这样检查它(取自 Git Internals):
$ echo 'version 1' > test.txt
$ git hash-object -w test.txt
83baae61804e65cc73a7201a7252750c76066a30
然后,将一些新内容写入文件,并再次保存:
$ echo 'version 2' > test.txt
$ git hash-object -w test.txt
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
如果可能重复的答案还不够,您可能想看看这个http://www.geekgumbo.com/2011/07/19/git-basics-how-git-saves-your-work/
长话短说,Git 使用SHA-1
文件内容来跟踪更改。Git 跟踪四个对象:一个 blob、一个树、一个提交和一个标签。
要回答您关于它如何跟踪更改的问题,请参考该链接的引用:
树对象是 Git 跟踪文件名和目录的方式。每个目录都有一个树对象。树对象在提交时指向该目录中的 SHA-1 blob、文件和其他树、子目录。您猜对了,每个树对象都被加密为其内容的 SHA-1 哈希,并存储在 .git/objects 中。树的名称,因为它们是 SHA-1 哈希,允许 Git 通过将名称与以前的名称进行比较来快速查看任何文件或目录是否有任何更改。很光滑。
https://codewords.recurse.com/issues/two/git-from-the-inside-out
Git 是建立在图上的。几乎每个 Git 命令都会操作这个图。要深入了解 Git,请关注此图的属性,而不是工作流或命令。
用户将 的内容设置
data/number.txt
为2
。这将更新工作副本,但保留索引和HEAD
提交原样。用户将文件添加到 Git。这会将一个包含 2 的 blob 添加到 objects 目录中。它将索引条目指向
data/number.txt
新的 blob。
我在最近的一门课程中发现以下解释很有帮助,Kevin Skoglund 的 Git 基本培训,我在 Lynda.com 上学习过。
Git 通过对我们提交的更改运行算法来生成由 40 个十六进制字符组成的哈希键。例如,如果我们在不同的场合提交相同的一组更改,我们应该得到相同的哈希键。
此外,它通过在每次提交中保留以下元信息来跟踪以前的更改。
每个后续提交都将引用父提交,而第一个提交将没有父提交(或 null/nil 值)。下图在这方面会有所帮助。
这是一个很好的参考:A Visual Git Reference - marklodato.github.io/visual-git-guide/index-en.html 。由于它在信息图表的帮助下提供了一个演练,这将有助于更好地理解 git。