git如何处理文件删除和重新添加?

我想知道 git 如何处理文件操作。假设我删除了 FileA 并在两次提交后将同一文件重新添加到同一路径。FileA 将作为新文件副本存储在 git 历史记录中还是存在,之前的两次提交将链接到当前提交?如果 FileA 稍有更改,会发生什么情况?

回答

tl;dr Git 将文件的内容与文件名分开存储。如果内容相同,它将重用现有的内容。如果它稍有修改,它将存储一个新副本。它将定期仅存储包文件中的内容更改。

当 Git 存储一个文件时,它会将它存储在两个对象中。

  1. 那个树
  2. blob(二进制大对象)

该树基本上是一个目录列表。它包含文件和目录的名称、它们的权限、它是什么类型的对象(blob 或树)以及它们的对象的 ID。

100644 blob a906cb2a4a904a152e80877d4088654daad0c859      somefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      somedir

然后它将压缩的文件内容存储在 blob 中。上面说的内容somefile存储在 blob 中a906cb2a4a904a152e80877d4088654daad0c859

如果您有两个内容相同的文件,Git 将对这两个文件使用相同的 blob。

如果您git rm somefile并提交 Git 将创建一个没有文件的新树并将其附加到提交中。由于它在较早的提交中被较早的树引用,因此 blob 将继续存在。

040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      somedir

如果您git add newfile的内容与旧的相同,Git 将重用相同的 blob。

100644 blob a906cb2a4a904a152e80877d4088654daad0c859      newfile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      somedir

如果 FileA 稍有更改,会发生什么情况?

Git 将存储一个新的 blob 对象,其中包含新文件的完整内容。

100644 blob 8f94139338f9404f26296befa88755fc2598c289      somefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      somedir

Git 最终将通过将所有单个对象放入只能存储增量的包文件来优化这一点。

有关更多信息,请参阅Pro Git 中的 Git 对象。


这是一个快速演示。

$ echo 'Basset hounds got long ears' > FileA
$ git add FileA
$ git commit -m First
[main (root-commit) af9df46] First
 1 file changed, 1 insertion(+)
 create mode 100644 FileA
$ git hash-object FileA
34f45be4cebdae4cf67218bd47df88dcd9a4cdc6
$ tree .git/objects/
.git/objects/
??? 34
?   ??? f45be4cebdae4cf67218bd47df88dcd9a4cdc6
??? af
?   ??? 9df4604a35039b68625b8283d7b36fb0409136
??? e5
?   ??? d8ddccedc871c546b4f6bf0e316165786c62ba
??? info
??? pack

5 directories, 3 files

af9df46 是提交对象。e5d8dcced 是树对象。34f45be4ce 是包含 FileA 内容的 blob 对象。

$ git rm FileA
rm 'FileA'
$ git commit -m Second
[main 3bcbfae] Second
 1 file changed, 1 deletion(-)
 delete mode 100644 FileA
$ tree .git/objects/
.git/objects/
??? 34
?   ??? f45be4cebdae4cf67218bd47df88dcd9a4cdc6
??? 3b
?   ??? cbfae6e607ef605b572f2b88ea21ad021b030b
??? 4b
?   ??? 825dc642cb6eb9a060e54bf8d69288fbee4904
??? af
?   ??? 9df4604a35039b68625b8283d7b36fb0409136
??? e5
?   ??? d8ddccedc871c546b4f6bf0e316165786c62ba
??? info
??? pack

7 directories, 5 files

3bcbfae6 是第二个提交对象。4b825dc 是新的树对象。请注意,34f45be4ce blob 仍然存在。

$ echo 'Basset hounds got long ears' > FileB
$ git add FileB
$ git hash-object FileB
34f45be4cebdae4cf67218bd47df88dcd9a4cdc6
$ git commit -m Third
[main 9ba46ad] Third
 1 file changed, 1 insertion(+)
 create mode 100644 FileB
$ tree .git/objects/
.git/objects/
??? 34
?   ??? f45be4cebdae4cf67218bd47df88dcd9a4cdc6
??? 3b
?   ??? cbfae6e607ef605b572f2b88ea21ad021b030b
??? 4b
?   ??? 825dc642cb6eb9a060e54bf8d69288fbee4904
??? 9b
?   ??? a46ad12eab0a384ebae59aa46def2bbc2b7f0a
??? af
?   ??? 9df4604a35039b68625b8283d7b36fb0409136
??? c9
?   ??? 8f44c0bd58f45a14f0bb29b15acd4c1616b0dc
??? e5
?   ??? d8ddccedc871c546b4f6bf0e316165786c62ba
??? info
??? pack

9 directories, 7 files

我们添加了一个与 FileA 具有相同内容的不同文件。有一个新的提交对象,9ba46ad。一个新的树对象,c98f44c。但它使用相同的 blob,34f45be4。

$ git gc
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (10/10), done.
Total 10 (delta 0), reused 7 (delta 0), pack-reused 0
Windhund:test.git (main)$ tree .git/objects/
.git/objects/
??? info
?   ??? commit-graph
?   ??? packs
??? pack
    ??? pack-4e76192447fc323d1026ae980fdbda304b70a597.idx
    ??? pack-4e76192447fc323d1026ae980fdbda304b70a597.pack

2 directories, 4 files

运行git gc(Garbage Collection) 后,Git 将单个目标文件替换为更高效的包文件。

  • Or the answer the specific question of the OP: "Git will re-use the file from 2 commits before" (+1 nevertheless)

以上是git如何处理文件删除和重新添加?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>