首页 > 解决方案 > 每次提交都会在 git 中创建一个新的树对象吗?

问题描述

我正在学习 git 内部结构以及 git 对象模型如何“在幕后”工作。

如果我更改了一些文件并将其提交到本地 git 存储库中,那么commit object将创建一个新的 git。每个提交对象都与之关联tree object。每个树对象都包含它指向的文件(blob)的 SHA1。那么这是否意味着每个新的提交(假设其中有一些文件更改)总是会生成一个新的树对象(即使它们指向文件系统上的同一目录,它也将具有与所有以前的树不同的 SHA1)?

我对此的推理是否正确?另外,是否可以在不更改文件的情况下提交?在那种情况下,就不需要新的了tree object,但我不知道这种类型的提交在 git 中是否可行。

标签: git

解决方案


让我们一步一步来。

每次将文件添加到存储库时,通常通过将其添加到索引然后提交,都会添加整个文件的快照。计算一个哈希值,这个哈希值就是这个文件的标识符。

但是,如果您 5-6 次提交,设法将文件内容恢复到以前的状态,则其新哈希将已存在于存储库中,因此不会添加其他文件。相反,任何要引用这个文件的东西都将使用散列,但因此引用“旧”文件。

树对象只是包含目录中文件哈希值的文本文件,以及标识子树(子文件夹)的哈希值。树对象的哈希值也是根据树的内容计算的,因此取决于文件的哈希值和子树的哈希值。

换句话说,在我们恢复文件的上述场景中,如果我们最终将存储库中所有文件的内容恢复到它们在先前提交中的状态,那么新树的哈希将已经存在并且不会将添加新的树对象。相反,任何将引用该树的东西,最有可能的提交,将使用哈希并引用“旧”树。

在大多数情况下,这可能有点理论化。您可能不会经常遇到最终将所有文件恢复到某个较旧状态的情况。因此在实践中,每次创建提交时,您很可能还会创建并添加一个或多个新的树对象。

要添加不更改文件的提交,称为“空提交”,您可以使用以下 git 命令:

git commit --allow-empty

您可以-m "message"像往常一样添加类似或类似的东西。

这是一个例子:

λ git init .
Initialized empty Git repository in D:/Temp/.git/

λ echo a >test.txt                                                             
λ git add .                                                                    
λ git commit -m test1                                                          
[master (root-commit) dc613fe] test1                                           
 1 file changed, 1 insertion(+)                                                
 create mode 100644 test.txt                                                   

λ git commit -m test2 --allow-empty                                            
[master c197192] test2                                                         

λ git lg                                                                       
* c197192: (7 seconds ago) test2 (HEAD -> master)                              
| Lasse Vågsæther Karlsen <lasse@vkarlsen.no> (Sat, 20 Apr 2019 23:28:44 +0200)
|                                                                              
* dc613fe: (17 seconds ago) test1                                              
  Lasse Vågsæther Karlsen <lasse@vkarlsen.no> (Sat, 20 Apr 2019 23:28:34 +0200)

现在,如果我输出这两个提交的内容:

λ git cat-file -p c197192
tree 35b422a71005d59dd6af858a3425b608b63f7b5a
parent dc613fe57276009b399d8152a657cb971fad605a
author Lasse Vågsæther Karlsen <lasse@vkarlsen.no> 1555795724 +0200
committer Lasse Vågsæther Karlsen <lasse@vkarlsen.no> 1555795724 +0200

test2

λ git cat-file -p dc613fe
tree 35b422a71005d59dd6af858a3425b608b63f7b5a
author Lasse Vågsæther Karlsen <lasse@vkarlsen.no> 1555795714 +0200
committer Lasse Vågsæther Karlsen <lasse@vkarlsen.no> 1555795714 +0200

test1

您可以看到它们都引用了完全相同的树对象,如下所示:

λ git cat-file -p 35b422a71005d59dd6af858a3425b608b63f7b5a
100644 blob f5eea678d87a8664e4c76e12d3ef5c4ff775ad58    test.txt

推荐阅读