Git 是一套内容寻址文件系统。什么意思呢?

就是Git的核心部分是一个简单的键值数据库(key-value data store)。你可以向该数据库插入任意类型的内容,并会返回一个键值,通过该键值可以在任何时候再取出该内容。

(一)Git对象的存放目录

Git中对象都保存在本地版本库的.git/objects 目录(即:对象数据库)中。

首先初使化一个赶紧的Git仓库:

  1. # 创建一个本地的git仓库git_learning
  2. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository
  3. $ mkdir git_learning
  4. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository
  5. $ cd git_learning/
  6. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning
  7. $ git init
  8. Initialized empty Git repository in J:/git-repository/git_learning/.git/
  9. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  10. $ ll -a
  11. total 8
  12. drwxr-xr-x 1 L 197121 0 4 10 20:24 ./
  13. drwxr-xr-x 1 L 197121 0 4 10 20:23 ../
  14. drwxr-xr-x 1 L 197121 0 4 10 20:24 .git/

确认 objects 目录是默认初始状态:

  1. # 查看.git/objects/目录
  2. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  3. $ ll -a .git/objects/
  4. total 4
  5. drwxr-xr-x 1 L 197121 0 4 10 20:24 ./
  6. drwxr-xr-x 1 L 197121 0 4 10 20:24 ../
  7. drwxr-xr-x 1 L 197121 0 4 10 20:24 info/
  8. drwxr-xr-x 1 L 197121 0 4 10 20:24 pack/
  9. # 查看info目录和pack目录中的内容
  10. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  11. $ ll -a .git/objects/info/
  12. total 0
  13. drwxr-xr-x 1 L 197121 0 4 10 20:24 ./
  14. drwxr-xr-x 1 L 197121 0 4 10 20:24 ../
  15. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  16. $ ll -a .git/objects/pack/
  17. total 0
  18. drwxr-xr-x 1 L 197121 0 4 10 20:24 ./
  19. drwxr-xr-x 1 L 197121 0 4 10 20:24 ../

从上可以看到Git初始化一个本地版本库的时候,就已经初始化了objects目录,并在其中创建了packinfo子目录,但是没有其他常规文件,packinfo子目录中也没有文件。我们只关注objects目录下除了infopack目录之外的变化。

(二)Git中对象类型

Git中对象类型有四种:blob(块)对象,tree(目录树)对象,commit(提交)对象和tag(标签)对象,这四种原子对象构成了Git高层数据结构的基础。

(三)blob对象

1、blob对象说明

(1)blob对象定义

blob对象有叫数据对象。

blob对象是用来存储文本内容的。即把一个文本文件的内容,作为一个blob对象存储在Git系统中。

翻译:

  • Git中blob对象就是对应文件系统中的文件,确切的说是文件的内容,包含

    键:一个hash值和校验值的组合,

    值:文件的内容。
  • 比较特殊的是:blob对象只存内容,不存文件名,文件名在tree对象中保存。

blob对象存储方式如下图

(2)blob对象说明

通过底层命令 git hash-object 来演示,该命令可将任意数据保存于 .git/objects 目录(即 对象数据库)中,并返回指向该数据对象的唯一的键。

1)创建一个新的数据对象,并将它手动存入你的新Git数据库中:

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ echo 'git object test content' | git hash-object -w --stdin
  3. cb2eb834126f53952590c448f14fece6cbb1bff3

说明:这是在Git中以最简单的形式存储数据到Git版本库中,git hash-object命令会接受你传给它的东西,而它只会返回,可以存储在Git仓库中数据对象的唯一的键。

命令含义如下:

  • git hash-object:Git底层命令,可以根据传入的文本内容返回表示这些内容的键值。
  • git object test content:为文本文件中的内容。
  • -w选项:表示hash-object命令将数据对象存储到Git数据库中;若不指定此选项,则该命令仅返回对应的键(也就是那串Hash值)
  • --stdin 选项:表示该命令从标准输入(比如键盘)读取内容,若不指定此选项,则须在命令尾部给出待存储文件的路径。例如:git hash-object -w 文件路径

此命令输出一个长度为40个字符的校验和,这是一个SHA-1哈希值,如上cb2eb834126f53952590c448f14fece6cbb1bff3。该值是文件原内容加上特定头部信息拼接起来,做散列计算得到的数值。(只要文本内容相同,计算出的结果都是一样的)

