前言
在使用git工具管理项目的时候,.git
目录下存放了index文件,这个文件是git的staging area
,也叫做暂存区,也可以理解为当前工作区已经被托管文件的区域。index文件是使用二进制的方式进行存储的,具体内容是一些基础信息数据,然后面就是暂存区的条目信息。
基础环境
我这里简单创建了一个小环境具体创建过程如下
E:\TEMP\TEMPGIT>dir
驱动器 E 中的卷是 新加卷
卷的序列号是 F238-DE49
E:\TEMP\TEMPGIT 的目录
2024/12/06 12:29 <DIR> .
2024/12/06 12:26 <DIR> ..
2024/12/06 12:27 9 hello.txt
2024/12/06 12:27 16 README.md
2 个文件 25 字节
2 个目录 24,408,936,448 可用字节
E:\TEMP\TEMPGIT>git init
Initialized empty Git repository in E:/TEMP/TEMPGIT/.git/
E:\TEMP\TEMPGIT>git add hello.txt
E:\TEMP\TEMPGIT>git commit -m "feat: add hello.txt"
[master (root-commit) 49c851f] feat: add hello.txt
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
E:\TEMP\TEMPGIT>git add README.md
E:\TEMP\TEMPGIT>git commit -m "feat: add README.md"
[master 699a3fc] feat: add README.md
1 file changed, 1 insertion(+)
create mode 100644 README.md
使用16进制编辑器打开项目下.git/index
文件,具体内容如下
44 49 52 43 00 00 00 02 00 00 00 02 67 52 7D 35
28 C5 D9 74 67 52 7D 42 34 FA 3B A4 00 00 00 00
00 00 00 00 00 00 81 A4 00 00 00 00 00 00 00 00
00 00 00 10 75 7C B5 AA CC 80 7E B5 B1 FD 67 4E
1F 51 EC 71 DE 00 22 A3 00 09 52 45 41 44 4D 45
2E 6D 64 00 67 52 7D 15 2C 21 10 D4 67 52 7D 18
37 F7 20 24 00 00 00 00 00 00 00 00 00 00 81 A4
00 00 00 00 00 00 00 00 00 00 00 09 34 FE 99 B2
F1 96 86 5F 6D E9 3E 35 0A E6 AE 3A FD 34 55 06
00 09 68 65 6C 6C 6F 2E 74 78 74 00 54 52 45 45
00 00 00 19 00 32 20 30 0A 7E 4E 0F A2 7B 51 A7
2C E3 BA 34 E5 70 F0 8B 89 63 58 C5 9F 4D 52 68
C5 94 87 74 75 74 DA D9 91 8F 7E 56 3D B7 01 82
CD
基础信息
基础信息就是前12bytes具体内容位,它们依次代表的内容如下
44 49 52 43 00 00 00 02 00 00 00 02
前4byte是固定的文件头44 49 52 43
,转换到10进制的内容就是DIRC
.
紧接着的4byte是记录git版本的00 00 00 02
这里的git版本就是2
再后面的4byte是记录git提交次数的00 00 00 02
这里的提交次数是2
条目信息
条目信息的前62位是固定的,之后的长度是按照文件路径名字来计算的,按照上面的数据来说第一条的数据是
67 52 7D 35 28 C5 D9 74 67 52 7D 42 34 FA 3B A4
00 00 00 00 00 00 00 00 00 00 81 A4 00 00 00 00
00 00 00 00 00 00 00 10 75 7C B5 AA CC 80 7E B5
B1 FD 67 4E 1F 51 EC 71 DE 00 22 A3 00 09 52 45
41 44 4D 45 2E 6D 64 00
下面依次说一下每个byte代表的作用
- 8byte内容是ctime,创建文件的时间,前4byte是从1970年1月1日00:00:00计算的时间戳,后4byte是nanosecond微秒,一般前都用前面4byte,文件创建的时间戳
67 52 7D 35
转换过来就是1733459253
即2024-12-06 12:27:33
- 8byte内容是mtime,上次修改的时间,他的格式和CTIME一样,前4byte是时间戳,后面是nanosecond微秒。
67 52 7D 42
转换的时间戳是1733459266
即2024-12-06 12:27:46
- 4byte的内容应该是device即文件存储的设备,我这里是
00 00 00 00
,全0肯定是有些问题,具体问题我也没研究出来。 - 4byte的内容应该是Inode即
文件在设备的文件系统中存储的具体块的编号
,我这里是00 00 00 00
,全0肯定是有些问题,具体问题我也没研究出来。 - 4byte的内容是文件权限,我这里的内容为
00 00 81 A4
转换之后就是100644
,100是代表普通文件,后面的644就是linux中的权限,这里不多说 - 4byte的内容是uid,大概率是因为我用的win系统,所以没展示出来全是0x00
- 4byte的内容是gid,大概率是因为我用的win系统,所以没展示出来全是0x00
- 4byte的内容是文件大小,我这里是
00 00 00 10
转换过来即16,就是16字节 - 20byte的内容是sha-1,我这里的内容为
75 7C B5 AA CC 80 7E B5 B1 FD 67 4E 1F 51 EC 71 DE 00 22 A3
,这个内容在objects
目录中会有对应的文件,这个可以理解为对应文件的索引,以这个sha-1为例,他的位置应该是在.git\objects\75\7cb5aacc807eb5b1fd674e1f51ec71de0022a3
- 2byte的内容是文件的长度,我这里的长度是
00 09
即9位 - 文件名在条目中的占用长度是不固定的,以当前条目为例,其长度为9字节,文件名内容是
52 45 41 44 4D 45 2E 6D 64 00
,转换后为README.md
.但它实际占用了10字节.这是因为在存储时,文件名后会填充0x00
即00
作为分隔符.为了满足存储规则,文件名会按照8字节对齐的方式进行填充.因此,如果条目的总字节长度不能被8整除,会继续填充0x00
,直到长度达到8的倍数.比如本条目就通过填充一个00
字节使得长度符合对齐要求
扩展信息
条目解析结束之后,后面还有一段信息,这段信息的内容是index文件的扩展信息,内容如下
54 52 45 45 00 00 00 19 00 32 20 30 0A 7E 4E 0F
A2 7B 51 A7 2C E3 BA 34 E5 70 F0 8B 89 63 58 C5
9F 4D 52 68 C5 94 87 74 75 74 DA D9 91 8F 7E 56
3D B7 01 82 CD
前面四个字节是TREE,代表记录的是TREE的信息,这里会记录当前HEAD的SHA-1还有index的SHA-1来确定文件的完整性,这里当前HEAD的sha-1是7E 4E 0F A2 7B 51 A7 2C E3 BA 34 E5 70 F0 8B 89 63 58 C5 9F
紧接着就是index的SHA-1,即4D 52 68 C5 94 87 74 75 74 DA D9 91 8F 7E 56 3D B7 01 82 CD