Git 领有一个通过精心设计的模型,这使其可能反对版本控制所需的所有个性,例如保护历史记录、反对分支和促成合作。然而,通过自顶向下的形式(从命令行接口开始)学习 Git 可能会让人感到十分困惑。一旦呈现问题,就只能将当前工作保留下来,而后从新复制一份工作,持续进行解决了。如果咱们可能先对其底层的数据结构有所理解,在接触命令行接口时,就会更加得心应手。
快照
Git 将顶级目录中的文件和文件夹作为汇合,并通过一系列快照来治理其历史记录。在 Git 的术语里, 文件被称作 Blob 对象(数据对象),也就是一组数据。 目录则被称之为“树”,它将名字与 Blob 对象或树对象进行映射(使得目录中能够蕴含其余目录)。 快照则是被追踪的最顶层的树,快照也被称为提交(commit)。
历史记录建模:关联快照
在 Git 中,历史记录是一个由快照组成的有向无环图。每个快照都有一系列的“父辈”,也就是其之前的一系列快照。留神,快照可能同时有多个“父辈”,例如,通过合并后的两条分支。
o <-- o <-- o <-- o <---- o
^ /
\ v
--- o <-- o
数据模型及其伪代码示意
通过伪代码的示意,可能更加清晰的理解 Git 的数据模型。
// 文件就是一组数据
type blob = array<byte>
// 一个蕴含文件和目录的目录
type tree = map<string, tree | blob>
// 每个提交都蕴含一个父辈,元数据和顶层树
type commit = struct {
parent: array<commit>
author: string
message: string
snapshot: tree
}
对象和内存寻址
Git 中的对象能够是 blob、树或提交:type object = blob | tree | commit
,所有的对象都会通过 SHA-1 哈希进行寻址。
objects = map<string, object>
def store(object):
id = sha1(object)
objects[id] = object
def load(id):
return objects[id]
援用
给这些哈希值赋予人类可读的名字,也就是援用(reference)。 援用是指向提交的指针 。与对象不同的是,它是可变的(援用能够被更新,指向新的提交)。例如,master 援用通常会指向主分支的最新一次提交。
references = map<string, string>
def update_reference(name, id):
references[name] = id
def read_reference(name):
return references[name]
def load_reference(name_or_id):
if name_or_id in references:
return load(references[name_or_id])
else:
return load(name_or_id)
在 Git 中,咱们以后的地位有一个非凡的索引,它就是“HEAD”。