2)在计算机中查看本地版本库.git/objects 目录中的变化。

可以看到.git/objects 目录中多了一个cb文件夹,如下:

进入cb文件夹,可以看到有一个文件,如下:

好,我们就看到这里就行,这样看比较复杂,还是回到Git Bash中查看。

3)看本地版本库.git/objects 目录中的变化。

  1. # 只看文件可以加 -type f选项参数
  2. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  3. $ find .git/objects
  4. .git/objects
  5. .git/objects/cb
  6. .git/objects/cb/2eb834126f53952590c448f14fece6cbb1bff3
  7. .git/objects/info
  8. .git/objects/pack

我们可以看到cb目录和cb目录中的2eb834126f53952590c448f14fece6cbb1bff3文件。

这就是Git中一个blob对象的存储。

(3)blob对象存储的方式

Git对象的寻址使用40位的16进制数表示,也就是SHA-1散列码,例如:cb2eb834126f53952590c448f14fece6cbb1bff3

为了管理方便,在文件系统中前两位作为.git/objects/ 子目录的名字,后38为作为文件名字。

如下:

  1. # 查看objects目录中的文件,一个文件对应一个Git对象(数据内容)
  2. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  3. $ find .git/objects -type f
  4. .git/objects/cb/2eb834126f53952590c448f14fece6cbb1bff3
  5. # 输出数据对象的hash键,不保存该数据对象。
  6. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  7. $ echo 'git object test content' | git hash-object --stdin
  8. cb2eb834126f53952590c448f14fece6cbb1bff3

我们可以看到两个Hash串是一样的。

提示:你可能感觉用40位作为Git对象的寻址ID,可能会存在不同的内容但是散列码相同的情况,你的感觉是正确的,但是这种情况出现的概率肯定可以忽略不计了。

(4)查看blob对象内容

我们先用cat命令直接读取上面文件,看看是什么情况,如下图:

可以看到显示的内容是一片乱码。

我们需要根据Hash键读取数据,使用命令git cat-file -p 键

-p选项可指示该命令自动判断内容的类型,并为我们使用友好的格式显示内容。

如下:

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ git cat-file -p cb2eb834126f53952590c448f14fece6cbb1bff3
  3. git object test content

提示:

cat命令直接读取Git对象文件,为什么是乱码信息?

文件内容是先通过 zlib 压缩,然后将 zlib 压缩后的内容写入磁盘文件(SHA-1 前两个字符作为子目录名称,后 38 个字符作为子目录文件的名称)

(5)查看Git对象的类型

通过git cat-file -t 键命令,可以查看.git/objects 目录中Git对象的类型

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ git cat-file -t cb2eb834126f53952590c448f14fece6cbb1bff3
  3. blob

这里也说明,我们之前存储的Git对象是一个blob对象。

(6)Git管理文件

至此,你已经掌握了如何向 Git 中存入内容,以及如何将它们取出。

我们同样可以将这些操作应用于文件中的内容。 例如,可以对一个文件进行简单的版本控制。

1)首先,创建一个文件。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ echo "hello-git.txt v1" > hello-git.txt
  3. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  4. $ ll
  5. total 1
  6. -rw-r--r-- 1 L 197121 17 4 10 23:17 hello-git.txt
  7. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  8. $ cat hello-git.txt
  9. hello-git.txt v1

此时文件还有被Git管理。

2)将hello-git.txt文件存入Git数据库。

  1. # 加入版本库,生成blob对象
  2. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  3. $ git hash-object -w ./hello-git.txt
  4. a620c95d3001e1f64cecfc6715f9750cc7bbbf98

3)查看Git数据库内容。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ find .git/objects -type f
  3. .git/objects/a6/20c95d3001e1f64cecfc6715f9750cc7bbbf98
  4. .git/objects/cb/2eb834126f53952590c448f14fece6cbb1bff3

可以看到有多了一个a6子目录,就说明有新增了一个对象。

4)查看a6对象的内容。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ git cat-file -p a620c95d3001e1f64cecfc6715f9750cc7bbbf98
  3. hello-git.txt v1

5)查看a6对象的类型。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ git cat-file -t a620c95d3001e1f64cecfc6715f9750cc7bbbf98
  3. blob

可以看到,不管是你存储一个文件还是存储控制台内容到Git中,最终存储到Git数据库中的都是一个blob类型的Git对象。(即:blob对象是存储数据内容的)

(7)Git管理修改过的文件

