对于git的原理我的理解是:git在每次commit的时候都会生成一个tree对象、一个parent对象(如果不是第一次提交的话)、和一个commit对象,这个最顶层的tree就是对应整个工作目录,tree下面还有blob、tree对象,都是一串hash值指向对应的内容,当某个文件发生变动的时候会重新保存一次快照,如果文件没有发生变动,保留的快照依然是上次的。
所有的数据都是保存在objects中的,那么我每次提交岂不是都要生成一个新的文件(因为每次的commit都是不一样的)?那么整个项目在经历过无数次提交之后objects文件的内容会越来越多.....
但是我看了一下项目中的objects中的文件并没有很多,为什么会这样呢?而且在我理解中每次commit在objects中只会生成一个文件文件名就是每次commit hash值的前两位,但是实际上会生成三个文件夹?这又是为啥?
分割线:
我在本地新建git仓库,文件夹下只有一个txt文件
现在我提交一次commit,log如下
然后执行
git cat-file -p c6298e6493a3096dc5dd9
可以看到这里有个tree对象hash值为ba65d8..,我再对这串hash执行:
git cat-file -p ba65d80b3655f4
这里可以看到一个blob对象也对应一个hash值,然后我在对此hash执行
git cat-file -p ea4fff75dac5abe33d1ac53
最后这个引用指向的就是文件的内容。
通过以上操作我个人理解如下:
之前说的git有三个对象,tree、blob、commit,通过测试我觉得这三个对象不是平级关系,在提交一次commit后,生成一个commit对象,这个commit对象下面有一个顶层的tree对象,然后tree对象下面再包含tree对象或者blob对象。最底层的blob对象就是文件的内容
而且git就是依照这些对象的hash值找到对应的文件,记录每次commit的状态。每次提交commit后变化的文件都会保存一个新的快照(hash),没有发生变化的文件依然保留原来的快照(hash)值。
为什么objects中的文件没有很多?
Git 往磁盘保存对象时默认使用的格式叫松散对象 (loose object) 格式:即每次修改一个文件,除了保留旧blob对象,还会生成一个含有完整内容的新blob对象。Git 时不时地将这些对象打包至一个叫 packfile 的二进制文件以节省空间并提高效率:Git 打包对象时,会查找命名及尺寸相近的文件,并只保存文件不同版本之间的差异内容。当仓库中有太多的松散对象,或是手工调用
git gc
命令,或推送至远程服务器时,Git 都会这样做。 打包后,.git/objects中的对象就被移除了,剩下多是没有被任何commit包含的对象。每次commit在objects中生成三个文件夹?
这跟你的文件结构有关系。 commit操作一定会增加 commit对象, 以及代表根目录的tree对象。 若你的修改的文件层级比较深,有多少层级就生成多少个tree对象。
每个对象以文件夹的形式展示出来。
或者也跟你的理解有关? 你更新了问题,只有一个单一文件,在根目录下,那么文件本身是个blob,它在一个tree下(按照你题目的补充,它就是根目录),然后还有一个commit对象。 一共三个。