当git说它正在"解决三角洲"时,它实际上在做什么?

Nik*_*man 168 git

在第一次克隆存储库时,git首先接收对象(这很明显),然后花费大约相同的时间"解析增量".在克隆的这个阶段实际发生了什么?

ara*_*nid 106

阶段git clone是:

  1. 接收repo数据库中所有对象的"pack"文件
  2. 为收到的包创建索引文件
  3. 查看头版修订版(显然是非裸版回购)

"解决增量"是为第二阶段显示的消息,索引包文件("git index-pack").

包文件中没有实际的对象ID,只有对象内容.因此,为了确定对象ID是什么,git必须对包中的每个对象进行解压缩+ SHA1以生成对象ID,然后将其写入索引文件.

包文件中的对象可以存储为增量,即对一些其他对象进行的一系列改变.在这种情况下,git需要检索基础对象,应用命令和SHA1结果.可能必须通过应用一系列delta命令来派生基础对象本身.(即使在克隆的情况下,已经遇到过基础对象,但在内存中缓存了多少制造对象的限制).

总之,"解决增量"阶段涉及对整个仓库数据库进行解压缩和校验和处理,这不足为奇地花费了很长时间.据推测,解压缩和计算SHA1实际上比应用delta命令需要更多的时间.

在后续提取的情况下,所接收的包文件可以包含对接收git预期已经具有的其他对象的引用(作为增量对象基础).在这种情况下,接收git实际上重写接收的包文件以包括任何这样的引用对象,以便任何存储的包文件是自给自足的.这可能是"解决增量"消息的来源.

  • 这可以并行化吗? (7认同)
  • @brooksbp:事实证明,我错了,包文件不需要按 sha1 哈希排序。此外,在编写时,git 在对象需要它们之前写入所需的对象。所以,实际上你应该能够并行化它。唯一的缺点仍然存在:因为您不知道以后需要哪些对象,所以您必须一遍又一遍地重新创建一些对象。请参阅此处:https://www.kernel.org/pub/software/scm/git/docs/technical/pack-heuristics.txt (2认同)
  • @BodoThiesen 这是一本相当有趣的读物。其中大部分内容都超出了我的理解范围,但我获得了一种新的最喜欢的勺子主义:“一举一动……” (2认同)

Amb*_*ber 50

Git使用delta编码来存储packfiles中的一些对象.但是,你不希望有播放的每一个修改,以获得最新的版本在给定的文件,这样的Git还具有存储和文件内容偶尔的快照."解决增量"是确保所有这些保持一致的步骤.

这是 Pro Git书中"Git Internals"部分的一章,可以在线获取,讨论这一点.

  • 这个答案是不正确的.它似乎描述了Mercurial是如何工作的,而不是Git.Google正在搜索此问题,因此我觉得有必要回复.Git确实*不*将提交之间的差异存储为增量; Git是一个"整个对象"商店.因此,Git不需要"快照"来显示任何给定文件,因为文件历史不需要从增量重建.这就是Mercurial的工作方式. (69认同)
  • delta编码发挥作用的唯一地方是包文件,它严格用于压缩和传输 - 它不会改变Git"看到"世界的方式.(http://kernel.org/pub/software/scm/git/docs/v1.6.2.3/technical/pack-heuristics.txt)请参阅下面的araqnid的答案,以获得准确的答复. (10认同)
  • 在此上下文中,所有"快照"表示文件状态的完整副本,而不是增量编码版本.正如您所提到的,Git*会在packfiles中使用delta编码.没有人说它"改变了Git如何看世界"; 请停止预测您自己的假设. (3认同)
  • 你的答案仍然不准确."Git也偶尔存储了存储文件内容的快照." - 这是不正确的."'解决增长'是确保所有这些保持一致的步骤." - 这也不正确,下面araqnid的回答是正确的. (2认同)
  • 正如上面章节所述,Git 始终存储最新版本的完整文件内容。当以前的版本是“松散”文件时,它们会存储为增量编码文件。定期(通过调用 `git gc` 或每当 Git 确定有必要时)Git 会将所有“松散”文件压缩到包文件中以节省空间,并在该包文件中创建一个索引文件。因此 zlib 将使用自己的 delta 算法进行压缩,但 Git 确实使用 delta 编码来存储以前的版本。由于最常见和最频繁的访问是最新版本,因此将其存储为快照。 (2认同)