我正在学习git的内部知识以及git对象模型如何“在幕后”工作。
如果我更改一些文件并将其提交到本地git存储库中,则将创建一个新的git commit object
。每个提交对象都有关联的tree object
。每个树对象都包含它指向的文件(blob)的SHA1。那么,这是否意味着每个新的提交(假设其中有一些文件更改)总会生成一个新的树对象(即使它指向文件系统上的同一目录,它的SHA1与之前的所有树都不同)?>
我的解释是否正确?
另外,是否可以在不更改文件的情况下提交?在那种情况下,不需要新的tree object
,但我不知道git中是否可以进行这种类型的提交。
答案 0 :(得分:4)
我的解释是否正确?
实际上-是-但请参见下文
还可以在不更改文件的情况下进行提交吗?在那种情况下,就不需要新的树对象,但是我不知道在git中是否可以进行这种类型的提交。
@Lasse已经提到git commit --allow-empty
作为重用 last 树的一种方式,但这是一个非常不寻常的命令。当您只想修复最后的提交消息时,一个很常见的命令是git commit --amend
。
还请注意:现有树可以重用,并且这些树不必来自最后一次提交。常见的情况是git rebase --interactive
,只是重新编写提交消息(类似于git commit --amend
,但对于远离HEAD的提交)。
另一种情况:考虑此提交顺序:
commit 0
commit A
commit B
commit C
revert C # will reuse tree from B
revert B # will reuse tree from A
revert A # will reuse tree from 0
在这种情况下,老树也被重用。
下一个场景:git merge -s ours
(不要与git merge -X ours
混淆)将合并另一个分支,但忽略任何更改。换句话说:merge-commit和第一个父节点共享同一棵树。
用于做奇怪事情的瑞士军刀当然是git filter-branch
,在这里您可以用几种方式重写提交,但不影响树木。
答案 1 :(得分:2)
让我们一次迈出一步。
每次将文件添加到存储库时(通常是通过将其添加到索引然后提交),都会添加整个文件的快照。计算哈希值,该哈希值是此文件的标识符。
但是,如果您以5-6提交,则设法将文件内容恢复到以前的状态,则其新哈希将已存在于存储库中,因此不会添加任何其他文件。取而代之的是,凡是要引用此文件的内容都将使用哈希,因此将引用“旧”文件。
树对象只是文本文件,其中包含目录中文件的哈希以及标识子树(子文件夹)的哈希。树对象的哈希也从树的内容中计算得出,因此取决于文件的哈希和子树的哈希。
换句话说,在上述还原文件的场景中,如果最终将存储库中 all 文件的内容还原到上一次提交时的状态,新树的哈希将已经存在,并且不会添加任何 new 树对象。取而代之的是,无论引用什么树,最有可能的提交都将使用哈希并引用“旧”树。
在大多数情况下,这可能有点理论化。最终将所有文件恢复到较旧状态的情况可能不是经常遇到的情况。因此,实际上,每次创建提交时,您很有可能也会创建并添加一个或多个新的树对象。
要添加没有文件更改的提交(称为“空提交”),可以使用以下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
答案 2 :(得分:0)
如果树的内容(目录具有相同的名称和布局,文件具有相同的名称和相同的内容)与以前的修订版相同,则该树将是“重复的”,因此它是teo指向同一棵树的修订