git原理探索实验1——git的三种对象

背景知识

git的三个区域

  • working directory
    • 也就是你当前所能操作的那些目录和文件
  • history
    • 你所提交的所有记录,文件历史内容等等。git是个分布式版本管理系统,在你本地有项目的所有历史提交记录;文件历史记录;提交日志等等
  • stage(index)
    • 暂存区域
    • 本质上是个文件,也就是.git/index

git的三类对象及其关系

  • commit对象
    • 用于表示一个提交
    • commit对象之间会组织成一棵树的结构
    • 每一次提交都会产生一个commit对象
    • 除了第一次提交产生的commit对象,其它的commit对象都会有父亲commit对象
    • 如果只是提交操作,则父亲节点只有1个
    • 如果是merge操作,则父亲节点会有2个
    • commit对象包含的信息有
      • parent,父亲提交对象
      • tree, 根目录树对象
      • author,作者
      • committer,提交者
  • tree对象
    • 用于表示一个目录
  • blob对象
    • 用于表示一个文件
    • tree和blob对象可以看成是git内部采用的文件系统对象
    • 其组织结构和文件系统是很像的,很好理解
  • 这些对象都保存在.git/objects/目录下,每一个对象都会生成1个40位的哈希值,前2位作为文件夹,后38位作为文件名
  • 不同名,相同内容的文件,其哈希值相同,其blob对象也是共用的

实验1

$ git init test
Initialized empty Git repository in C:/Users/MilesGO/Desktop/git/test/.git/
$ cd test
$ find .git/objects -type f

此时由于没有任何的提交记录, find .git/objects -type f指令的返回结果为空,这条指令会列出.git/objects目录下的所有文件
接下来在根目录下创建一个README文件,文件内容hello git

$ echo 'hello git' >> README
find .git/objects -type f

返回结果仍然为空,说明在工作区域做出的改变,如果没有提交到暂存区或历史版本库,是不会产生任何的git对象的

git add README
$ find .git/objects -type f
.git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
$ git cat-file -t 8d0e4123
blob
$ git cat-file -p 8d0e4123
hello git

git cat-file -t指令可以查看一个git对象的类型,git cat-file -p指令可以查看一个git对象的内容
我们将README文件添加到暂存区之后,生成了一个blob文件,对应了暂存区中的README,其内容就是我们刚刚添加的hello git
接下来我们将暂存区的README提交

$ git commit -m 'add README'
[master (root-commit) 29c0715] add README
 1 file changed, 1 insertion(+)
 create mode 100644 README

$ find .git/objects -type f
.git/objects/28/324fe5bad6e397de7a37aa7d8c94b6bf176b83
.git/objects/29/c07152991c7b3ee41f9cb5ac1eff1f26610665
.git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f

$ git cat-file -t 28324fe5
tree

$ git cat-file -t 29c07152
commit

可以看到新生成了1个commit对象和一个tree对象,分别查看这两个对象的内容

$ git cat-file -p 29c07152
tree 28324fe5bad6e397de7a37aa7d8c94b6bf176b83
author MilesGO <164173218@qq.com> 1560070361 +0800
committer MilesGO <164173218@qq.com> 1560070361 +0800

add README

commit对象表明了其对应的根目录tree为28324f,也就是刚才新生成的tree对象

$ git cat-file -p 28324f
100644 blob 8d0e41234f24b6da002d962a26c2495ea16a425f    README

这个tree对象中只包含了一个blob对象8d0e41,也就是一开始我们添加的README文件

实验2

在实验1的基础上继续进行
在README文件中添加hello git again,commit后查看git对象情况

$ echo 'hello git again' >> README
$ git add README
$ git commit -m 'modify README'
[master 4a1d754] modify README
 1 file changed, 1 insertion(+)

$ find .git/objects -type f
.git/objects/28/324fe5bad6e397de7a37aa7d8c94b6bf176b83
.git/objects/29/c07152991c7b3ee41f9cb5ac1eff1f26610665
.git/objects/4a/1d75425a4cd5c3e206a4c69415c59802175039
.git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
.git/objects/b9/641c1bd3e89e43cfaebf63305fc0a655635b50
.git/objects/f8/3422c24917dcb2c2f781c08d83ac2fbc363dd2

$ git cat-file -t 4a1d75
commit
$ git cat-file -t b9641c
tree
$ git cat-file -t f83422
blob

分别新增了1个commit,1个tree和1个blob对象

$ git cat-file -p 4a1d75
tree b9641c1bd3e89e43cfaebf63305fc0a655635b50
parent 29c07152991c7b3ee41f9cb5ac1eff1f26610665
author MilesGO <164173218@qq.com> 1560070808 +0800
committer MilesGO <164173218@qq.com> 1560070808 +0800

modify README

新的提交必然需要生成1个新的提交对象,其tree根目录对象为b9641c,也是新生成的,其parent对象为29c071,也就是第一次提交生成的提交对象

$ 100644 blob f83422c24917dcb2c2f781c08d83ac2fbc363dd2    README
$ git cat-file -p b9641c

