Git对象

简介

Git 中常见有四种类型的对象 blob、tree、 commit 、tag:

  • blob:用来存储文件数据,通常是一个文件
  • tree:一个tree上可以有多个 blob 或tree
  • commit:指向一个”tree”,用来标记项目某状态。它包括信息数据,如时间戳、提交的作者、父提交(parent commits)等
  • tag:标记某一个提交(commit)

下图很好的说明他们的关系


这里写图片描述

Git 是一个内容寻址文件系统,其核心部分是一个简单的键值对数据库。向该数据库插入任意类型的内容,它会返回键值(SHA-1 哈希值),我们可以利用此值来重新获取内容。 我们应该先初始化一个新的 Git 版本库,因为老版本库东西太多,容易让我们混淆。

初始化一个新的 Git 版本库:

$ git init
Initialized empty Git repository in C:/Users/Administrator/Desktop/gitstudy/.git/

$ find .git/objects
.git/objects
.git/objects/info
.git/objects/pack

可以看到 Git 对 objects 目录进行了初始化(objects 目录会是对象文件存储的地方),并创建了 pack 和 info 的空目录。

数据对象(blob object)

向 Git 数据库存入一些文本:

$ echo 'test' | git hash-object -w --stdin
9daeafb9864cf43055ae93beb0afd6c7d144bfa4
  • 可以通过下面命令查看更多帮助信息 $ git hash-object -h
  • -w 选项指示 hash-object 命令存储数据对象;若不指定此选项,则该命令仅返回对应的键值(SHA-1 哈希值)。
  • –stdin选项则指示该命令从标准输入读取内容;若不指定此选项,则须在命令尾部给出待存储文件的路径。 该命令输出一个长度为 40 个字符的校验和。 这是一个 SHA-1 哈希值——一个将待存储的数据外加一个头部信息(header)一起做 SHA-1 校验运算而得的校验和。

现在我们可以查看 Git 是如何存储数据的:

$ find .git/objects/ -type f
.git/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4
  • find .git/objects -type f 这个linux命令可以列出.git/objects下所有的类型为一般文件的文件
  • 一个文件对应一条内容,以该内容加上特定头部信息一起的 SHA-1 校验和为文件命名
  • 校验和的前两个字符用于命名子目录(别忘了),余下的 38 个字符则用作文件名

如果是一个文件,我们也可以用同样方法:

$ echo '1.txt' > 1.txt

$ git hash-object -w 1.txt
1f67fc4386b2d171e0d21be1c447e12660561f9b

修改内容,在此存储,并查看对象:

$ echo 'test txt' > 1.txt

$ git hash-object -w 1.txt
5eb252be93508457ff0b5ef442577dcd50daf6e4

$ find .git/objects/ -type f
.git/objects/1f/67fc4386b2d171e0d21be1c447e12660561f9b
.git/objects/5e/b252be93508457ff0b5ef442577dcd50daf6e4
.git/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4

可以看到,内容都被存储。由于是对文件和内容进行 SHA-1 校验,即使在不同电脑,上面的校验和还是一致。

获取数据/还原版本

可以通过 cat-file 命令从 Git 那里取回数据:

$ git cat-file -p 9daeafb9864cf43055ae93beb0afd6c7d144bfa4
test

$ git cat-file -p 1f67fc
1.txt

$ git cat-file -p 5eb252
test txt

$ git cat-file -t 1f7a7a
blob
  • 可以通过下面命令查看更多帮助信息 $ git cat-file -h
  • -p 选项可指示该命令自动判断内容的类型,并为我们显示格式友好的内容
  • -t 命令,查看其对象类型

既然可以通过上面方法获取数据了,那么我们可以通过流,将旧版本的数据写入文件并覆盖,从而达到版本还原的功能。

现在可以把文件内容恢复到第一个版本:

$ git cat-file -p 1f67fc > 1.txt
$ cat 1.txt
1.txt

或者第二个版本:

$ git cat-file -p 5eb252 > 1.txt
$ cat 1.txt
test txt

树对象(tree object)

想要记住文件的每一个版本所对应的 SHA-1 值并不现实(随着版本增多,objects 目录内容会越来越多)。而且,当前的方式我们只保存了文件内容,而文件名没有进行保存。所以,有了树对象(tree object)的概念,它能保存文件名,也允许将多个文件组织到一起。

