Git似乎存储整个文件而不是diff,如何避免?

时间:2017-01-05 10:42:26

标签: git

我在git repo中有一个“大”(5 mb)文本文件。 如果我在最后一行添加一个字符并运行git add我的.git文件夹大小增加大约1 mb(我假设是我的5 mb文件的压缩大小)。

每次编辑和添加都会发生同样的情况。

如果我运行git add -p file,我只能获得几个字节的差异。但无论如何,当我完全填充添加内容时,会存储大对象文件。

运行git gc --prune=now会删除大对象文件,但事情似乎仍按预期工作。

但是每次添加后经常运行git gc并不是一个好选择,因为我在SD卡上以自动方式使用git,这会耗尽卡写入并以这种方式删除兆字节。

所以,我的问题是

1)我是对的,这是git的行为吗?还是我误解了什么?

2)我可以避免这种情况并让git只保存差异吗?

我没有办法在恢复旧的更改等方面获得灵活性。不需要分支或存储或其他可能使git生活复杂化的事情。

修改 为了清楚起见,我的问题不是git将整个文件保存一次。但它存储了每个编辑的整个文件。如果我在每个字符编辑之间添加和提交10个字符,它会将整个文件(压缩格式)保存10次。

3 个答案:

答案 0 :(得分:4)

Git将所有文件存储为"对象" (具体来说,作为 blob对象,blob是Git中四种可能的对象类型之一)。但这不是全部。

每个对象由其内容唯一标识。对象的内容被转换为加密哈希(具体来说,SHA-1,原始内容以对象类型为前缀 - 在本例中为blob - 以及其大小的十进制表示形式(以字节为单位)和单个ASCII NUL字节,后跟实际的对象字节)。因此,如果您多次添加完全相同的文件,则会获得相同的哈希值,因为原始内容保持不变 - 但如果您更改了单个字节,则会获得一个新对象,新的和不同的哈希。

这就是你的存储库增长大约1 MB的原因:正如你猜测的那样,1 MB是压缩的5 MB对象的大小。一个字节是不同的,因此新对象具有新的ID并存储为新的"松散的"宾语。松散的对象由压缩的对象和标题组成,存储在它自己的单独文件中......但并非所有对象都是松散的。 Git还提供压缩的对象。

打包的对象要复杂得多。存储在包中的对象是" deltified":使用Git的特殊修改变体libXdiff进行压缩(另请参阅Is the git binary diff algorithm (delta storage) standardized?)。 Git选择基础对象和一系列派生对象,然后针对基础进行压缩。运气好的话,你的文件会被自己压缩,所以一旦打包,它们会回到相对较小的位置,除了基本文件本身。

Git通常会选择何时自行创建包文件,而其通常的代码可以很好地处理大多数普通的源文件。非常大的文本文件会在某种程度上使自动打包失去平衡,因此您可能希望尝试使用"手工打包" (使用偶尔git repack -a -d和/或调整窗口参数)来查看是否可以获得更好的结果。但请注意,除了"瘦身"用于通过网络连接发送增量,包文件要求基础对象与所有已经完成的对象存在于同一个包中。如果您的大文件经常更改,经常打包会适得其反,因为您将获得许多大包(尽管-a -d步骤应该整合包,只要您不使用"保持&#34 ;文件在他们身上。)

(如果您修改文件的工作树版本并git add结果并获得新哈希,Git会立即将其打包为松散对象,而不管任何现有的打包版本。)< / p>

答案 1 :(得分:0)

所有源控制系统的常见问题。它们意味着来存储他们可以解析为文本的代码。任何不是文本的东西都不会以差异方式存储。无法识别的文件只是上传。作为一个在工作中维护多个存储库的人,我通过上传大文件,然后移动或重新上传来处理能够将存储库大小增加到千兆字节的用户。

答案 2 :(得分:0)

您可以看到 documentation here

<块引用>

事实证明它可以。 Git 在磁盘上保存对象的初始格式称为“松散”对象格式。但是,有时 Git 会将这些对象中的几个打包到一个称为“packfile”的二进制文件中,以节省空间并提高效率。 如果您周围有太多松散的对象,如果您手动运行 git gc 命令,或者如果您推送到远程服务器,Git 会执行此操作。要查看会发生什么,您可以通过调用 git gc 命令手动要求 Git 打包对象:

所以,这个不用担心,git会打包你的文件,只有在对象太多时才会自动保留差异以节省磁盘空间。此外,您可以手动运行 git gc