0
点赞
收藏
分享

微信扫一扫

【论文阅读】Improved Denoising Diffusion Probabilistic Models

金牛豆豆 03-18 09:00 阅读 4

【Git】从快照到内容寻址,浅析Git版本管理的实现方式

学习使用Git的过程中,常常对Git的原理与机制感到好奇:Git为什么能通过一个小小的仓库实现庞大文件的版本管理?为什么明明没有倍增式存储却还能轻松地完成合并与分支操作?Git的功能实现究竟是通过保存差异化文件?还是通过保存差异(diff)?本篇博客将从Git的快照机制入手,以十万个为什么的方式,介绍Git底层机制的一部分。

QQ图片20240313192233

<1>啥是快照?快照和文件差异有啥区别?

此处需要先引出SVN版本控制系统(貌似经常捞出来跟Git比较),只关注两者存储方式的区别:

这里有两张图可以比较明确地显示出两者之间的区别:

preview

preview

img

全…量?很全吗?有多全?

快…照?很快嘛?有多快?

这么多奇怪的名词,倘若读者第一次见,必然会感到晕头转向,不过不用担心,接下来笔者会一一解释:

快照(snapshot)

这个概念源于摄影学,在摄影中,snapshot可以翻译成:抓拍,指记录某一瞬间的影像。

在计算机领域中,我们提到的快照多半为存储快照,百度百科对存储快照的解释是这样的:

image-20240317010223927

全量快照(full snapshot)与增量快照(incremental snapshot)

快照有全量快照 (full snapshot) 和增量快照 (incremental snapshot) 两种类型。

  1. 全量快照(Full Snapshot):在全量快照中,整个数据集或文件系统的状态被完整地复制并保存。无论是第一次备份还是后续备份,都会复制整个数据集,这样每次备份都会占用大量的存储空间。
  2. 增量快照(Incremental Snapshot):在增量快照中,只有自上次备份以来发生更改的部分被复制并保存。这意味着每次备份只会存储自上次备份以来的变化,因此它们通常需要更少的存储空间,并且备份速度更快。

此处需要纠正前文的一个概念,前文说:Git使用全量快照。这个说法其实并不完全准确,试想一下,如果仓库文件本身很大,某次提交可能仅仅更新了README文件里面的一部分标点符号,就创建了一个全量快照,如此一来仓库大小几乎翻倍,在存储上显然不够优秀。

Git面对这样的情况,采取了一种内容重用的方式,来解决存储上的问题:

内容重用

首先,git会对每一个文件进行哈希值的计算:

当你提交一个新的版本时,Git 不会简单地复制整个文件内容并创建一个新的对象。相反,Git 首先计算新版本文件的哈希值。如果该哈希值已经存在于仓库中,说明相同的文件内容已经被存储过了,Git 将会重用这个已经存在的对象,而不是重复存储相同的内容。

仍然以前面的假设为栗子,假如某次更新只修改了README文件里面的标点符号,而没有修改其他大型文件,此时创建提交,git会计算出所有文件的哈希值,发现仅仅多了一个文件的哈希值,而其他值并无变化,则仓库内仅仅多了一个新的README文件,存储模式上大大优化了。

image-20240316233930771

通过内容重用,Git 能够节省大量的存储空间。即使在项目中有许多相似的文件或相同的文件内容,Git 也只会存储一份文件内容的副本。这种方式使得 Git 仓库的存储效率非常高,即使在处理大型项目时也能够快速、高效地存储和管理文件。

<2>快照有什么用呢?Git如何实现保存快照?

快照的优点

我们将视线再次转回snapshot这个词的原意:保存某一瞬间的影像。

所以,对于 git 仓库,只需要将每一个文件的内容恢复到节点时的状态,就能完整还原当时的场景了。

保存快照相对于保存文件差异的优点有许多,例如:

img

哈希与内容寻址

可能读者会发现之前在介绍内容重用的时候提到过哈希,要介绍Git实现保存快照的方式,就绕不开哈希与内容寻址。

哈希值(Hash):

Git 使用 SHA-1 哈希算法来计算对象的唯一标识符。每个 Git 对象,包括文件内容(blob)、目录结构(tree)、提交信息(commit)等,都会被计算出一个唯一的哈希值。哈希值是根据对象的内容计算得出的,只要对象内容不同,哈希值就会不同。这确保了 Git 中的每个对象都具有唯一性。

SHA-1算法是一种消息摘要算法,与MD5算法的类型相同。

引个流先(你真以为文章有人看吗):【加密算法】如何藏住Little Burger的小秘密?-CSDN博客

这篇文章中简单介绍了消息摘要算法的几个特征,我们不妨看看:

image-20240317003539278

主要关注红圈中的字,消息摘要算法具有高度离散性和抗碰撞性,这就可以确保每次文件有修改时哈希值会发生变化,同时很难与其他文件的哈希值相同,便于内容寻址。

内容寻址(Content Addressing):

Git 使用哈希值来寻址对象。这意味着 Git 的对象数据库(Object Database)是一个键值对结构,其中键是对象的哈希值,而值则是对象的内容。通过使用哈希值作为对象的唯一标识符,Git 可以确保对象在存储和检索时是完整和一致的。当你需要访问某个对象时,Git 只需根据该对象的哈希值在数据库中查找相应的内容。

以一般的流程为栗子,我们会先用git add指令将文件添加到暂存区,而后用git commit来提交。

现在假设我们在工作目录下新增俩文件Ham, Bur。同时执行了一次git add添加了这三份文件。那么此时git add做了如下两件事:

  • 首先,它给这三个文件分别创建2个索引添加到暂存区中。git通过SHA-1这种哈希算法,遍历每一个文件,根据文件内容等信息,为文件创建索引。以后,只要根据这个索引,我们就可以取出一个文件中的完整内容
  • 然后,git对当前的暂存区拍了一张照片,也就是我们所说的**快照,**并将快照放入版本库。快照里包括什么内容呢?快照里包括我们刚才说的文件索引和文件完整内容(类似于key-value的结构)。同时,git采用内置的blob对象来存储这三个文件的快照。

image-20240317005246552

接下来,我们执行git commit ,这个命令又做了两件事:

  • 首先,零散的文件得有一个目录结构吧?所有它用一个内置的tree对象,把文件的目录结构保存下来。
  • 然后,git在这个tree对象上又包了一层,创建了一个commit对象,这个commit对象也是我们说的git进行版本管理的最终对象。commit对象里包含了tree对象,还包含作者、提交评论等信息。

image-20240317005705217

img

结语

祝大家好好学习,天天向上。

举报

相关推荐

0 条评论