首页 教育培训 git 索引(git搜索引擎)

git 索引(git搜索引擎)

教育培训 2024-08-19 00:08:55 346 教育网

在上一篇文章中,我们了解了索引的基本概念,索引存储了所有文件和对象之间的关系以及所有文件的基本信息。在这篇文章中,我们将深入Git,从二进制的角度了解它的索引结构。

本文最初发表于某未具名网站,并由作者本人同步至知乎。转载时请注明原作者博客地址或本链接。谢谢你!

0x01

git 索引(git搜索引擎)

什么是Git索引?

这个问题我已经在之前的文章中回答过。为了方便阅读,本文再次解释一下Git索引:

Git索引是工作目录和项目存储库之间的暂存区域。有了它,您可以一起提交对内容的许多更改。如果创建commit,那么提交的就是当前索引(index)中的内容,而不是工作目录中的内容。

因此,只要执行gitadd,即使工作目录中的文件被误删除,文件也不会丢失,因为文件已经存储在Git对象中,并且使用索引来定位。

我们可以通过gitls-files--stage命令看到仓库中的每个文件及其对应的文件对象,也可以直接通过查看二进制索引文件来了解更多信息(虽然太硬核了)。

0x02

索引文件存储在.git/index中。git目录存放的是仓库中的所有文件,其他目录只是基于该目录重构的镜像。

.git/index是一个二进制文件。如果直接用文本编辑器打开,你会发现里面全是乱码。在Linux/MacOS中,我们可以使用hexdump以十六进制显示文件:

#hexdump-C.git/index000000004449524300000002000000345d456b72|DIRC.4]Ekr|00000010000000005d456b720000000000000000|.]Ekr...|000000200451c4fe000081a4000001f500000014|.Q..|0000003000000078d717f9f65d8c51afe074d2f9|.x.].Q.t.|00000040c799e3436ad172fd800a2e6769746967|.Cj.r.gitig|000000506e6f726500000000000000005c168881|没有.\。|00000060000000005bbda4c60000000001000004|.[.|00000070000e7481000081a4000001f500000014|.t...|00000080000002dd7a4eb6572137f46011ca256a|.zN.W!7.`.%j|00000090ba514cb71878f73a000c4348414e4745|.QL.x.更改|000000a04c4f472e6d640000000000005c16887e|LOG.md.\.~|000000b0000000005bf54cbf0000000001000004|.[.L.|.由于篇幅限制,只能显示一小部分。这部分包含有关.gitignore文件的元数据,这足以供我们分析。

1.索引识别符

索引标识符占据索引文件的前12个字节:

444952430000000200000034前四个字节为“DIRC”(0x44495243),指的是“DirCache”,用于标识该文件是否是合法的索引文件。中间四个字节包含索引。文件的版本。当前版本是“2”(0x00000002)。最后四个字节是一个32位无符号整数,标识索引中的文件数量。仓库中存储了52个文件,即文件数为52个(0x00000034)。

2.状态数据

此部分存储与文件关联的状态。在分析之前,我们首先在Linux下对.gitignore文件运行stat命令:

#stat-fmtime=%mctime=%c.gitignore|tr\nmtime=1564830578ctime=1564830578#stat-t%FT%T.gitignore012957369598-rw-r--r--1lurenjiasworld工作人员0120'2019-08-03T21:17:23''2019-08-03T19:09:38''2019-08-03T19:09:38''2019-08-03T19:09:33'409680.gitignore了解stat命令的输出将有助于我们后续的分析。

2.164位文件创建时间

索引标识符的接下来8个字节包含文件的创建时间,即“2019-08-03T19:09:38”或“1564830578”(0x5d456b7200000000),因为MacOS使用的HFS+文件系统不支持纳秒精度时间戳。因此最后四个字节设置为0以确保与其他文件系统的兼容性。

2.264位文件修改时间

创建时间之后存储的是文件修改时间,即“2019-08-03T19:09:38”或“1564830578”(0x5d456b7200000000)。其格式与创建时间相同。

2.3存储设备编号与inode编号

设备号和inode号各占4个字节。前四个字节是设备号。由于MacOS不支持设备编号,因此它们被设置为0(0x00000000)。最后四个字节是索引节点号,溢出位被修剪:

