git如何处理文件删除和重新添加?
我想知道git如何处理文件操作。假设我删除了FileA,在两次提交之后,我将同一个文件重新添加到同一路径。FileA是存储为git历史记录中的新文件副本,还是之前存在的两次提交将链接到当前提交?如果FileA发生轻微变化,会发生什么情况?tl;dr Git将文件内容与文件名分开存储。如果内容相同,它将重用现有内容。如果它被稍微修改,它将存储一个新的副本。它会定期将内容更改存储在packfile中 当Git存储一个文件时,它将其存储在两个对象中git如何处理文件删除和重新添加?,git,Git,我想知道git如何处理文件操作。假设我删除了FileA,在两次提交之后,我将同一个文件重新添加到同一路径。FileA是存储为git历史记录中的新文件副本,还是之前存在的两次提交将链接到当前提交?如果FileA发生轻微变化,会发生什么情况?tl;dr Git将文件内容与文件名分开存储。如果内容相同,它将重用现有内容。如果它被稍微修改,它将存储一个新的副本。它会定期将内容更改存储在packfile中 当Git存储一个文件时,它将其存储在两个对象中 树 blob(二进制大对象) 该树基本上是一个目录列
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 somefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 somedir
然后将压缩后的文件内容存储在blob中。如上所述,somefile
的内容存储在bloba906cb2a4a904a152e80877d4088654daad0c859
中
如果您有两个具有相同内容的文件,Git将对这两个文件使用相同的blob
如果您git rm somefile
并提交,git将创建一个没有该文件的新树,并将其附加到提交。因为它被早期提交中的早期树引用,所以blob将继续存在
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 somedir
如果您使用与旧文件相同的内容添加新文件,git将重用相同的blob
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 newfile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 somedir
如果FileA稍微更改,会发生什么情况
Git将存储一个包含新文件完整内容的新blob对象
100644 blob 8f94139338f9404f26296befa88755fc2598c289 somefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 somedir
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
(垃圾收集)后,git用更高效的包文件替换了单个对象文件。当你说“delete-FileA”时,你的意思是git-rm-FileA
?当你说“将相同的文件读取到相同的路径”时,你的意思是说git add FileA
并且FileA具有相同的内容?是的。相同的文件或稍有修改。或者回答OP的特定问题:“Git将在提交前重复使用2次提交的文件”(+1)@knittl,这要简洁得多。如果在提交n次后重复,是否也是如此?@OHLÁLÁ是的,Git完全是本地的,必须在每次提交中存储所有文件的完整内容。也有一些例外,比如浅层克隆和克隆。Git对此进行了优化,它只能存储更改之间的增量。