这里我们创建一个新的git仓库,来看看当我们新提交一个commit时,git目录文件下objects文件内容是怎么变化的。

新建一个仓库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| G:\mygitea\GitLearn $ git init learn02 Initialized empty Git repository in G:/mygitea/GitLearn/learn02/.git/
G:\mygitea\GitLearn $ cd learn02
G:\mygitea\GitLearn\learn02 master $ mkdir doc
G:\mygitea\GitLearn\learn02 master $ git status On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
G:\mygitea\GitLearn\learn02 master $ echo "hello, world!" >> doc\readme.md
G:\mygitea\GitLearn\learn02 master ± $ cat doc\readme.md "hello, world!"
G:\mygitea\GitLearn\learn02 master ± $ git status On branch master
No commits yet
Untracked files: (use "git add <file>..." to include in what will be committed) doc/
nothing added to commit but untracked files present (use "git add" to track)
|
现在看看objects文件夹下有无内容:
1 2 3 4 5 6 7
| G:\mygitea\GitLearn\learn02 master ± $ ls -al .git\objects\ total 4 drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:57 ./ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:59 ../ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:57 info/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:57 pack/
|
接着再git add
加入暂存区看看objects目录下是否有内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| G:\mygitea\GitLearn\learn02 master ± $ git add doc/readme.md
G:\mygitea\GitLearn\learn02 master ± $ git status On branch master
No commits yet
Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: doc/readme.md
G:\mygitea\GitLearn\learn02 master ± $ ls -al .git\objects\ total 4 drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:14 ./ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:14 ../ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:14 d8/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:57 info/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:57 pack/
G:\mygitea\GitLearn\learn02 master ± $ ls -al .git\objects\d8\ total 1 drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:14 ./ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:14 ../ -r--r--r-- 1 WhiteCookies 197121 33 5月 9 15:14 ed87105b8eba70ea70f4256bff9bf0dc7f22d7
G:\mygitea\GitLearn\learn02 master ± $ git cat-file -t d8ed87105b8eba70ea70f4256bff9bf0dc7f22d7 blob
G:\mygitea\GitLearn\learn02 master ± $ git cat-file -p d8ed87105b8eba70ea70f4256bff9bf0dc7f22d7 "hello, world!"
|
可以看到,加入新文件到暂存区后objects目录下生成了一个文件夹d8
,存储了一个blob对象,内容刚好是我们添加进入暂存区的readme.md文件内容。
所以,git会先将暂存区的文件创建一个blob对象。
接着,我们提交commit来看看objects下文件变化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| G:\mygitea\GitLearn\learn02 master ± $ git status On branch master
No commits yet
Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: doc/readme.md
G:\mygitea\GitLearn\learn02 master ± $ git commit -m "add readme" [master (root-commit) 15f598b] add readme 1 file changed, 1 insertion(+) create mode 100644 doc/readme.md
G:\mygitea\GitLearn\learn02 master $ git status On branch master nothing to commit, working tree clean
G:\mygitea\GitLearn\learn02 master $ tree /f .git\objects\ Folder PATH listing for volume 新加卷 Volume serial number is 406B-D0C3 G:\MYGITEA\GITLEARN\LEARN02\.GIT\OBJECTS ├───15 │ f598be27de83504f6da78d50efa7b5376d2854 │ ├───44 │ 41ff53a05fbbd8442abd5cf60d5c7bbe1ef36f │ ├───d8 │ ed87105b8eba70ea70f4256bff9bf0dc7f22d7 │ ├───fe │ 918c8aeeca1c7f91755927447004db23d08b4a │ ├───info └───pack
G:\mygitea\GitLearn\learn02 master $ git cat-file -t 15f598be commit
G:\mygitea\GitLearn\learn02 master $ git cat-file -p 15f598be tree 4441ff53a05fbbd8442abd5cf60d5c7bbe1ef36f author GitHub Whiteco-okie <GitHub 1961663351@qq.com> 1652080699 +0800 committer GitHub Whiteco-okie <GitHub 1961663351@qq.com> 1652080699 +0800
add readme
G:\mygitea\GitLearn\learn02 master $ git cat-file -t 4441ff53a05f tree
G:\mygitea\GitLearn\learn02 master $ git cat-file -p 4441ff53a05f 040000 tree fe918c8aeeca1c7f91755927447004db23d08b4a doc
G:\mygitea\GitLearn\learn02 master $ git cat-file -p fe918c8ae 100644 blob d8ed87105b8eba70ea70f4256bff9bf0dc7f22d7 readme.md
G:\mygitea\GitLearn\learn02 master $ git cat-file -t d8ed87105b8eb blob
G:\mygitea\GitLearn\learn02 master $ git cat-file -t fe918c8aeec tree
G:\mygitea\GitLearn\learn02 master $ git cat-file -p fe918c8aeec 100644 blob d8ed87105b8eba70ea70f4256bff9bf0dc7f22d7 readme.md
|
可以看到,commit后objects文件下增添了三个文件夹。其中两个是tree对象,有一个是commit对象,最后一个是一个blob对象。正如图所示:

总结
看到这里我得出一个经验,没有文件也就是没有blob对象的目录是不会被git管理的,因为git要对文件进行版本管理,所以没有必要对空目录生成对象。基于这一点,readme文件的全路径是这样:[仓库根目录]/doc/readme。那么tree的数量与全路径中“/”的数量一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
G:\mygitea\GitLearn\learn02 master $ mkdir test
G:\mygitea\GitLearn\learn02 master $ ls doc/ test/
G:\mygitea\GitLearn\learn02 master $ git status On branch master nothing to commit, working tree clean
G:\mygitea\GitLearn\learn02 master $ ls -al .git\objects\ total 4 drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:18 ./ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:29 ../ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:18 15/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:18 44/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:14 d8/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 15:18 fe/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:57 info/ drwxr-xr-x 1 WhiteCookies 197121 0 5月 9 14:57 pack/
|
Q1:老师这里 我实验了一下,当提交一次,对一个文件生成一个 Blob 对象后,在对该文件进行修改提交 ,又会产生一个新的 Blob, 这里是不是对同一文件多次修改提交后,会产生多个 Blob 对象?
你的理解都对,git也考虑到后面这个问题了,所以它会把松散的blob做整理,把内容相近的blob做增量存储。
Q2:最后那个小练习,为什么中间需要有2个tree,一个tree不可以吗?多个tree的原因是什么?
让blob成为基础组件,可以利用树把多个文件特定版本对应的blob进行灵活的组装。 blob(代表文件的内容)可以充分地被复用。
就commit对应的项目所有文件的组织来说,commit相当于根节点,blob相当于叶子节点存储文件值,其他的是tree节点。
Q3:刚刚看了一下具体结构, 关于每个 commit 当次提交文件的区分, 是通过比较当次 commit 和 parent 中所有不同的 tree 和 blob , 然后计算出的当次 commit 涉及的文件么?
不会,平常 Git 存储的完整文件——松散 loose 对象格式,但是 Git 会时不时对这些文件进行打包,删除原始文件,当向远程服务器推送的时候也会执行这个操作。自己可以执行 git gc 主动触发这一操作 详细解答可以看: https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E5%8C%85%E6%96%87%E4%BB%B6