为什么git会推送如此多的数据?

时间:2016-01-15 21:19:52

标签: git

我想知道git在推动变化时做了什么,以及为什么它似乎偶尔会推动更多的数据而不是我所做的改变。我对两个增加了大约100行代码的文件进行了一些更改 - 不到2k的文本,我想象。

当我将数据推送到原点时,git将其转换为超过47mb的数据:

git push -u origin foo
Counting objects: 9195, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6624/6624), done.
Writing objects: 100% (9195/9195), 47.08 MiB | 1.15 MiB/s, done.
Total 9195 (delta 5411), reused 6059 (delta 2357)
remote: Analyzing objects... (9195/9195) (50599 ms)
remote: Storing packfile... done (5560 ms)
remote: Storing index... done (15597 ms)
To <<redacted>>
 * [new branch]      foo -> foo
Branch foo set up to track remote branch foo from origin.

当我区分我的更改时,(origin / master..HEAD)只显示了两个文件和一个提交。 47mb的数据来自哪里?

我看到了这个:When I do "git push", what do the statistics mean? (Total, delta, etc.) 而这:Predict how much data will be pushed in a git push 但那并没有真正告诉我发生了什么......为什么包/捆绑会很大?

2 个答案:

答案 0 :(得分:5)

我刚刚意识到非常现实的情况会导致非常大的推动。

推送什么对象发送?服务器上尚不存在。或者,而不是它现有的检测。它如何检查对象的存在?在推送开始时,服务器发送有的引用(分支和标签)。因此,例如,如果他们有以下提交:

QTcpSocket* socket = new QTcpSocket();
socket->setSocketDescriptor(socketDesc); // socketDesc is a point of  type   qintptr 

然后客户端将获得类似 CLIENT SERVER (foo) -----------> aaaaa1 | (origin/master) -> aaaaa0 (master) -> aaaaa0 | | ... ... 的内容,并发现它必须仅发送提交/refs/heads/master aaaaa0中的新内容。

但是,如果有人将任何东西推到了远程掌握,那就不同了:

aaaaa1

此处,客户端获取 CLIENT SERVER (foo) -----------> aaaaa1 (master) --> aaaaa2 | / (origin/master) -> aaaaa0 aaaaa0 | | ... ... ,但它对aaaaa2 一无所知,因此无法推断服务器上存在refs/heads/master aaaaa2。因此,在这个只有2个分支的简单情况下,将发送整个历史记录,而不是仅增加历史记录。

这不太可能发生在成长,积极开发,项目,其中有标签和许多分支,其中一些变得陈旧,不会更新。因此,用户可能会发送更多信息,但它并没有像您的情况那样变得那么大,并且没有任何损失。但是在非常小的团队中,它可以更频繁地发生,而差异将是巨大的。

为避免这种情况,您可以在推送之前运行aaaaa0。然后,在我的示例中,git fetch提交已存在于客户端,而aaaaa2会知道它不应发送git push foo及更早的历史记录。

阅读here以了解协议中的推送实现。

PS:最近的git commit graph功能might help with it,但我没有尝试过。

答案 1 :(得分:3)

  

当我将数据推送到原点时,git将其转换为超过47mb的数据..

看起来您的存储库包含大量二进制数据。

首先让我们看看git push会做什么?

  

git-push - 更新远程引用以及关联对象

那些associated objects是什么?

每次提交后,你都会把git执行pack个数据到名为的文件中 XX.pack&amp;&amp; `XX.idx'

有关包装的好读物是here

enter image description here

git pack文件如何?

  

打包存档格式.pack旨在自包含,以便在没有任何进一步信息的情况下解压缩。
  因此,delta所依赖的每个对象必须存在于包中。

     

生成包索引文件.idx,以便快速随机访问包中的对象。

     

将索引文件.idx和压缩存档.pack放在pack的{​​{1}}子目录(或$GIT_OBJECT_DIRECTORY上的任何目录)中Git从包存档中读取。

当git打包你的文件时,它会以智能的方式完成它,因此它将非常快速来提取数据。

为了实现这个git,使用pack-heuristics基本上在你的包中寻找类似的内容部分并将它们存储为单个内容,这意味着 - 如果你有许多相同的标题(例如许可协议)文件,git将“找到”它并将存储一次。

现在,包含此许可证的所有文件都将包含指针到标头代码。在这种情况下,git不必反复存储相同的代码,因此包大小很小。

这是为什么它不是一个好主意并且不建议在git中存储二进制文件的原因之一,因为具有相似性的可能性非常低,因此包大小将不是最佳的。

Git以压缩格式存储您的数据以减少空间,因此再次二进制文件也不是最佳的,因为压缩(大小为wize)。

以下是使用压缩压缩的git blob示例:

enter image description here