> For the complete documentation index, see [llms.txt](https://alanmpan.gitbook.io/git-learning/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alanmpan.gitbook.io/git-learning/git/19.-le-jie-git-dui-xiang-cun-chu-ji-zhi.md).

# 19.了解Git对象存储机制

Git 使用一种称为对象存储的机制来管理和处理所有文件和目录内容，以及它们之间的关系。

Git 对象存储机制包括以下几个方面：

1. Git 对象：Git 中的所有数据都被视为对象。一个对象可以是一个文件的内容（Blob）、目录结构（Tree）、提交记录（Commit）或标签（Tag）等。
2. SHA-1 哈希：每个 Git 对象都具有与其内容相关联的唯一标识符，该标识符由其内容的 SHA-1 哈希值生成。这使得 Git 可以轻松地检测文件内容的更改。
3. Git 数据库：Git 会将所有对象存储在一个数据库中，该数据库位于 `.git/objects` 目录下。该目录包含一个名为 `info` 的子目录和一个名为 `pack` 的子目录，其中 `info` 子目录包含有关对象的元数据，而 `pack` 子目录包含经过压缩的对象。

## Git 对象

Git 数据库包含了许多不同类型的对象，这些对象相互关联形成一个有向无环图（DAG）。在 Git 中，每个对象都由 SHA-1 哈希值唯一标识，并按照其哈希值存储在 .git 目录下的 objects 目录中。

Git 对象包括四种主要类型：blob、tree、commit 和 tag。

### Blob

Blob 对象代表一个文件的内容。每个 blob 都由一个唯一的 SHA-1 哈希值标识，并存储在 .git/objects 目录下。Blob 对象是 Git 数据库的基本单位，它们包含文件的原始内容而不包含任何元数据。

### Tree

Tree 对象代表一个目录或文件夹，在 Git 中被称为“树”。它可以包含多个 blob 或其他 tree 对象，以及相关元数据，如文件名和权限等信息。Tree 对象也由一个 SHA-1 哈希值唯一标识，并存储在 .git/objects 目录下的 objects/trees 子目录中。

### Commit

Commit 对象代表一个 Git 提交，包含作者和提交日期等元数据，以及一个指向对应 tree 对象的指针。每个 commit 也由一个 SHA-1 哈希值唯一标识，并存储在 .git/objects 目录下。

### Tag

Tag 对象代表一个 Git 标签，它可以指向特定的 commit 或其他 tag。它包含了版本号、标签类型以及描述信息等元数据，以及对应对象的 SHA-1 哈希值指针。Tag 对象也由一个 SHA-1 哈希值唯一标识，并存储在 .git/objects 目录下。

这些 Git 对象之间的关系构成了一个有向无环图（DAG），每个节点都是一个对象，每个边表示一个指针。Git 使用这种数据结构来跟踪代码库的历史记录和变化，并支持分支、合并、撤销和回滚等操作。 ![1](https://github.com/apnpc/Git-Learnnig/blob/main/images/19-1有序无环图.png)

## 实验

`git cat-file` 命令在 Git 中是一个非常有用的工具，特别是对于那些需要深入了解 Git 内部机制的开发人员和高级用户来说。`git cat-file` 命令通常用于以下两种情况：

1. 调试 Git 内部存储：如果您需要深入了解 Git 的内部工作方式，或者需要调试 Git 存储机制中的某些问题，则可以使用 `git cat-file` 命令查看 Git 对象的类型和内容。例如，您可以使用 `git cat-file -p <commit-SHA>` 命令来查看一个提交对象的详细信息，包括其作者、时间、提交消息等。
2. 恢复丢失的 Git 对象：如果您的代码库中丢失了某个对象，例如 Blob 或 Tree 对象，您可以使用 `git cat-file` 命令查看该对象的 SHA-1 标识符，并尝试从其他地方恢复它。例如，您可以使用 `git cat-file -t <object-SHA>` 命令来验证指定的对象是否存在，如果不存在，则表示该对象已经丢失。

我们现在开始实验

### 找到最新一条提交记录

```powershell
# 查看最近一条提交日志
$ git hist --max-count=1
* 5dc8b1e 2023-05-05 | Added .gitignore (HEAD -> master) [aku]
```

### 查看提交对象的类型和对象的内容

`-p`：查看对象内容 `-t`：查看对象类型

```powershell
# 查看对象类型
$ git cat-file -t  5dc8b1e
commit

# 查看对象内容
$ git cat-file -p 5dc8b1e
tree 8b1db75acbd6f424e485953d3b4b8fb0de2f9065
parent b77158ade22b7ec01d29dde4c2e20df0ed2008ec
author aku <aku@example.com> 1683342959 -0700
committer aku <aku@example.com> 1683342959 -0700

Added .gitignore
```

* `Tree`：该提交所指向的树对象的 SHA-1 标识符。
* `Parent`：该提交的父提交（可能有多个）的 SHA-1 标识符。
* `Author`：该提交的作者姓名和电子邮件地址，以及提交时间戳。
* `Committer`：该提交的提交者姓名和电子邮件地址，以及提交时间戳。
* `Moved test.txt to lab`：我在提交时添加的注释。

### 探索

```powershell
# 这里的哈希值，是上一步查看最新提交的 tree 哈希
$ git cat-file -p 8b1db75
100644 blob cb266c781c016fa3ae0be3bab90e71145dc6b09c    .gitignore
040000 tree 652058dd2d8057d2d79049dd3aa7a9f4e69d5e89    lab

# 查看 lab 文件夹的哈希
$ git cat-file -p 652058d
100644 blob 0605515085232c2911ca5e6c407da497c51a5c74    test.txt

# 查看 test 的哈希
$ git cat-file -p 060551
abc
123456
```

> `100644` 是一种文件模式，也称为文件权限或 Unix 文件模式。 `6` 表示所有者可以读取和写入该文件，但不能执行。 `4` 表示组用户可以读取该文件，但不能写入或执行。 `4` 表示其他人可以读取该文件，但不能写入或执行。 在 Unix 系统中，文件权限由一组三个数字表示，分别代表文件所有者、组用户和其他人的文件权限。每个数字表示一个具体的权限：- `0`：无权限。- `1`：执行权限。- `2`：写入权限。- `3`：写入和执行权限。- `4`：读取权限。- `5`：读取和执行权限。- `6`：读取和写入权限。- `7`：读取、写入和执行权限。 例如上文中的 `644` 表示以下内容：文件所有者可以读写该文件（`6 = 4 + 2`）。组用户可以读该文件（`4`）。 其他人可以读该文件（`4`）。 以下是一些常见的 Git 文件模式及其含义：- `040000`：子目录。- `120000`：符号链接。- `160000`：Git 子模块。- `33188` 或 `100644`：普通文件（文件权限为 `-rw-r--r--`）。- `33261` 或 `100755`：可执行文件（文件权限为 `-rwxr-xr-x`）。

Git 对象可以帮助我们跟踪文件的历史记录和变化，并在需要时恢复旧版本的文件或比较不同版本之间的差异。在 Git 中，提交记录、树对象和文件对象都有各自的哈希值，并以这些哈希值相互关联，形成一个完整的 Git 数据库。通过使用 `git log`（\[\[9.设置别名]]）、`git cat-file` 等命令，我们可以查看存储库中的对象内容，并深入了解存储库的历史记录和变更。
