Git在提交对象中存储差异信息吗?

58

根据这篇文章:

需要注意的是,这与你熟悉的大多数版本控制系统非常不同。Subversion、CVS、Perforce、Mercurial等都使用增量存储系统——它们存储一个提交和下一个提交之间的差异。Git并不这样做——每次提交时,它存储项目中所有文件看起来像什么的快照。对于使用Git的人来说,这是一个非常重要的概念。

然而,当我运行git show $SHA1ofCommitObject时,...

commit 4405aa474fff8247607d0bf599e054173da84113
Author: Joe Smoe <joe.smoe@example.com>
Date:   Tue May 1 08:48:21 2012 -0500

    First commit

diff --git a/index.html b/index.html
new file mode 100644
index 0000000..de8b69b
--- /dev/null
+++ b/index.html
@@ -0,0 +1 @@
+<h1>Hello World!</h1>
diff --git a/interests/chess.html b/interests/chess.html
new file mode 100644
index 0000000..e5be7dd
--- /dev/null
+++ b/interests/chess.html
@@ -0,0 +1 @@
+Did you see on Slashdot that King's Gambit accepted is solved! <a href="http://game

...它输出的是提交与之前提交的差异。我知道git在blob对象中不存储差异,但它是否在提交对象中存储差异?或者git show是动态计算差异吗?


8
一个附注:Git实际上确实对对象进行增量压缩,但这仅仅是为了压缩效果。有时人们会误解这个说法,认为Git存储差异文件。这里有一些格式的文档:http://book.git-scm.com/7_the_packfile.html(请记住,它记录增量之间的对象只是它发现相似的数据块;它们不一定是同一文件的连续版本,但也可能是。当然,这些增量并不是逐行比较差异)。 - Cascabel
3
更新来自Jefromi的相关链接:http://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E6%9E%B6%E6%9E%84-Packfiles - Ciro Santilli OurBigBook.com
3个回答

94

这句话的意思是,大多数其他版本控制系统需要一个过去的参考点才能重新创建当前提交。

例如,过去某个时间点,基于差异的版本控制系统会存储完整的快照:

x = snapshot
+ = diff
History:
x-----+-----+-----+-----(+) Where we are now

所以,在这种情况下,要重新创建(现在)的状态,它必须先检出(x),然后为每个(+)应用差异,直到达到现在。请注意,永远存储增量会极其低效,因此基于增量的版本控制系统定期存储完整快照。这是subversion的做法

现在,Git就不同了。Git存储对完整数据块的引用,这意味着使用Git,只需一个提交即可重新创建该时间点的代码库。Git不需要从过去的修订中查找信息来创建快照。

那么,如果是这样,Git使用的增量压缩又在哪里呢?

好吧,这只是一种压缩概念-如果仅有微小的更改,则没有必要将相同的信息存储两次。因此,代表已更改的内容,但存储对其的引用,以便可以重新创建其所属的提交(实际上是引用树),而无需查看过去的提交。问题是,Git并不是在每个提交之后立即执行此操作,而是在垃圾收集运行时执行。因此,如果Git还没有运行垃圾收集,您可能会在索引中看到非常相似的内容对象。

但是,当Git运行其垃圾收集(或手动调用 git gc 时),则会清除重复项并创建只读压缩文件。您无需担心手动运行垃圾收集- Git包含可告诉它何时执行此操作的启发式方法。


2
谢谢,卡尔。那么,在一个庞大的项目中提交小的更改不会在长期内使存储库充斥着大量冗余副本吗? - shuhalo
4
没错,实际上它比这更好。如果您复制了所有源文件并将它们添加到当前提交中,则在运行 gc 后仅会有元数据 - 文件名、路径、作者等等的额外信息。文件本身的实际内容只会简单地指向以前来自原始代码的 blob。 - Carl
1
很抱歉,我不理解你的措辞。你能否修改一下:“嗯,这只是一个压缩概念——如果只有微小的变化,存储相同的信息就没有意义。因此,要表示发生了什么变化。”你的意思是说,如果在一个10k行的文件中添加一个字符,那么不会生成新的哈希值吗?对我来说这太不清楚了。 - mfaani

59

不,git中的提交对象不包含差异-相反,每个提交对象包含树的哈希,该哈希递归地完全定义了该提交时源树的内容。在git社区书籍中有一个很好的解释,其中详细说明了blob对象、tree对象和commit对象的内容。

所有由git工具显示给您的差异都是从文件的完整内容按需计算出来的。


0
1. Commit是一个小的元数据文件。它包含了恢复项目完整快照所需的所有信息。
2. 一些命令,比如diff或cherry-pick,计算快照之间的差异。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接