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.22.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 43DIRC 。 TODO:为什么这是必要的?

  • 00 00 00 02 :格式版本:2.索引格式随着时间的推移而发展。 目前版本最多为4个。在GitHub上不同计算机之间进行协作时,索引的格式不应该成为问题,因为裸存储库不存储索引:它在克隆时生成。

  • 00 00 00 01 :索引上的文件数:只有一个, b

接下来启动一个由struct cache_entry定义的索引条目列表在这里,我们只有一个。 它包含:

  • 一堆文件元数据:8字节的ctime ,8字节的mtime ,然后4字节:设备,inode,模式,UID和GID。

    请注意:

    • ctimemtime是相同的( 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 (ASCII b ):可变长度path。 在前面的标志确定的长度,这里只有1个字节, b

然后出现00 :1-8字节的零填充,这样path将被空终止,索引将以8个字节的倍数结束。 这只发生在索引版本4之前。

没有使用扩展名。 Git知道这一点,因为校验和文件中没有足够的空间。

最后在索引的内容上有一个20字节的校验和。

Git索引是你的工作目录和你的仓库之间的集结区域。 您可以使用索引build立一组您想一起提交的更改。 当你创build一个提交时,什么是提交是目前在这个索引,而不是在你的工作目录。

要查看索引内部的内容,请发出以下命令:

 git status 

当你运行git status的时候,你可以看到哪些文件正在执行(目前在你的索引中),哪些文件已经被修改,但还没有上演,哪些文件完全没有被跟踪。

你可以阅读这个 。 谷歌search抛出许多链接,这应该是相当自给自足。