Git中基于内容寻址的好处是什么?

xkrw2x1b  于 2023-09-29  发布在  Git
关注(0)|答案(4)|浏览(98)

问:
Git使用基于内容的文件寻址系统(也就是说,它使用blob和树哈希作为“文件名”)。我想知道这种寻址系统的好处是什么?
我可以清楚地看到一些好处,但这些都是次要的:
1.如果有人更改了git repo中的某个文件,它将中断所有指向它的提交。这样你就会知道有什么不好的事情发生了。但它真的那么有用吗?
1.对文件使用哈希将 * 真实的文件名 * 从其内容中分离出来,因此您可以“便宜地”重命名文件。
我觉得使用sha进行文件寻址的真正原因是完全不同的。有人能解释一下吗?
PS:澄清。问题是为什么Git使用哈希来寻址文件,而不是它是如何做到这一点的。我知道一个如何,我需要知道为什么。
P.P.S.有一篇关于Git principals和why Git looks so strange的文章(因为它应该在除了核心操作系统和文本编辑器之外没有其他软件的机器上使用),但这篇文章仍然只提到了这个原因:

  • 如果您计算文件的sha,并且此sha已经在objects文件夹中,那么您知道您不需要再次存储它,因为sha取决于内容。*

好吧,这就是为什么我得到。任何其他为什么使用 * 内容可寻址文件系统 *?

ibps3vxo

ibps3vxo1#

Git最常见的一件事就是比较一个项目的两个版本。因为对象存储(提交、树和blob)是内容可寻址的,所以这可以通过比较“文件名”来非常快速地完成。
此外,在存储内容时,很容易看到它是否是您已经存储的内容的副本,因此您可以避免存储重复内容。

yvgpqqbh

yvgpqqbh2#

此哈希是对象的唯一ID。您可以对存储在DB中的blob执行相同的操作-计算散列并使其成为ID。它的好处包括:

  • 重复数据删除。如果你有相同的blob(Git中的相同文件)-你不会复制数据-它将被存储一次并从不同的地方引用。这意味着:
  • 你可以复制相同的文件或文件夹,并且在Git“数据库”中不会有任何重复,只是多个引用到同一个blob。因此,要存储/传输的空间量被最小化。
  • 当您重命名/移动文件时-它们的内容不会以不同的名称再次添加到Git。Git将生成相同的哈希,因此将快速识别出不需要创建新对象。同样-相同的对象将从不同的位置引用。
  • 如果你在一次提交中删除文件,然后在另一次提交中再次添加它-仍然不会创建新对象,因为旧对象仍然驻留在.git中(它们被旧提交引用,因此必须留在.git中)。
  • 另外,如何快速显示两次提交之间的差异?对于Git来说,这很容易,因为文件夹只是引用blob和其他文件夹的对象(树)-并且这些信息也是内容可寻址的。因此,如果树(文件夹)现在引用不同的blob/树(或它们的名称更改)-基于散列的ID将更改。所以Git可以首先检查树(文件夹)的哈希值,看看它们的内容是否不同,以及Git是否必须进入内部检查其他差异。
  • 您不必存储有关哪个 surrogate ID引用哪个数据的额外数据库(元信息)。ID可以从内容中推断出来。

PS:虽然第1-2点也可以通过代理ID来实现,但您只需将散列 * 沿着这些ID一起存储。因此,在存储新文件之前,您必须计算其哈希值,并通过数据库中的哈希值查找代理ID。不太方便,但有可能。

eyh26e7m

eyh26e7m3#

老实说,并发症。
如果你将哈希值视为文件的逻辑内容,那么每个git对象都是一个不可变的写时复制对象。
两个代码块可以同时与不可变的写时复制对象交互,并且永远不会相互冲突。它们之间唯一的交互就是操纵引用计数。
如果git对象在逻辑上有对其他对象的引用,并发问题就会爆炸。避免基于锁的并发的疯狂几乎是不可能的,这也是非git SCS如此糟糕的原因之一。
当你尝试同步git-repo状态时,你首先要将不可变对象向上推。如果其他人也在做同样的事情,远程存储库可以告诉你不要打扰:但是如果忽略远程存储库,它是无害的,因为两次创建相同的不可变对象是安全的操作。
唯一的争论点是当你试图修改git中逻辑上不可变的部分--分支时。
在这里,git依赖于原子读取-修改-写入操作。您声明“main,它曾经引用不可变的状态X1,现在引用状态X2”。如果其他人同时说他们希望将main从状态X1移动到X3,则任何一个操作都可以运行,而另一个操作失败。
在大型项目中,正是这一步使用了git外部的解决方案,因为这是git工作流程中不承认不可变并发之美的一部分。
但是基于不可变散列的系统几乎消除了所有的并发问题,并且git被设计为一个高度并发的源代码控制系统。它是如此的并发,以至于人们可以克隆一个git repo,离开一年,然后回来,仍然能够与原始repo讨论他们的更改如何与其他人相关。

rwqw0loc

rwqw0loc4#

如果有人更改了git repo中的某个文件,它将中断所有指向它的提交。这样你就会知道有什么不好的事情发生了。但它真的那么有用吗?
这就是使用 strong(kind of;而不是在安全性方面)在类似简单校验和的东西上的散列函数。
在BitKeeper时代(Git之前使用的BitKeeper),Linux项目的源代码曾被入侵。[1]一些恶意行为者试图在没有人注意到的情况下更改代码。值得庆幸的是,BitKeeper有一些校验和机制,碰巧捕捉到了这一点。
想想Linus Torvalds使用的Git仓库:他是唯一一个可以承诺的人那么,当他收到一个拉取请求(通过电子邮件)时会发生什么呢?如果他拉它,他可以看到它引入的差异,并确信合并前的历史是合理的。为什么?因为如果有人修改了历史记录,那么操作就会失败,因为传入提交的SHA1值不匹配。
但是SHA1并不安全那么,如果有人花了一些钱来计算与他自己历史中的某个提交相同的SHA1呢?那么,“伪造”的对象仍然不会进入他的存储库,因为 * 他自己的 *(不是伪造的)对象将优先于任何 * 传入的 * blob。
尽管有这些警告:这些是2007年提出的索赔。也许技术已经改变了,Git不再拥有它曾经拥有的(或认为它拥有的)保证。但事实仍然是,这种哈希值链的目的(意图)(在一千次提交之前改变一个小东西会使所有祖先无效)是为了防止人们在你没有注意到的情况下改变你的存储库的历史。

注意事项

1.这是基于我对2007年Linus Torvalds Google Talk的回忆

相关问题