Git的科普这里就不多说了,百度一搜就有一大堆
以下主要是探究git操作(add and commit)的背后、.git目录下文件内容的变化
PS:git数据库中主要有三种存储对象(tree\commit\blob)、存储在.git/objects目录下,后面会做介绍、查看git数据库文件主要有以下两个命令:git cat-file -t <键值>和git cat-file -p <键值> (-t 用于查看键值对应数据的类型、-p用于查看键值对应的数据内容)
最后还有 git ls-files --stage 命令(参看暂存区文件内容)
首先找个目录初始化一个git仓库(这里选择了F://GIT)
执行完毕后F://GIT目录下多了一个.git文件夹
现在 .git/objects 长这样(info and pack 保存执行 git gc命令后修剪过的 git 数据文件、这里不展开讨论、有时间再说)
add
add 命令会将文件数据放到暂存区(概念百度)中、其实这个暂存区就是个文件(.git/index)目前还没在这个git仓库中执行过任何操作,所以目前无该文件
步入正题
- 首先在F://GIT目录下创建一个demo.txt 文件,里面的内容是add(随便写的)、然后进行一次add操作(省略)
- 现在.git/index文件已经生成了,如果直接打开看、会发现是乱码、不过Git提供了查看此文件内容的命令(git ls-files --stage)
- 这就是暂存区的内容了,d28d40b18823a27071d0e9ce89c149adb3f9c4ee 是一个hash值(键值), 指向.git/objects下的一个具体文件 ; 最后的demo.txt就是此次add 操作对象文件的路径了
- 看下.git/objects下的变化,多了一个d2文件夹(其实就是上面hash值的前两个字符)、d2文件夹下有一个文件、文件名是hash值后面的字符(8d40b18823a27071d0e9ce89c149adb3f9c4ee )
- 使用git cat-file -t <键值>看下文件类型(键值使用缩写)、发现是上面提到过的blob存储对象
- 接着使用git cat-file -p <键值>看下文件内容、哦豁,就是demo.txt里的内容,原来blob存储对象保存的是文件内容
由上述内容可知add产生blob存储对象、接下来看看commitPS:index文件内容规则:相同的文件是覆盖式的(总保存最新的),不同的文件是增加的方式,撤销当前add,只会撤销对应文件信息,之前的信息依旧存在,有兴趣可自行尝试
commit
- 在前面add基础上执行commit操作(message 为 version1)
- 看下.git/objects下的变化、又多了两个文件(接下来要说的tree 和 commit存储对象)
- 先看第一个文件夹下的内容(和blob存储对象一样,文件夹名和文件名拼起来就是该储存对象对应的键值)
- 如法炮制,看下文件类型和内容、看结果该文件对应的是tree存储对象、内容记录了 此次生成的blob存储对象的键值和 文件路径(demo.txt)
- 最后看一下另外一个文件的类型和内容、看结果该文件对应的是commit存储对象、内容记录了相应tree对象的键值、提交人信息和时间、还有对应的commit message(version1)其实还应该有一个parent信息(内容是上一次commit键值)、因为我们只进行了一次commit、所以没看到
至此,git 继续对应版本信息的脉络就出来了
关系图
最后说一下git的索引,没有索引的话、每次都要去读那么多commit存储对象文件向上查找....慢死个人
.git目录下有一个检索文件(.git\logs\HEAD)当前分支对应的索引,里面存放的内容如下
基本总结
Git的核心为它的对象数据库,其中最重要的是commit、tree和blob对象
commit:记录了对应tree对象的hash键值值、上一次commit对应的hash键值、版本作者、版本序列、版本说明和提交时间等附加信息
tree:记录了对应版本文件名、文件目录结构
blob:对文件内容的记录
Git通过键值找到对应的文件、可以更加方便的定位到某一版本的提交。Git分支、tags等功能都是基于它实现的。