对于一个复杂的问题,Git确实是一个简单而优雅的解决方案。我认为重要的是,我们要了解幕后发生的事情,以及做出的工程决策,以充分掌握它的简单性和威力。
Git如何存储文件?当我们运行各种Git命令时会发生什么?一切是如何联系在一起的?使用的数据结构是什么?
当您在目录中运行git init时,Git会创建.git目录,Git存储和操作的几乎所有内容都位于该目录中。
钩子:.git/hooks目录包含可以在存储库的某些生命周期事件上运行的脚本。
临时区域:.git/index文件(它还没有出现在上面的树清单中)将为我们的工作目录提供临时区域。
对象数据库:.git/Objects目录是默认的Git对象数据库,其中包含所有内容或指向本地内容的指针。
引用:.git/refs目录是存储本地和远程分支、标记和头部的引用指针的默认位置。引用是指向对象的指针,通常类型为“标记”或“提交”。引用在对象数据库之外进行管理,以允许引用随着存储库的发展而更改它们所指向的位置。引用的特殊情况可能指向其他引用,例如Head。
当我们运行命令git add时。Git将工作目录中的所有更改添加到临时区域,并在.git/Objects子目录中创建BLOB文件。
每个对象文件的文件名都有一个40个字符的SHA-1散列。Git使用前2个字符来组织目录中的对象。
此BLOB对象包含文件的内容。一旦创建,所有对象都是不可变的。对文件进行更改并将其暂存将导致创建一个全新的对象。
让我们验证并检查此BLOB文件的内容。当我们运行CAT.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238命令时,我们没有得到我们期望的结果。
实际上,Git使用zlib压缩每个对象,因此您看到的是压缩的内容。
运行git Commit命令将在Objects子目录中创建另外两个对象。一个是树对象,另一个是提交对象。
单个树对象包含一个或多个条目,每个条目都是BLOB或子树及其相关模式、类型和文件名的SHA-1散列。
提交对象的格式很简单:它为此时的项目快照指定顶层树、父提交(如果有的话)、作者/提交者信息和提交消息。
我们通常使用的提交id是提交对象内容的SHA-1散列。
Git使用这些不同类型的对象将所有内容存储为有向无环图。下面是此时的数据结构。
Git中的分支只是指向其中一个提交对象的轻量级可移动指针。正因为如此,在Git中创建新分支非常便宜。
Git如何知道您当前在哪个分支机构?它保留一个名为head的特殊指针。Head只不过是一个指向分支的特殊指针。您当前正在处理的分支。
当我们运行命令git checkout-b<;name>;时,Git会在refs/head目录中创建一个带有分支名称的新文件。该文件包含指向最新提交的指针。
总之,Git命令是对数据存储的抽象。散列、基于文件的键值存储和树形数据结构,这些都是Git背后的关键。
我正在写一本书:Git Complete:Git和Github的权威分步指南。获得您的预购,可享受五折优惠。😇