1)我们继续向hello-git.txt文件中添加内容。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ echo "hello-git.txt v2" >> hello-git.txt
  3. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  4. $ cat hello-git.txt
  5. hello-git.txt v1
  6. hello-git.txt v2

2)查看Git数据库中的对象。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ find .git/objects -type f
  3. .git/objects/a6/20c95d3001e1f64cecfc6715f9750cc7bbbf98
  4. .git/objects/cb/2eb834126f53952590c448f14fece6cbb1bff3

可以看到还是之间的两个对象cba6,说明我们修改过的文件不会自动的存储到Git数据库中。

我们还需要手动的把修改后的hello-git.txt文件,存储到Git数据库中。

3)把修改后的hello-git.txt文件添加到Git数据库中。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ git hash-object -w ./hello-git.txt
  3. 7c320a2d671f2ff177063f98343a0123432521dd

4)再次查看Git数据库中的对象。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ find .git/objects -type f
  3. .git/objects/7c/320a2d671f2ff177063f98343a0123432521dd
  4. .git/objects/a6/20c95d3001e1f64cecfc6715f9750cc7bbbf98
  5. .git/objects/cb/2eb834126f53952590c448f14fece6cbb1bff3

我们可以看到Git数据库中多了一个7c对象。

5)查看7c对象存储的内容。

  1. L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/git_learning (master)
  2. $ git cat-file -p 7c320a2d671f2ff177063f98343a0123432521dd
  3. hello-git.txt v1
  4. hello-git.txt v2

如上所示,我们可以看到7c对象存储了v1v2的内容,v1内容即在a6对象中,也在7c对象中。所以对于Git来说,存储的不是文件内容的增量。

2、blob对象总结

  • Git的核心部分是一个简单的键值数据库(key-value data store),键就是文本内容的Hash,值就是文本内容。
  • blob对象都存储在.git/objects 目录中,子目录+目录中的文件名,就是40位Hash值,也就是对象的键值。
  • 通过这个键就能找到对应的内容。
  • 每个文本内容存储到Git数据库的时候,内容都会进行zlib 压缩再存储。
  • blob对象存储的是文件的内容,相同的内容不产生新的blob对象。
  • blob对象并没有存储文件名。

提示:Git对象的hash键,我们截取前几位就行,练习时对象不那么对,就不用全部都写,能够表示唯一对象就行。

3、问题

我们对文件做一次修改,存储到Git数据库中,都会在Git数据库中创建一个新的blob对象。而在实际的工作中,我们需要做很多的改动,才提交一个版本,我们是否可以用一个blob对象代表整个项目的一次快照。

不能,只能代表一次存储时,一个文件中的内容,与之前数据内容相同时不新增Git对象,数据内容不同时再次新增blob对象。即:只要有新的内容被Git纳入管理,必定有一个blob对象与之对应。

那么还有如下问题:

  1. 记住文件的每一个版本所对应的SHA-1值并不现实。
  2. blob对象中,文件名并没有被保存,仅保存了文件的内容。

所以,没有文件名就没有办法通过文件名来读取数据,只能用40位Hash值读取,非常的不现实。

解决方案:树对象。

提示:以上的操作都是在工作区和本地版本库之间进行操,不涉及暂存区,因为我们直接存储到了本地版本库中。

4、本文用到的命令总结

Git底层命令:

  • git hash-object -w 文件路径:把工作区的一个文件提交到本地版本库中。
  • find .git/objects -type f:查看Git数据库中的对象。(Linux命令)
  • git cat-file -p 键:查看该Git对象的内容。
  • git cat-file -t 键:查看该Git对象的类型。

参考:

