git标签的存储效率低下吗?

Cra*_*ing 6 git

我想知道git标签的存储是否效率低下.

我认为标签只是指向变更集的"指针",它应该非常高效且在磁盘使用方面很小.

但是,使用我的新git存储库:

  1. 推动所有分支(8)和所有变更集(20489)在一起~110MB(在Gitlab中显示)
  2. 推送没有添加任何额外变更集(仍然是20489)的所有标签(1444)突然合在一起~150MB

这很奇怪.我之所以没有想到这么大的增长只是因为"指针".

有没有人有任何线索或可能的解释?

谢谢

tor*_*rek 5

TL; DR

标签通常非常有效.正如ElpieKay在评论中总结的那样,你必须拥有一些对象 - 可能是提交,但任何对象都可以 - 可以从标签访问,但不能从分支访问.

标签 - 无论是轻量级还是带注释; 我们将在瞬间将这些区分为任意Git对象,而不是变更集.当我们说点到这里,我们真正的意思是包含的哈希ID:所有的Git对象有,作为他们的"真名",用作在关键的哈希ID key-value存储所有的Git对象.

这个主Git数据库中有四种类型的对象.它们是提交,,blob和带注释的标记对象.提交充当快照,但它们本身只包含少量元数据,包括提交者的名称和电子邮件地址以及时间戳; 提交的提交的哈希ID,日志消息和存储的对象的哈希ID .树对象最终通过子树和blob对象提供快照.

名称 - Git将引用refs -fall 调用到各种名称空间.两个大的有分支的名字一样master,这实际上是在refs/heads/*名称空间(refs/heads/master)和标签名称一样v1.2,这实际上是在refs/tags/*名称空间(refs/tags/v1.2).即使名称拼写相同,名称空间也不会使名称发生冲突.每个名称包含一个哈希ID,name-to-hash-ID键值存储是构成Git存储库的另一个主要数据库.

分支名称被约束为仅指向提交对象.标记名称可以直接指向提交对象.这种标签称为轻量标签.或者,标记名称可能指向带注释的标记对象.该对象本身指向一些其他(任意)对象,尽管标记名称指向提交非常典型.指向带注释的标记对象的标记名称是带注释的标记.

对象数据库形成有向非循环图

提交包含,即指向其他提交哈希ID.一旦对象生成就无法更改,并且无法预测任何对象的哈希ID.1 因此,新提交只会指向现有的提交.每个提交也被赋予唯一的哈希ID(即,不会多次提交任何提交).这意味着提交图本身通常一次增加一个提交,从来没有任何周期:所有提交箭头"指向后"到先前的提交.

提交还包含树形哈希ID,树包含更多树哈希ID以及blob哈希ID.这些也是有向和非循环的,尽管树形散列ID不必是唯一的(例如,两个不同的提交可以共享相同的快照).

带注释的标记对象可以包含任何其他对象的ID,但是像提交一样,带注释的标记对象具有唯一的哈希ID,并且只允许指向现有对象.因此,这些同样不会向图表添加循环.


1哈希ID是对象内容的加密校验和,包括对象的类型.从技术上讲,如果您在问题上花费了足够的计算能力,就可以预测,或者可能产生故意的哈希冲突.但是,Git也禁止以其他方式进行循环.


名称数据库充当DAG的入口点,允许垃圾回收

结果是,如果我们选择存储库中的任何对象,我们可以从该对象跟踪所有可到达的其他对象并获得子图.如果我们使用名称数据库(分支和标记名称以及所有其他Git引用 - 有一些特别是偷偷摸摸的,例如存储在索引中的blob哈希ID)作为我们的入口指向对象数据库,并将所有可到达的对象着色为绿色暂时,我们可以让Git遍历整个对象数据库并丢弃任何无法访问的对象(然后删除着色,Git实际上是在内存中保存,而不是在磁盘上).

到达设定的目标,然而,取决于我们使用的名称!如果我们省略所有标记名称,我们可能会有一些对象 - 通常是一些提交链 - 否则无法访问.

获取和推送仅复制可到达的对象

作为一般规则,git fetch和-copies git push初始提取git clone只运行那些可以从正在使用的名称访问的对象.转移中涉及的两个Git实例具有初始对话,其中每个Git在读取一些名称/ ID对之后告诉另一个其具有和/或想要的哈希ID.2 发送和接收Git实例根据需要遍历对象DAG,以确定完成这些名称/ ID对所需的对象.然后发件人发送对象; 3接收Git将这些对象添加到其对象数据库,并完成传输.

在您的情况下,这意味着某些对象只能从标签访问,这使得推送量显着增大.找到这些对象可以是一个有点棘手,Git有低级别的工具,这(git rev-parsegit branch --contains,例如),但没有干净地包装成一个面向用户的解决方案.


2新的有线协议(v2-旧的v0与v1相同) - 改变了列出名称/ ID对的方式,因为事实证明在某些存储库中,名称数据库已经增长到了简单地每次列出所有内容,如v0所做的,花费的时间太长.

3发送Git通常使用其接收 Git对象数据库中的内容(由接收方必须具有的哈希ID确定)来构建一个瘦包,其中发送方的对象针对接收方已有的对象进行增量压缩.请参阅下面的压缩.


压缩一边

这两个键值数据库都以多种不同的方式存储在Git中.对象数据库中的对象可以是松散的,它们是zlib-deflated但是独立的,或者是打包的,它们是针对其他对象进行增量压缩的.Delta链的作用就像变更集一样,但存在一个关键的区别 - 对实现者来说至关重要; 用户根本不需要关心它! - 其中:任何对象至少在理论上可以压缩任何其他对象,甚至是不同类型的对象.(实际上,Git只会针对相同类型的对象压缩对象.)即使blob压缩blob,也不要求某个文件是针对同一文件的先前版本的增量:它可能是未来版本的delta相同的文件,或不同文件的当前版本,或其他.

包文件通常是自包含的:在包文件中进行增量压缩的对象必须在同一包文件中的链中提供下一个对象,一直到本身不是delta压缩的基础对象.该薄包git fetchgit push建立蓄意违反这个假设; 瘦包的接收者有义务"修复"它(git index-pack --fix-thin)或以其他方式纠正问题.但所有这些都是内部细节.


Ben*_*Ben 3

您的提交只能通过标签访问。如果你查看你的历史记录,git log --decorate --oneline --graph --all你可以看到它们。

查找在标签中“结束”的历史行:

* 4d60a50b0 (HEAD -> master, origin/master, origin/HEAD) Latest commit
* 123d19df2 More Stuff
* 158f2091b Removed bogus quote.
| * 413d140f4 (tag: 6.4.1_76119) line endings
| * c3fa7ee03 getting the branch to autobuild and make installer
| |  * bda836a25 (tag: 7.0.0) more credits changes 
| |  * 3cab6e792 for autobuilds, launch seed7.0.0 so it gets the branch
| |_/  
|/|   
* | 11b2165f5 formatting
* | 4af66cc59 changed version numbers to 7.0.0 
Run Code Online (Sandbox Code Playgroud)