新生成的tree对象中,包含1条blob对象的信息

$ git cat-file -p f83422
hello git
hello git again

该blob对象也就是我们刚才修改后提交的README
到此为止,一共有2个commit对象,2个tree对象,2个blob对象

实验3

创建src目录,在src目录下添加main.cpp,添加一些内容

$ mkdir src
$ echo 'hello world' >> src/main.cpp
$ git add --a
$ git commit -m 'add src/main.cpp'
[master 12c2c80] add src/main.cpp
 1 file changed, 1 insertion(+)
 create mode 100644 src/main.cpp

$ find .git/objects -type f
.git/objects/12/c2c80788dcd74a1cd739157c0a1011514d36b2
.git/objects/28/324fe5bad6e397de7a37aa7d8c94b6bf176b83
.git/objects/29/c07152991c7b3ee41f9cb5ac1eff1f26610665
.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
.git/objects/3f/68ce3f72d2ee5bec285180c6fb0aa3a7eee4ff
.git/objects/4a/1d75425a4cd5c3e206a4c69415c59802175039
.git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
.git/objects/b9/641c1bd3e89e43cfaebf63305fc0a655635b50
.git/objects/c5/fb7c2c039f5f48bf89f922267016e8702bead8
.git/objects/f8/3422c24917dcb2c2f781c08d83ac2fbc363dd2

新添加的对象有

12c2c8
3b18e5
3f68ce
c5fb7c

查看这些新添加的对象

$ git cat-file -t 12c2c8
commit
$ git cat-file -p 12c2c8
tree 3f68ce3f72d2ee5bec285180c6fb0aa3a7eee4ff
parent 4a1d75425a4cd5c3e206a4c69415c59802175039
author MilesGO <164173218@qq.com> 1560071508 +0800
committer MilesGO <164173218@qq.com> 1560071508 +0800

add src/main.cpp

$ git cat-file -t 3b18e5
blob
$ git cat-file -p 3b18e5
hello world

$ git cat-file -t 3f68ce
tree
$ git cat-file -p 3f68ce
100644 blob f83422c24917dcb2c2f781c08d83ac2fbc363dd2    README
040000 tree c5fb7c2c039f5f48bf89f922267016e8702bead8    src

$ git cat-file -t c5fb7c
tree
$ git cat-file -p c5fb7c
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    main.cpp

实验4

不同文件名,相同文件内容

$ echo 'hello world' >> main2.cpp
$ git add main2.cpp
$ git commit -m 'add main2.cpp'
[master 314b549] add main2.cpp
 1 file changed, 1 insertion(+)
 create mode 100644 main2.cpp

在这种情况下,会新增哪些git对象呢?

$ find .git/objects -type f
.git/objects/12/c2c80788dcd74a1cd739157c0a1011514d36b2
.git/objects/28/324fe5bad6e397de7a37aa7d8c94b6bf176b83
.git/objects/29/c07152991c7b3ee41f9cb5ac1eff1f26610665
.git/objects/31/4b5494eb06a9963f4e6f97075f2354c8a15f13
.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
.git/objects/3e/c767e93a78c0ef5c4685eace73192bf6bc6848
.git/objects/3f/68ce3f72d2ee5bec285180c6fb0aa3a7eee4ff
.git/objects/4a/1d75425a4cd5c3e206a4c69415c59802175039
.git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
.git/objects/b9/641c1bd3e89e43cfaebf63305fc0a655635b50
.git/objects/c5/fb7c2c039f5f48bf89f922267016e8702bead8
.git/objects/f8/3422c24917dcb2c2f781c08d83ac2fbc363dd2

其中314b54和3ec767是新增的

$ git cat-file -t 314b54
commit
$ git cat-file -p 314b54
tree 3ec767e93a78c0ef5c4685eace73192bf6bc6848
parent 12c2c80788dcd74a1cd739157c0a1011514d36b2
author MilesGO <164173218@qq.com> 1560072040 +0800
committer MilesGO <164173218@qq.com> 1560072040 +0800

add main2.cpp

$ git cat-file -t 3ec767
tree

$ git cat-file -p 3ec767
100644 blob f83422c24917dcb2c2f781c08d83ac2fbc363dd2    README
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    main2.cpp
040000 tree c5fb7c2c039f5f48bf89f922267016e8702bead8    src

$ git cat-file -p c5fb7c
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    main.cpp

main2.cpp和src/main.cpp共用了同一个blob对象

git ls-files --stage可以看到暂存区所有文件及其对应的blob文件

$ git ls-files --stage
100644 f83422c24917dcb2c2f781c08d83ac2fbc363dd2 0       README
100644 3b18e512dba79e4c8300dd08aeb37f8e728b8dad 0       main2.cpp
100644 3b18e512dba79e4c8300dd08aeb37f8e728b8dad 0       src/main.cpp

从这里也可以看到main2.cpp和src/main.cpp共用了同一个blob对象

原文地址:https://www.cnblogs.com/milesgo517/p/10993618.html