原始索引节点号:`00030451c4fe`-0000000000000011|0000010001010001|1100010011111110存储在Git索引中的Inode编号:`0451c4fe`-0000010001010001|11000100111111101100010011111110这可能会让读者感到非常困惑。为什么不直接使用64位inode号呢?但实际上Git中inode号的唯一作用就是检测文件是否被修改,所以使用64位inode号意义不大。您可以参考以下相关代码来了解其唯一用途。

read-cache.c更多源代码

sd-sd_mtime.nsec=ST_MTIME_NSEC(*st);sd-sd_dev=st-st_dev;sd-sd_ino=st-st_ino;sd-sd_uid=st-st_uid;改变|=OWNER_CHANGED;if(sd-sd_ino!=(unsignedint)st-st_ino)已更改|=INODE_CHANGED;}

2.432位文件模式

接下来的四个字节是文件模式。从前面的统计我们可以知道文件模式是-rw-r--r--,八进制就是100644(0x000081a4)。

2.532位所属用户UID

接下来的四个字节是用户UID。在MacOS中执行id-u命令,获取当前用户UID为501(0x000001f5),与索引一致。

2.632位所属用户组

接下来的四个字节是其所属的用户组。在MacOS中执行id-g命令,获取当前用户GID为20(0x00000014),也与索引一致。

2.732位文件大小

接下来的四个字节是文件大小。从stat中可以看到文件大小为120字节(0x00000078),与索引一致。

2.8160位SHA-1格式对象ID

接下来的20个字节是该文件对应的Git对象文件的SHA-1哈希值,即.gitignore文件的ID。可以通过gitls-files--stage检索此ID,如#0x01命令获取中所述。

2.916位对象状态

接下来的两个字节1000000000001010(0x800a)包含了很多内容:

2.9.11位假定不变标识

在文章《如何让GIT忽略本地对已入库文件的修改》中,我提到了“假设不变”标识的概念。我们当时使用的命令是gitupdate-index,它实际上更新了索引文件的标识符。

其中0表示跟踪所有更改,1表示忽略所有更改。事实上,我们对这个文件做了“假设不变”的配置,与index.js文件一致。

2.9.11位扩展标识

该标志在当前索引文件版本(版本2)中无意义,设置为0。

2.9.22位阶段标识

该标识符在合并分支时使用,可以通过#0x01中提到的gitls-files--stage命令获取。普通(未合并)文件通常为0。

2.9.312位文件名长度

该标识符存储文件名的长度,最多支持4095位(0xFFF)。溢出部分将被忽略。

2.10可变长文件目录

其实我们的文件.gitignore目录的长度只有80位,也就是10个字节。为了对齐,随后填充四个字节。文件目录的长度是可变的并且不固定。

2.1132位分隔符

分隔符长度为8字节(32位),通常为0x00000000,用于分隔不同的文件。

综合以上,我们可以画出下图来形象地表示文件索引的结构:

|0|4|8|C||-------------|-------------|------------|----------------|0|DIRC|版本|文件计数|时间.|0|.|时间|设备|2|索引节点|模式|UID|GID|2|文件大小|条目SHA-1.|4|.|旗帜|索引SHA-1.|4|.|

3目录索引

对于具有目录的Git存储库,通常会额外引入目录索引以实现更快的工作目录重建。本节以如下索引文件片段为例:

.000012a0466e137cf7e92c9f000f7574696c2f74|Fn.|.util/t|000012b07261636b65722e676f00000054524545|racker.go.树|000012c0000001af002d3120380a646200332030|.-18.db.30|000012d00a91ca3b67517ebf1f44cd5b505fd042|.gQ~.D.[P_.B|000012e02e8ffaab31617070003520300a9ae2bb|.1app.50.|000012f07d861040bc94ece7a9ebf90447d5312f|}.@.G.1/|0000130098636f7265003120300a504ee21ea0aa|.core.10.PN.|00001310a8ca68ea75a090ae0ae445e727f17574|.h.u.E.ut|…目录索引的格式如下:

3.132位识别符

标识符包含四个字节,即TREE(0x54524545)。

