Git数据结构

数据形式

直接记录快照,而非差异比较

  • CVS、SVN等

image-20191118111458367

  • Git

image-20191118111848290

数据结构

Git object

  • Git仓库提交历史部分是由commit object链表组成的
  • commit object、tree object、blob object
  • commit object代表一次提交
  • tree object代表一个目录
  • blob object代表一个文件快照
  • object的key(或id)是一个SHA-1校验和,通过SHA-1哈希算法生成
  • 一个commit object的示意图,只有一个根目录,三个文件 image-20191120192857753
  • commit object链表示意图(tree object 与 blob object 简化为snapshot) image-20191120192947105

object的生成

  • 暂存操作会为每一个文件计算校验和(使用SHA-1 哈希算法),然后会把当前版本的文件快照保存到Git仓库中(Git 使用 blob object来保存它们),最终将校验和加入到暂存区域等待提交
  • 当使用 git commit 进行提交操作时,Git会先计算每一个子目录(图例中只有项目根目录)的校验和,然后在Git仓库中这些校验和保存为tree object。 随后,Git 便会创建一个提交对象,它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针。如此一来,Git 就可以在需要的时候重现此次保存的快照。

数据区域

三个工作数据区域

  • Git有三个工作数据区域,也可以看成是三棵树(下面两张图实际上是等价的,Git仓库(Repository)是狭义的) image-20191118112746775 image-20191120225139822

image-20191120224418733

  • HEAD树、Git仓库、本地仓库、Repository
  • Index、索引区、暂存区、Staging Area
  • Working Directory、工作区、工作树
  • 实际上HEAD树和Index都在.git文件夹内
  • 广义的Git仓库是指.git文件夹里面的所有内容,包括所有的历史提交对象,以及暂存区的内容
  • 狭义的Git仓库只是指所有的历史提交对象,甚至只指HEAD树

HEAD指针

  • HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交。 这表示 HEAD 将是下一次提交的父结点。

三个数据区域稳定状态的数据

  • 假定以刚执行完克隆操作的仓库状态为稳定状态,也可称工作区和暂存区是干净的

  • HEAD树的数据为HEAD指针当前指向的commit object关联的文件树,由tree object和blob object构成

  • 工作区的数据为HEAD树在文件系统中的表达,tree object对应文件夹,blob object对应可编辑的一个文件

  • 索引区的数据可以当作为是HEAD树的复制来理解。当然,实际上并不一样,书上并没有说清楚。个人猜测是扁平化的blob object,不具备树结构,没有tree object。下面是Pro Git书上的阐述:

确切来说,索引并非技术上的树结构,它其实是以扁平的清单实现的。不过对我们而言,把它当做树就够了。

数据状态

Git文件的状态

  • 已被Git跟踪的文件有三种状态:未修改(unmodified)(也可称为已提交(committed))、已修改(modified)和已暂存(staged)。加上未被Git跟踪的状态:未跟踪(untracked),一共四种状态。
  • 实际上Git文件存在六种状态的区分,通过git status -s可以查看文件的当前状态 image-20191120164116121
  • 上图未列出的文件,处于未修改(unmodified)状态,该状态的文件与HEAD树的快照一致
  • ??,处于未跟踪(untracked)状态
  • A,处于已暂存(staged)状态,且文件在进入该状态之前是未跟踪(untracked)状态
  • 右边M,处于已修改(modified)状态,该状态的文件被修改了(与HEAD树不一致)但是还没放入暂存区
  • 左边M,处于已暂存(staged)状态,且文件在进入该状态之前是已跟踪状态
  • MM,同时处于已暂存(staged)状态和已修改(modified)状态
  • 即文件在暂存区有比HEAD树更新的快照,左边M点亮。工作区文件对比Git仓库(广义)的最新快照有修改,右边M点亮
  • 文件是否被Git跟踪,是以暂存区是否存在此文件的快照来判断(历史提交是否包含这里存疑),不存在的话则是未跟踪的(untracked)

Git文件的状态变换

  • 状态变换大体参考下图
  • Unmodified通过Remove the file并不足以变为Untracked,还需要把删除操作加入暂存区并提交。实际上也可以不删除工作区的文件,直接删除暂存区的文件快照,并提交
  • Modified和Staged状态可以同时生效,也就是MM状态
  • Staged经过Commit后,可以是回到Modified状态,也就是MM状态提交后 image-20191120162320801