git原理性概念

参考资料

近期学习git内部概念及原理,为了加强效果和日后回忆,还是写了这篇笔记进行输出。

参考资料如下:

实验环境:unbuntu 18

objects(blobs tree commits tag) & hash

git里的object 有四种:tree object 、 blob(Binary Large Object) object、 commit object、 tag object

git 会为每个object生成一个SHA1哈希码作为“身份证”。

在git仓库中添加一个文件,git将创建一个blob object对应这个文件。

git的blob object内容与文件内容相关,而与文件名无关。git将对文件的内容使用SHA1哈希算法,产生一串哈希码。该哈希表唯一标识该文件与其对应的object

文件的路径名(pathname)等信息,由tree object 存储。其组织方式类似于Linux文件组织方式。

每一次commit都会产生一个commit object,同样有hash码对应每次commit

只要文件内容相同,blob object的hash就是相同的,因为hash码只对文件内容起作用。

文件内容相同,且文件组织方式也相同时,tree object的hash码才会相同。

commit object的hash码很难相同,因为除了文件内容,提交人的name、email、提交时间等信息都会参与到hash码的计算中

tag则用来引用(reference)一个commit,分为lighweight 和 annotated tag。前者不会创建object,后者则会创建object。许多git命令都只对后者有效。同样的,tag object也会对应一个hash码。

working directory、index、object store/repository(工作区、暂存区、仓库)

注意:在repository的内容不能被删除或修改,只能添加!

  • working directory 存放工作linux目录中的内容

  • index(暂存区)存放一种“索引”,记录目录之间的关系,通常git add 命令会修改该索引,git commit则会将“索引”转换为tree object存储在仓库中

  • object store(仓库)存放4中object,各个object都有hash码与其对应,git commit将会在这个区域中增加object,但不会修改\删除object

先新建一个文件夹,初始化为一个git仓库

ljc@ljc:~/gitlearning$ mkdir project
ljc@ljc:~/gitlearning$ cd project/
ljc@ljc:~/gitlearning/project$ git init
Initialized empty Git repository in /home/ljc/gitlearning/project/.git/
ljc@ljc:~/gitlearning/project$ ll
total 12
drwxrwxr-x 3 ljc ljc 4096 3月   1 19:37 ./
drwxrwxr-x 4 ljc ljc 4096 3月   1 19:37 ../
drwxrwxr-x 7 ljc ljc 4096 3月   1 19:37 .git/

初始化后添加文件、提交文件

在这之前,可以先了解一下git ls-file 和 git cat-file命令:

git-ls-files - Show information about files in the index and the working tree
git-ls-files -s #展示被staged的file对象的哈希值等信息

git cat-file -p <对象哈希码>  # 可该哈希码对应的object的具体内容
git cat-file -t <对象哈希码>  # 可查看

初始化

新建一个project文件,使用git init初始化git仓库

image-20240301193904642

观察.git/objects文件夹, 目前发现只有info、pack这两文件夹

image-20240301194919345

添加两个文件,分别写入内容“foo” “bar”,使用git status可知晓这两个文件目前还没有加入暂存区

image-20240301195213458

目前,index区(暂存区)和object store中没有任何东西

image-20240301195532209

git add 后

将两个文件staged,可以观察到,.git/objects目录下,多出两个blob object,分别对应file1和file2,说明此时两个file对应的object已经被存储

image-20240301202138713

途中这一连串的十六进制码就是object对应的哈希码。且他们的内容存储于.git/objects目录下,为了防止文件数目过大,采用了层级式目录的方式存储object,取hash码的前两个字符先创建一个子目录,然后在子目录中存储对应的object:

image-20240301203432721

且在index也已经创建出了某个index,指向了这两object。由于index没有对应的object,因此不能在.git/objects目录下看到对应的变化。但可以观察./git目录,发现多出来一个index文件,猜想这个文件就对应着Index区。

image-20240301201138500

那么目前三个区域的内容如下所示:

image-20240301203804274

git commit 后

最后commit这两个file:

image-20240301204218591

此时,./git/objects 中会出现两个新的object

image-20240301204404999

使用git cat-file -p查看这两个object类型:

image-20240301204524493

可以发现,其中一个是commit object和一个tree object。

因为git commit后会将index转化为tree object,然后生成一个commit object“指向”该tree object。此时,三个区的内容如下:

image-20240301205305673

看看tree object 和 commit object的内容

image-20240301205911661

tree object像一个文件目录一样把其中的文件关系记录下来。commit object则存储了提交者的信息以及提交信息。

分支

创建分支

创建分支不会产生任何object,分支名只是一种引用,指向了某个commit,它会在.git/refs/heads中。

下面创建分支branch1:

image-20240304170037243

使用git cat-file -p 命令查看他们的内容

image-20240304170409097

看到它们的输出与commit object的输出相同,但它们并不是object本身,因此可以将它们视作一种引用。而且,目前在branch1分支与master分支的指向是相同的,目前的存储区域内容如下所示,几乎没有任何影响。

image-20240304171042772

分支中进行commit

image-20240304191806926

此时object store中将加入三个新的object,分别为blob object、 tree object和commit object。

存储区域的内容变更如下图:

image-20240304193744092

git不会修改object store中的内容,因此即使在working directory中的某些文件被修改,git会直接创建另一个blob object并重新计算哈希值,且将index的引用至新的blob object上。

当commit时,先将index转化为新的tree object(对应hash值为abd31),然后创建一个commit object(对应hash值为d14e3)使其引用新的tree object。

合并分支

这里不考虑复杂的合并情况,也不考虑合并冲突的情况。但为了不至于太简单,首先切回master分支,然后在file2中新加上一行内容,最后commit该改动。

image-20240304202331875

此时,两个分支中的4个文件内容分别为:

image-20240304202607930

在master分支上,执行git merge合并branch1:

image-20240304202945834

git会自动生成commit object来执行这次的merge:

image-20240304203108826

存储区域的内容变更如下图:

image-20240304204739565

posted @ 2024-03-04 21:54  别杀那头猪  阅读(27)  评论(0编辑  收藏  举报