『现学现忘』Git对象 — 15、blob对象介绍的更多相关文章

  1. 『现学现忘』Git对象 — 16、Tree对象详解

    目录 1.Tree对象介绍 2.Tree对象说明 (1)初始化一个新的本地版本库 (2)创建一个树对象(重点) (3)创建第二个文件(重点) (4)将第一个树对象加入暂存区,使其成为新的树对 3.总结 ...

  2. 『现学现忘』Git分支 — 39、Git中分支与对象的关系

    目录 1.Git对象之间的关系 2.提交对象与分支的关系 (1)提交对象与分支的关系 (2)分支说明 (3)HEAD与分支的关系 1.Git对象之间的关系 我们之前学了Git的三个对象:提交对象.树对 ...

  3. 『现学现忘』Git对象 — 17、Commit对象

    目录 1.Commit对象介绍 2.Commit对象说明 3.本地库中对象之间的关系 4.总结 5.练习 6.本文用到的命令总结 1.Commit对象介绍 现在来介绍最后一种Git对象commit对象 ...

  4. 前端H5中JS用FileReader对象读取blob对象二进制数据,文件传输

    HTML5中的Blob对象只是二进制数据的容器,本身并不能操作二进制,故本篇将对其操作对象FileReader进行介绍. FileReader FileReader主要用于将文件内容读入内存,通过一系 ...

  5. 『现学现忘』Git基础 — 18、Git对象的总结

    目录 1.Git操作最基本的流程 2.工作目录中文件的状态 3.Git效率说明 提示:前面三篇文章已经分别的对blob对象.tree对象.commit对象进行了详细的说明,这篇文章我们总结一下,Git ...

  6. 『现学现忘』Git基础 — 5、Git的协作模式

    目录 1.分布式工作流程 2.集中式工作流 3.分支工作流 4.GitFlow 工作流(最流行) 5.Forking 工作流(偶尔使用) 6.总结 1.分布式工作流程 与传统的集中式版本控制系统(CV ...

  7. 『现学现忘』Git基础 — 36、标签tag(一)

    目录 1.标签介绍 2.列出标签 3.创建标签 (1)标签的分类 (2)附注标签 (3)轻量标签 4.后期打标签 1.标签介绍 软件的某个发行版本所对应的,其实就是软件开发过程中,某一个阶段的最后一次 ...

  8. NHibernate框架与BLL+DAL+Model+Controller+UI 多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

    原文://http://blog.csdn.net/wb09100310/article/details/47271555 1. 概述 搭建了Spring.NET+NHibernate的一个数据查询系 ...

  9. 『现学现忘』Git基础 — 10、配置Git用户签名说明

    目录 1.为什么要创建用户签名 2.为什么要在Git中配置这些信息 3.创建用户签名的方式 4.总结 1.为什么要创建用户签名 作为版本控制系统的客户端,每台客户机对版本库的所有提交操作,都需要注明操 ...

随机推荐

  1. mysql 在已存在的表中添加/删除字段约束AUTO_INCREMENT遇到的问题

    1. 在已存在的表中添加字段约束AUTO_INCREMENT修饰符 mysql> alter table user modify uid int auto_increment primary k ...

  2. 您使用了哪些 starter maven 依赖项?

    使用了下面的一些依赖项 spring-boot-starter-activemq spring-boot-starter-security 这有助于增加更少的依赖关系,并减少版本的冲突.

  3. C++各种输入

    https://blog.csdn.net/qq_29735775/article/details/81165882 1.cin 2.cin.get() 3.cin.getline() 4.getli ...

  4. 启动一个线程是调用 run()还是 start()方法?

    启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态, 这意味着它可以由 JVM 调度并执行,这并不意味着线程就会立即运行.run()方 法是线程启动后要进行回调(callb ...

  5. MariaDB ZIP方式安装(Window系统)

    Maria DB ZIP方式安装 Windows上ZIP包的入门非常简单-此发行版包括预构建的数据库文件,这些文件可以在解压缩ZIP后立即使用. 您可以从命令提示符运行mysqld.exe,如下所示: ...

  6. spring 支持哪些 ORM 框架?

    Hibernate iBatis JPA JDO· OJB

  7. 学习Apache(一)

    实验目的 通过apache实现反向代理的功能,类似nginx反向代理和haproxy反向代理 环境准备 逻辑架构如下 前端是apche服务器,监听80端口,后端有两台web服务器,分别是node1和n ...

  8. 要多简单就有多简单的H5拍照加水印

    来一个简单粗暴的gif演示图 先来html 内容 <video id="video" width="320" height="240" ...

  9. 关于小程序websocket全套解决方案,Nginx代理wss

    需求对话 提问 我在本地web能够使用ws协议去链接websocket,但是小程序不能使用. 回答 由于小程序使用的是SSL加密协议,所以需要使用wss.这里wss与ws的关系就相当于https于ht ...

  10. 如何使用Flannel搭建跨主机互联的容器网络

    当您将多台服务器节点组成一个Docker集群时,需要对集群网络进行设置,否则默认情况下,无法跨主机容器互联,接下来我们首先分析一下原因. 跨主机容器互联 下图描述了一个简单的集群网络,在该集群内,有两 ...