git索引包含什么?
Git索引究竟包含什么,以及我可以使用什么命令来查看索引的内容?
更新
感谢您的答复。 我知道索引是一个中转区,索引中的内容是索引而不是工作树。 我只是好奇索引对象是由什么组成的。 我想这可能是一个文件名/目录名,SHA-1对的列表,一种虚拟树也许?
有没有,在Git术语中,我可以使用任何pipe道命令来列出索引的内容?
Git书中包含一篇关于索引包含的文章:
该索引是一个二进制文件(通常保存在
.git/index
),其中包含path名的有序列表,每个path名都有权限和blob对象的SHA1;git ls-files
可以显示你的索引的内容:
$ git ls-files --stage 100644 63c918c667fa005ff12ad89437f2fdc80926e21c 0 .gitignore 100644 5529b198e8d14decbe4ad99db3f7fb632de0439d 0 .mailmap
Racy git问题提供了一些关于这个结构的更多细节:
该索引是git中最重要的数据结构之一。
它通过loggingpath及其对象名称列表来表示一个虚拟工作树状态,并作为一个临时区域写出下一个要提交的树对象。
状态是“虚拟的”,因为它并不一定必须(通常不会)与工作树中的文件相匹配。
要了解更多,参见 “ git / git / Documentation / technical / index-format.txt ”:
Git索引文件具有以下格式
所有的二进制数字都是networking字节顺序。
除非另有说明,否则在此描述版本2 。
- 一个12字节的标题包括:
- 4字节签名 :
签名是{'D
','I
','R
','C
'}(代表“dircache
”)- 4字节版本号 :
目前支持的版本是2,3和4。- 索引条目的32位数。
- 一些sorting的索引条目 。
- 扩展程序 :
扩展名通过签名来标识。
如果Git不理解,可选的扩展名可以忽略。
Git目前支持caching树并解决撤消扩展。
- 4字节的扩展签名。 如果第一个字节是'
A
'..'Z
',则扩展是可选的,可以忽略。- 扩展名的32位大小
- 扩展数据
- 该校验和之前的索引文件内容为160位SHA-1。
mljrg 评论 :
如果索引是下一个提交准备好的地方,为什么不提交后“
git ls-files -s
”不返回任何内容?
因为索引代表正在被跟踪的内容 ,在提交之后,正在跟踪的内容与上次提交相同( git diff --cached
返回任何内容)。
所以git ls-files -s
列出了跟踪的所有文件(对象名称,模式位和输出中的阶段编号)。
该列表(被跟踪的元素)被初始化为提交的内容。
当您切换分支时,索引内容将重置为您刚刚切换到的分支引用的提交。
一点一滴分析
我决定做一些testing,以更好地理解格式,并更详细地研究一些领域。
Git版本1.8.5.2
和2.3
结果如下。
我已经标出了我不确定/没有findTODO
点数:请随意补充这些点数。
正如其他人提到的那样,索引存储在.git/index
,而不是作为标准树对象,其格式是二进制的,并logging在: https : //github.com/git/git/blob/master/Documentation/technical/指数format.txt
定义索引的主要结构是cache.h ,因为索引是创build提交的caching。
build立
当我们启动一个testing仓库时:
git init echo a > b git add b tree --charset=ascii
.git
目录如下所示:
.git/objects/ |-- 78 | `-- 981922613b2afb6025042ff6bd878ac1994e85 |-- info `-- pack
如果我们得到唯一对象的内容:
git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85
我们得到a
。 这表明:
-
index
指向文件内容,因为git add b
创build了一个blob对象 - 它将元数据存储在索引文件中,而不是存储在树形对象中,因为只有一个对象:blob(在常规的Git对象上,blob元数据存储在树上)
高清分析
现在让我们看看索引本身:
hd .git/index
得到:
00000000 44 49 52 43 00 00 00 02 00 00 00 01 54 09 76 e6 |DIRC.... ....Tv| 00000010 1d 81 6f c6 54 09 76 e6 1d 81 6f c6 00 00 08 05 |..oTv ..o.....| 00000020 00 e4 2e 76 00 00 81 a4 00 00 03 e8 00 00 03 e8 |...v.... ........| 00000030 00 00 00 02 78 98 19 22 61 3b 2a fb 60 25 04 2f |....x.." a;*.`%./| 00000040 f6 bd 87 8a c1 99 4e 85 00 01 62 00 ee 33 c0 3a |......N. ..b..3.:| 00000050 be 41 4b 1f d7 1d 33 a9 da d4 93 9a 09 ab 49 94 |.AK...3. ......I.| 00000060
接下来我们将总结:
| 0 | 4 | 8 | C | |-------------|--------------|-------------|----------------| 0 | DIRC | Version | File count | ctime ...| 0 | ... | mtime | device | 2 | inode | mode | UID | GID | 2 | File size | Entry SHA-1 ...| 4 | ... | Flags | Index SHA-1 ...| 4 | ... |
首先是头部,定义在: struct cache_header :
-
44 49 52 43
:DIRC
。 TODO:为什么这是必要的? -
00 00 00 02
:格式版本:2.索引格式随着时间的推移而发展。 目前版本最多为4个。在GitHub上不同计算机之间进行协作时,索引的格式不应该成为问题,因为裸存储库不存储索引:它在克隆时生成。 -
00 00 00 01
:索引上的文件数:只有一个,b
。
接下来启动一个由struct cache_entry定义的索引条目列表在这里,我们只有一个。 它包含:
-
一堆文件元数据:8字节的
ctime
,8字节的mtime
,然后4字节:设备,inode,模式,UID和GID。请注意:
-
ctime
和mtime
是相同的(54 09 76 e6 1d 81 6f c6
),因为我们没有修改文件第一个字节是从hex的EPOCH开始的秒数:
date --date="@$(printf "%x" "540976e6")"
得到:
Fri Sep 5 10:40:06 CEST 2014
这是我做这个例子的时候。
第二个4字节是纳秒。
-
UID和GID是
00 00 03 e8
(hex):单用户设置的通用值。
所有这些元数据(其中大部分都不存在于树对象中)允许Git检查文件是否已经快速更改,而无需比较整个内容。
-
-
在
30
行的开头:00 00 00 02
:文件大小:2个字节(来自echo
a
和\n
) -
78 98 19 22 ... c1 99 4e 85
字节SHA-1在条目的前一个内容上。 请注意,根据我对假设有效标志的实验,在此SHA-1中不考虑后面的标志。 -
2个字节的标志:
00 01
-
1位:假定有效的标志。 我的调查表明,这个糟糕的命名标志是
git update-index --assume-unchanged
存储其状态的地方: https :git update-index --assume-unchanged
-
1位扩展标志。 确定扩展标志是否存在。 在没有扩展标志的版本2上必须为
0
。 -
合并期间使用2位阶段标志。 阶段logging在
man git-merge
:-
0
:常规文件,不在合并冲突中 -
1
:基地 -
2
:我们的 -
3
:他们的
在合并冲突期间,所有从1-3开始的阶段都存储在索引中,以允许像
git checkout --ours
这样的操作。如果你使用
git add
,那么一个阶段0被添加到path的索引中,Git将知道这个冲突已经被标记为已解决。 TODO:检查这个。 -
-
将遵循的path的12位长度:
0 01
:1字节,因为path是b
-
-
2个字节的扩展标志。 只有在基本标志上设置了“扩展标志”时才有意义。 去做。
-
62
(ASCIIb
):可变长度path。 在前面的标志确定的长度,这里只有1个字节,b
。
然后出现00
:1-8字节的零填充,这样path将被空终止,索引将以8个字节的倍数结束。 这只发生在索引版本4之前。
没有使用扩展名。 Git知道这一点,因为校验和文件中没有足够的空间。
最后在索引的内容上有一个20字节的校验和。
Git索引是你的工作目录和你的仓库之间的集结区域。 您可以使用索引build立一组您想一起提交的更改。 当你创build一个提交时,什么是提交是目前在这个索引,而不是在你的工作目录。
要查看索引内部的内容,请发出以下命令:
git status
当你运行git status的时候,你可以看到哪些文件正在执行(目前在你的索引中),哪些文件已经被修改,但还没有上演,哪些文件完全没有被跟踪。
你可以阅读这个 。 谷歌search抛出许多链接,这应该是相当自给自足。