说,我有一个包含内容的文件:
1111
2222
3333
然后我将其修改为:
1111
2222
4444
3333
Git 会生成一个新版本的新文件吗?我很困惑,如果它创建新文件,那么整个存储库的大小会增长得很快吗?
另一个想法是,Git 不会创建新文件,只是存储添加或删除行的位置,并存储新的行内容。
哪一个是正确的?
说,我有一个包含内容的文件:
1111
2222
3333
然后我将其修改为:
1111
2222
4444
3333
Git 会生成一个新版本的新文件吗?我很困惑,如果它创建新文件,那么整个存储库的大小会增长得很快吗?
另一个想法是,Git 不会创建新文件,只是存储添加或删除行的位置,并存储新的行内容。
哪一个是正确的?
许多较旧的源代码控制系统,例如 RCS 和 CVS,专门存储文件版本之间的差异。例如,给定源文件的信息可能以包括最新版本的全文以及用于生成早期版本的“说明”的形式存储在存储库中。
至少在概念上,Git 将每个文件的每个版本的全部内容存储在存储库中。它通过仅存储相同文件的一份副本来节省一些空间,因为用于存储它的名称是通过对内容进行散列确定的。
显然,如果这就是全部,Git 存储库将很快变得非常大。但是 Git 会自动打包或压缩存储的对象。坦率地说,我不知道所有细节,但它在最小化存储空间和允许快速重新创建任意版本方面做得很好。
例如,Git 源本身存储在 Git 存储库中,其中可能包含数千个不同的对象。所有文件的所有版本都存储在目录下.git/objects/pack
,该目录当前包含以下内容(清单是我系统上的克隆):
$ ls -l .git/objects/pack
total 48900
-r--r--r-- 1 kst kst 4196172 Mar 20 15:44 pack-0e69de7b7728ad0fde80423ded259dbff7760016.idx
-r--r--r-- 1 kst kst 36698393 Mar 20 15:44 pack-0e69de7b7728ad0fde80423ded259dbff7760016.pack
-r--r--r-- 1 kst kst 125896 Jun 30 22:17 pack-2848a675d3c196391f06cc7cdd6cebf67fb7119e.idx
-r--r--r-- 1 kst kst 3570770 Jun 30 22:17 pack-2848a675d3c196391f06cc7cdd6cebf67fb7119e.pack
-r--r--r-- 1 kst kst 178452 May 16 08:22 pack-bfd75de39dff6ac03adcc775f7b5715480b54637.idx
-r--r--r-- 1 kst kst 5292998 May 16 08:22 pack-bfd75de39dff6ac03adcc775f7b5715480b54637.pack
与早期系统(至少与我使用的早期系统)相比,Git 的不同之处在于,在较高级别上,存储库中所有文件的所有版本都完整存储,但压缩由单独的层提供.
Git 只是存储跨项目的内容更改。增量差异。在任何给定时间点,与某个先前文件相同的任何文件都被记录为指向描述该先前文件内容的对象的指针。它使用文件内容的散列来了解文件何时发生更改并查找与先前版本的匹配项,因此它不必多次存储相同的内容。
它还有一个简单的数据库,用于描述所有更改及其关系。
以下是有关如何组织存储库的一些文档:
https://www.kernel.org/pub/software/scm/git/docs/gitrepository-layout.html
关于节省空间的附加说明:Git 的大空间节省原来不是两次存储同一个文件。其他内容管理器不像 Git 那样使用指向文件版本的指针,这会在项目版本的生命周期内节省大量资金。由于项目的移动版本只有少数文件更改。
对于普通文件,git将它们存储为blob
对象,git将文件的每个版本存储为单独blob
的s。所以它们是分开存放的。这样做的好处是您可以非常快速地检查一些提交(而不是回溯并执行所有修补操作)。
对于存储库大小问题,git 提供了对象打包机制并自动(或根据您的需求)压缩数据。在大多数情况下,这不是一个大问题。