基本流程
git提交到远程仓库的基本流程大致如下:

在这四个过程中,git进行了大量的指针操作,其中主要涉及到三个对象:commit、tree、blob,这三个对象都保存在.git文件夹下,下面我们会详细了解一下git的目录结构以及这三个对象的含义和作用
git目录结构
当我们执行git init
命令时,会产生一个.git文件夹,其中的目录结构如下:

- HEAD文件保存了当前分支名
- objects下保存了commit、tree、blob对象
- refs 下有heads和tags文件夹,其中heads保存了提交过的分支名称
接下来我们来了解一下四个对象的含义
1、blob对象
- 概念:blob对象是git存储的基本对象,它存储了add到本地的文件内容
- 示例:
在文件夹下创建一个文件并输入内容:
echo 'master1' > lwl.txt
将创建的内容add到本地,查看./git下的objects文件夹,发现多了一个文件:

该文件的路径名称是git通过add上去的文件名和文件内容哈希所得到的字符串,git提供了一些命令查看这些文件:
//查看文件类型
git cat-file -t 哈希
//查看文件内容
git cat-file -p 哈希
我们查看上面形成的文件类型和内容:

可以看到该文件为blob类型,其中存储了我们输入到lwl.txt的文本(但是打开文件里面是乱码,因为已经被压缩过了)
2、tree对象
- 概念:tree对象中存储了目录信息和作者等结构信息,commit之后才会生成tree对象
- 示例:
重新创建一个嵌套文件夹,并在文件夹中创建txt文件:
mkdir -p first/second
echo 'aaa' > first/second/lwl.txt
git add .
git commit -m "first"
查看objects中的文件:

通过cat-file命令可以看到有一个commit对象,三个tree对象和一个blob对象,这里我们只关注tree对象,查看所有tree对象的内容:

可以看到tree对象中存储了各级目录的tree对象索引,而最后一级目录的tree对象则保存了指向保存了lwl.txt的blob文件的索引
3、commit对象
- 概念:commit对象保存了committer、author和一个根目录的tree对象,以及提交时的备注。每一次提交都会生成一个commit对象
- 示例:
在 2、tree对象 的示例中,由于我们提交过一次,因此也产生了一个commit对象,查看其中的内容:
commit对象内容
可以看到和概念完全吻合
提交
每次提交的时候,都会生成一个commit对象,打开.git/refs/heads文件夹,其中有一个master文件,打开该文件,其中记录了一串哈希值,查看该指针的类型:

我们修改一下lwl.txt中的内容:

添加并提交,重新查看master中的内容:

发现内容改变了,查看该指针表示的类型和内容:

其中保存了上一个提交的commit指针parent,根目录tree对象,因此可以知道每次提交,git只是将当前分支的指针指向了最新的commit对象
分支切换
创建一个新的分支:
git branch lwl
heads文件夹下会出现两个文件

其中lwl为新建的分支,里面的内容和master一致,因为该分支上没有做任何提交操作
查看.git下的HEAD文件:

当前分支为master,我们用checkout切换分支,再查看HEAD文件:

HEAD的内容变成了lwl,因此git是通过HEAD文件来确定当前分支,通过refs里对应的分支文件中记录的commit指针来确认目前处于哪个提交记录上面,这样做的好处是,一旦发生回滚操作,只需要改变指针即可。
总结
对象类型的关系图如下:

网友评论