Git对象存储和Index file

Git版本存储中两个重要概念:git对象数据库和Index file。

示例数据:

$echo hi,gits >a.txt
$git add .
$git commit -m "first commit"
>[master (root-commit) fee2019] first commit
>1 file changed, 1 insertion(+)
>create mode 100644 a.txt

Git对象存储

Git本地空间分为三种:work tree工作目录树/工作空间、index file和仓库。

工作目录树(work tree)

未执行git add,文件停留在工作目录树/工作空间中。查看:

git diff

列出working与index file间的差异。

index  file

git add将文件状态扩大到index  file中。查看:

git diff --cached

列出index file与git repository间的差异。

git仓库(git repository)

git commit将变更存入git仓库。

git diff HEAD

列出working与git repository间的差异。

若将上述三种类型看成三个阶段:

git提交过程:working -> index file -> git repository。

文件状态变化依次:working最新 -> index file稍旧 -> git repository最旧。

git status

列出working与index file、index file与git repository间的差异。

git status

Git HEAD

HEAD指向当前分支最近一次commit的信息。

所有分支的HEAD都存放在.git/refs/heads目录下,示例为master。

当前分支的HEAD存放在.git/HEAD中。

commit指向了tree对象,tree记录了目录镜像/状态。

tree对象包含blob对象和子目录对象,blob对象包含文件数据。

演示:

$git log
>: commit fee20199b1326896dab693650a37b44e3e11c3cf (HEAD -> master)
>Date:   Sat Nov 24 12:26:33 2018 +0800
>    first commit
$git cat-file -t fee20199b1326896da
>: commit

git cat-file -t

列出指定log id的操作类型(对象类型),示例为commit。

$git cat-file commit fee20199b1326896da
>tree 37057b2e8a9041ef88b805a5b7c4e0e668a03be4
>author 解永辉 <nick@xieyonghui.com> 1543033593 +0800
>committer 解永辉 <nick@xieyonghui.com> 1543033593 +0800
>first commit

git cat-file commit

列出指定类型的对象信息,其中tree id指向可能是一个blob对象,也可以是另一个tree。

$git ls-tree 37057b2e
>:100644 blob 72943a16fb2c8f38f9dde202b7a70ccc19c52f34    a.txt

git ls-tree

列出tree详情:

$git cat-file blob 72943a16fb2
>:hi,gits

git cat-file blob

列出blob对象包含的信息。

$ find .git/objects
>.git/objects
>.git/objects/37
>.git/objects/37/057b2e8a9041ef88b805a5b7c4e0e668a03be4
>.git/objects/72
>.git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34
>.git/objects/fe
>.git/objects/fe/e20199b1326896dab693650a37b44e3e11c3cf
>.git/objects/info
>.git/objects/pack

所有对象都存放在.git/objects目录,类型可以是commit、blob、tree和tag,包含对象的类型、长度和内容。

$ cat .git/HEAD
>:ref: refs/heads/master

HEAD存放在.git目录下,HEAD保存当前分支信息。

$ cat .git/refs/heads/master
>:fee20199b1326896dab693650a37b44e3e11c3cf

查看HEAD文件指向的路径文件,随机数为commit对象id。

$ git cat-file commit fee20199b1326896dab693650a37b44e3e11c3cf
>tree 37057b2e8a9041ef88b805a5b7c4e0e668a03be4
>author 解永辉 <nick@xieyonghui.com> 1543033593 +0800
>committer 解永辉 <nick@xieyonghui.com> 1543033593 +0800

>first commit

HEAD指向当前分支最近一次commit信息,为证实这一点,新增一次提交。

$ git commit -m "second commit"
>[master f22d71f] second commit
>1 file changed, 1 insertion(+)
>create mode 100644 b.txt

通过cat命令查看HEAD文件指向的路径文件。

$  cat .git/refs/heads/master
>:f22d71f18043ac38f8dbce6cf9e48e598c5cc501

执行git cat-file:

$ git cat-file commit f22d71f18043ac38f8dbce6cf9e48e598c5cc501
>tree 61079fdd21307b94ad35ae0f4113a749d222ae03
>parent fee20199b1326896dab693650a37b44e3e11c3cf
>author 解永辉 <nick@xieyonghui.com> 1543037407 +0800
>committer 解永辉 <nick@xieyonghui.com> 1543037407 +0800

>second commit

可看出tree指向最近一次commit对象,parent指向上一次commit对象。

Git index file/索引文件

git index file(索引文件)位于.git/index路径下,为二进制文件,使用git ls-files查看:

git ls-files

对a.txt增加两行内容,未执行git add,使用git diff查看:

$ git diff
>diff --git a/a.txt b/a.txt
>index 72943a1..1802a74 100644
>--- a/a.txt
>+++ b/a.txt
>@@ -1 +1,3 @@
> hi,gits
>+bbb
>+ccc

执行git add,使用git diff查看:

$ git add .
$ git diff

git diff未输出任何信息。

git diff默认比较工作目录树与index file间的差异。 

使用git ls-files查看index file:

$ git ls-files --stage
>100644 1802a7474429e8c0f81d2a36bed657d4b29ed23c 0       a.txt
>100644 2d57b63e6946a9548531960c4f7b15ed10884f52 0       b.txt

git cat-file查看指定文件类型:

$ git cat-file -t 1802a7474 >:blob

git cat-file查看指定类型和id的文件,示例中文件类型为blob。

$ git cat-file blob 1802a7474
>hi,gits
>bbb
>ccc

执行git add命令后,会创建一个blob文件,记录最近的修改,并在index file中更新blob文件引用。