Git 会根据某一时刻暂存区所表示的状态创建并记录一个对应的树对象。 可以通过底层命令 update-index 为一个单独文件创建一个暂存区:

$ git update-index --add --cacheinfo  100644 \
> 5eb252be93508457ff0b5ef442577dcd50daf6e4 1.txt
  • –add:让git不忽略掉新文件(未放入暂存区的)
  • –cacheinfo:将文件放入暂存区
  • 100644,文件模式;参考了常见的 UNIX 文件模式 - 100644(普通文件),100755,表示一个可执行文件,120000,表示一个符号链接等

创建树对象

可以通过 write-tree 命令将暂存区内容写入一个树对象:

$ git write-tree
578d3113e3145dbb260e6a33aff45b408ce36c3d

$ git cat-file -p 578d31
100644 blob 5eb252be93508457ff0b5ef442577dcd50daf6e4    1.txt

$ git cat-file -t 578d31
tree

创建一个新的树对象,它包括 1.txt 文件的第二个版本,以及一个新的文件 2.txt,然后观察它的结构:

$ echo '2.txt' > 2.txt

$ git update-index --add 2.txt

$ git write-tree
d0b4a7dfd637bc58aceb020c09e8be28377289f4

$ git cat-file -p d0b4a7
100644 blob 5eb252be93508457ff0b5ef442577dcd50daf6e4    1.txt
100644 blob e7b4ad382349ff96dd8199000580b9b1e2042eb0    2.txt

往树对象添加树对象

可以将第一个树对象加入第二个树对象,使其成为新的树对象的一个子目录。通过调用 read-tree 命令,可以把树对象读入暂存区:

$ git read-tree --prefix=bak 578d31

$ git write-tree
e4c2c43c04d78d2ac7b82d82c543c3d0999afade

$ git cat-file -p e4c2c4
100644 blob 5eb252be93508457ff0b5ef442577dcd50daf6e4    1.txt
100644 blob e7b4ad382349ff96dd8199000580b9b1e2042eb0    2.txt
040000 tree 578d3113e3145dbb260e6a33aff45b408ce36c3d    bak

这个时候,我们数据的结构应该如下图:


这里写图片描述

提交对象(commit object)

要我们记住所有 SHA-1 哈希值来使用快照,会显得十分不方便。 提交对象(commit object)能为你保存基本信息:谁保存了这些快照,在什么时刻保存的,以及为什么保存这些快照。

可以通过调用 commit-tree 命令创建一个提交对象,为此需要指定一个树对象的 SHA-1 值(代表项目的快照,用于以后使用),也可以提供该提交的父提交对象,让他们有一个关联关系:

$ echo 'first' | git commit-tree e4c2c43
c3fe2f808a34b7c40671b8a27dbdbc2afcb3479f

$ git cat-file -p c3fe2f808a34b7c40671b8a27dbdbc2afcb3479f
tree e4c2c43c04d78d2ac7b82d82c543c3d0999afade
author oDevilo <15757166470@163.com> 1486459157 +0800
committer oDevilo <15757166470@163.com> 1486459157 +0800

first

我们将创建另两个提交对象,它们分别引用各自的上一个提交(作为其父提交对象):

$ echo 'second' | git commit-tree -p c3fe2f d0b4a7
14c01f0c70573e12f1d59f9853adfdca9a6afd1d

$ echo 'third'  | git commit-tree -p 14c01 578d31
e9775cfb8e302a700f2f67106895f139a781fea0

查看历史

至此,我们可以通过下面 git log 查看 Git 提交历史了:

$ git log --stat e9775
commit e9775cfb8e302a700f2f67106895f139a781fea0
Author: oDevilo <15757166470@163.com>
Date:   Tue Feb 7 17:29:06 2017 +0800

    third

 2.txt | 1 -
 1 file changed, 1 deletion(-)

commit 14c01f0c70573e12f1d59f9853adfdca9a6afd1d
Author: oDevilo <15757166470@163.com>
Date:   Tue Feb 7 17:28:12 2017 +0800

    second

 bak/1.txt | 1 -
 1 file changed, 1 deletion(-)

commit c3fe2f808a34b7c40671b8a27dbdbc2afcb3479f
Author: oDevilo <15757166470@163.com>
Date:   Tue Feb 7 17:19:17 2017 +0800

    first

 1.txt     | 1 +
 2.txt     | 1 +
 bak/1.txt | 1 +
 3 files changed, 3 insertions(+)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值