解释 Git 中的 BLOB 对象和树对象。
Git 使用一系列 BLOB 和树对象来存储项目工作目录的内容。每当我们执行提交操作时,Git 内部会创建一系列树和 BLOB,这是项目文件夹结构在提交时的二进制表示。
什么是 BLOB?
BLOB 代表 **Binary Large Object**(大型二进制对象)。Git 中每个版本的档案都表示为一个 BLOB。BLOB 保存档案的数据,但不包含任何关于档案的元数据,甚至不包含档案名称。
为了理解 BLOB,让我们来看一个例子。
创建 3 个文本文件:“file1.txt”、“file2.txt” 和 “file3.txt”。前两个文件将包含相同的内容,而第三个文件将有不同的内容。
$ git init // initialize a repo $ echo hello>file1.txt // create a file and enter some content $ echo hello>file2.txt // create a file and enter the same content $ echo hello world>file3.txt // create a file and enter some content
让我们将这些文件添加到暂存区。暂存这些文件将在“.git\objects”文件夹下创建 BLOB。在这个例子中,我们每次暂存文件时都会列出“.git\objects”文件夹中的内容。
$ git add file1.txt // stage the file $ ls .git/objects/ // list contents $ git add file2.txt $ ls .git/objects/ $ git add file3.txt $ ls .git/objects/
ls 命令的输出如下所示。
dell@DESKTOP-N961NR5 MINGW64 /e/tut_repo (master) $ git add filel.txt dell@DESKTOP-N961NR5 MINGW64 /e/tut_repo (master) $ Is .git/objects/ ce/ info/ pack/ dell@DESKTOP-N96LNR5 MINGW64 /e/tut_repo (master) $ git add file2.txt dell@DESKTOP-N961NR5 MINGw64 /e/tut_repo (master) $ Is .git/objects/ ce/ info/ pack/ dell@DESKTOP-N961NR5 MINGW64 /e/tut_repo (master) $ git add file3.txt dell@DESKTOP-N961NR5 MINGW64 /e/tut_repo (master) $ Is .git/objects/ 3b/ ce/ info/ pack/
当“file1.txt”和“file3.txt”被暂存时,创建了名为“ce”和“3b”的文件夹。但是,当“file2.txt”被暂存时,没有创建新的文件夹。这是因为“file1.txt”和“file2.txt”的内容相同。
现在让我们看看“ce”和“3b”文件夹的内容。
$ ls .git/objects/ce $ ls .git/objects/3b
输出显示这些文件夹包含表示为 SHA1 哈希的 BLOB 对象。
dell@DESKTOP-N961NRS MINGW64 /e/tut_repo (master) $ Is .git/objects/ce 013625030ba8dba906f756967f9e9ca394464a dell@DESKTOP-N961NR5 MINGW64 /e/tut_repo (master) $ Is .git/objects/3b 18e512dba79e4c8300dd08aeb37f8e728b8dad
现在让我们验证文件的类型及其内容。
$ git cat−file −t ce01 $ git cat−file −p ce01 $ git cat−file −t 3b18 $ git cat−file −p 3b18
从输出中可以看出,尽管我们添加了 3 个文件,但 Git 创建了 2 个 BLOB。这是因为前两个文件的内容相同。从输出中可以看出,BLOB 只存储文件的內容,而不存储文件名。
//output of cat−file −t ce01 blob //output of cat−file −p ce01 hello //output of cat−file −t 3b18 blob //output of cat−file −p 3b18 hello world
什么是树?
树就像一个目录。Git 中的每个提交都指向一个树对象,该对象又引用 BLOB。树对象记录以下内容:
BLOB 标识符
路径名称
该目录中所有文件的元数据
树可以递归地引用其他树对象或子树。因此,树构建了文件和子目录的完整层次结构。就像 BLOB 一样,树也可以在“.git/objects”文件夹下查看。
让我们通过之前的例子来理解树。我们创建了三个文件并将它们全部添加到暂存区。让我们使用**git status**命令来验证这一点。让我们也将所有更改提交到存储库。
$ git status -s // verify status $ git commit -m 'initial commit' // commit to the repo
状态指示已暂存 3 个文件。发出 git commit 命令后,将创建一个哈希值为“84a00db”的提交。
dell@0ESKTop-N961NR5 MINGW64 /e/tut_repo (master) $ git status -s A fiIe1.txt A file2.txt A file3.txt dell@DESKTOP-N961NR5 MINGW64 /e/tut—repo (master) $ git commit -m 'initial commit' [master (root-commit) 84aOOdb) initial commit 3 files changed, 3 insertions(+) create mode 100644 file1. txt create mode 100644 file2. txt create mode 100644 file3.txt
我们例子的内部结构可以表示如下:
上图显示提交“84a0”指向一个树,它是项目的根文件夹。根文件夹有 3 个作为 BLOB 存储的文件。前 2 个文件指向同一个 BLOB,因为它们的内容相同。树对象保存对所有 BLOB 的引用。如果我们在当前项目中创建新的文件夹,则这些文件夹将作为根项目树“e115”的子树创建。
让我们验证 objects 文件夹以查看是否创建了任何提交对象或树对象。这可以使用 ls 命令来查看。
$ ls .git/objects $ ls .git/objects/84 $ ls .git/objects/e1
输出显示文件夹“84”表示一个提交,“e1”将是与其关联的树。这些文件夹有一个由 SHA1 哈希表示的指针文件。
dell@DESKTOP-N961NR5 MINGW64 /e/tut_repo (master) $ Is .git/0bjects/84 aOOdb87bb5c69926b3343a564db1b3a96a389d dell@DESKTOP-N961NR5 MINGW64 /e/tut_repo (master) $ Is .git/objects/el 1588b4a639bb90b18268b7e26f243ba31706fd
现在让我们使用**cat-file**命令验证这些指针文件中的内容。
$ git cat−file −p 84a0 $ git cat−file −p e115
从输出中可以看出,提交 (84a0) 指向一个树,它是项目的根文件夹。
tree e11588b4a639bb90b18268b7e26f243ba31706fd author Kiran 1612777422+0530 committer Kiran 1612777422+0530 initial commit
项目的根文件夹包含三个作为 BLOB 存储的文件。
dell@DESKTop-N961NR5 MINGW64 /e/tut_repo (master) $ git cat −file −p e115 100644 blob ce013625030ba8dba906f756967f9e9ca394464a file1.txt 100644 blob ce013625030ba8dba906f756967f9e9ca394464a file2.txt 100644 blob 3b18e5L2dba79e4c8300dd08aeb37f8e728b8dad file3.txt