3.232位目录索引长度

这部分的总长度为四个字节,值为下一个目录索引的长度。这里的长度为431字节(0x000001af),与实际情况相符。

以下是各个目录节点的结构,以树的形式组织

3.3每个目录节点

3.3.1可变长目录名

目录索引中的目录名与文件索引中的文件名不同,并且以NUL字符(即0x00或\0)结尾(与字符串一致)。目录名称相对于目录的父目录定位。如果当前节点是根目录,则只包含一个NUL。

3.3.2索引中该树所包含的节点数(即叶子节点)

该值的格式是ASCII数字。由于只缓存目录索引,如果其值为-1(0x2d31),则表示不缓存叶子节点数。如果是其他值,则其值为索引中树包含的数字。节点数。

3.3.3一字节的ASCII空格

这个空格(0x20)用来分隔叶子节点的数量和子树的数量。

3.3.4索引中该树所包含的子树数

值格式也是ASCII数字,如数字8(0x38),通常是准确的,否则无法正确生成缓存树(即接下来的几个节点将被视为当前的子树)根据子树的数量来确定节点)。

3.3.5一字节的ASCII换行符

这个换行符(0x0a)用于分隔子树编号和后面的校验值

3.3.6160位SHA-1校验值

该校验值是节点对应对象的校验值(根节点无校验值)。例如上例中,util目录的检查值为0x17765ec6df577218aefc197ca6349b80c3ed539c。我们可以使用gitrev-parsemaster:util命令获取目录对应的对象,查询与索引文件一致。

4160位文件校验值

校验值是SHA-1值除去校验值的剩余部分,总长度为20字节。如果索引文件损坏,Git会提示以下错误:

#gitstatuserror:badindexfilesha1签名fatal:indexfileCorrupt索引文件被破坏后,仓库并没有损坏,但是仓库索引重建后,未提交的数据会消失(实际上并没有消失,只是存储在.git/object/,但没有指向它的指针)。正因为如此,即使索引文件损坏,只要损坏不彻底,就可以从中恢复相应的目标文件。

重建索引需要使用以下两个命令:

mv.git/index.git/index.corruptgitresetgitadd-u

0x03

事实上,Git的索引文件相当复杂。除了上面提到的文件索引(必须存在)和目录索引(可能存在)之外,还会有以下几种类型的索引:

REUC-解决撤消用于在解决冲突后恢复冲突。您可以先手动触发冲突,解决后使用hexdump查看。link-SplitIndex用于分散索引文件,避免索引文件过大。可以使用gitupdate-index--split-index手动打开它。UNTR-UntrackedCache用于缓存工作区中但尚未提交的文件索引。可以使用gitupdate-index--untracked-cache手动打开它。FSMN——文件系统监控缓存文件系统监控缓存,通过文件系统提供的信息变化来判断文件是否发生变化。可以先编辑.git/config文件,在core字段添加fsmonitor=true,然后执行gitupdate-index--fsmonitor手动开启。EOIE-EndofIndexEntry文件索引结束标识符,用于更快地读取文件索引后面的扩展索引(无需等待文件索引完成)。您可以先编辑.git/config文件并在索引字段中添加threads=true。激活它。IEOT-IndexEntryOffsetTable索引条目偏移表,用于优化多核处理器下Git索引的性能。该功能在Git2.20(2018年底)中推出。本文写于2019年8月。大多数主流Git发行版尚不支持此功能。您还可以先编辑.git/config文件并在索引字段中添加threads=true。激活它。

教育网 Copyright @ 2005-2024 All Rights Reserved. 版权所有 备案号:渝ICP备2023012207号-4

免责声明: 1、本站部分内容系互联网收集或编辑转载,并不代表本网赞同其观点和对其真实性负责。 2、本页面内容里面包含的图片、视频、音频等文件均为外部引用,本站一律不提供存储。 3、如涉及作品内容、版权和其它问题,请在30日内与本网联系,我们将在第一时间删除或断开链接! 4、本站如遇以版权恶意诈骗,我们必奉陪到底,抵制恶意行为。 ※ 有关作品版权事宜请联系客服邮箱:478923*qq.com(*换成@)