数据形式
直接记录快照,而非差异比较
- CVS、SVN等
- Git
数据结构
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的示意图,只有一个根目录,三个文件
- commit object链表示意图(tree object 与 blob object 简化为snapshot)
object的生成
- 暂存操作会为每一个文件计算校验和(使用SHA-1 哈希算法),然后会把当前版本的文件快照保存到Git仓库中(Git 使用 blob object来保存它们),最终将校验和加入到暂存区域等待提交
- 当使用 git commit 进行提交操作时,Git会先计算每一个子目录(图例中只有项目根目录)的校验和,然后在Git仓库中这些校验和保存为tree object。 随后,Git 便会创建一个提交对象,它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针。如此一来,Git 就可以在需要的时候重现此次保存的快照。
数据区域
三个工作数据区域
- Git有三个工作数据区域,也可以看成是三棵树(下面两张图实际上是等价的,Git仓库(Repository)是狭义的)
- 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
可以查看文件的当前状态 - 上图未列出的文件,处于未修改(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状态提交后