Git 是一个功能强大的分布式版本控制系统,它的核心概念决定了其强大的功能和灵活性。本章将深入探讨 Git 的基本概念,包括版本库、Git 对象类型、索引、可寻址内容名称、Git 追踪内容、路径名与内容的关系,以及 Git 的数据存储方式。此外,还会通过图示帮助读者更直观地理解 Git 的存储结构,并讲解 Git 工作时的核心概念,如 .git
目录、对象、blob、文件树、SHA-1 哈希值、树层次结构、提交、标签等。
4.1 基本概念
4.1.1 版本库
在 Git 中,版本库(Repository) 是用于存储项目所有文件及其历史记录的地方。Git 版本库的核心结构包括:
- 工作区(Working Directory):用户实际编辑文件的地方。
- 暂存区(Staging Area):Git 维护的一个中间区域,存储即将提交的更改。
- 版本库(Repository):Git 维护的所有版本的存储区域,通常在
.git
目录下。
在 Git 中,初始化一个新的版本库使用 git init
命令:
git init
执行后,Git 会在当前目录下创建 .git
目录,该目录包含所有 Git 相关的文件和元数据,如对象存储、HEAD 指针、分支信息等。
4.1.2 Git 对象类型
Git 以对象(Object)为核心进行数据存储,主要包括以下三种对象类型:
- Blob(Binary Large Object):存储文件内容,Git 不存储文件的名字或路径,而是仅存储其内容。
- Tree(树):存储目录结构,记录文件与文件夹的组织方式,并指向对应的 blob 对象。
- Commit(提交):代表一次快照,包含提交信息、提交者、提交时间以及指向的 Tree 对象。
Git 使用 SHA-1 哈希 作为对象的唯一标识,每个对象在 .git/objects
目录下存储为一个以 SHA-1 哈希值命名的文件。
4.1.3 索引
索引(Index)是 Git 中的一个重要概念,也称为暂存区(Staging Area)。它的作用是充当 工作区和版本库之间的缓冲区,允许用户在提交之前整理文件的更改。
当运行 git add
命令时,文件的更改会被添加到索引中,而不是直接提交到版本库。例如:
echo "Hello Git" > file.txt
git add file.txt
此时,file.txt
进入索引,但尚未正式提交。可以通过 git status
查看索引中的内容:
git status
要提交更改,需要运行 git commit
:
git commit -m "Added file.txt"
4.1.4 可寻址内容名称
Git 的一个关键特性是所有存储的对象(blob、tree、commit)都使用 SHA-1 哈希进行标识。这意味着 Git 可以通过 SHA-1 哈希值来唯一地寻址任何存储的内容。例如,查看某个提交的哈希值:
git log --oneline
输出可能类似于:
a3c6f29 Initial commit
其中 a3c6f29
就是该提交的 SHA-1 哈希的前几位。Git 允许使用部分哈希值进行引用,例如:
git show a3c6f29
4.1.5 Git 追踪内容
Git 通过跟踪文件的内容(而非文件本身)来管理版本变更。每当文件发生更改,Git 会计算其内容的 SHA-1 哈希值,并存储新的 blob 对象,而不是存储整个文件的副本。
查看 Git 追踪的文件状态:
git status
文件可能处于以下几种状态:
- Untracked(未跟踪):Git 尚未管理该文件。
- Modified(已修改):文件已更改,但未添加到暂存区。
- Staged(已暂存):文件已添加到暂存区,准备提交。
- Committed(已提交):文件的更改已存入版本库。
4.1.6 路径名与内容
在 Git 中,路径名(文件名)与文件内容是分开的。Git 仅存储文件的内容,而文件名存储在 Tree(树)对象 中。这种设计使得 Git 可以高效地处理重命名文件的操作,因为 Git 只需更新树对象,而不必存储新的 blob。
4.1.7 打包文件
当 Git 仓库增长时,存储大量独立对象会导致 .git/objects
目录变得庞大。为了解决这个问题,Git 采用 打包(Packfile) 机制来合并多个对象,减少存储空间和提升性能。
手动运行以下命令可以进行打包优化:
git gc
4.2 对象库图示
Git 的存储结构可以用下图表示:
Commit -> Tree -> Blobs(文件内容)
|
-> Tree -> Blobs(文件内容)
每次提交(commit)指向一个树(tree),树指向多个 blob(文件内容)。如果文件未修改,则新的提交仍然指向原有的 blob,从而节省存储空间。
4.3 Git 在工作时的概念
4.3.1 进入 .git 目录
.git
目录是 Git 版本库的核心,包含:
objects/
:存储 Git 对象(blob、tree、commit)refs/
:存储分支和标签HEAD
:指向当前分支config
:Git 配置文件
进入 .git
目录后,可以手动查看对象存储:
cd .git/objects
ls
4.3.2 对象、散列和 blob
在 .git/objects
目录下,每个对象文件名由 SHA-1 哈希值命名,例如 3b18e6
。可以使用 git cat-file
命令查看对象内容:
git cat-file -t 3b18e6
git cat-file -p 3b18e6
4.3.3 文件和 tree
Tree
记录了文件的组织方式,每个提交(commit)都会生成一个新的 Tree
,指向文件的 blob 对象。例如,查看某个提交的 tree:
git ls-tree HEAD
4.3.4 对 Git 使用 SHA1 的一点说明
Git 使用 SHA-1 哈希 作为对象的唯一标识符,以确保数据完整性。如果文件内容被篡改,其 SHA-1 哈希值将发生变化,Git 立即能检测到。
4.3.5 树层次结构
Git 的存储结构采用类似 Unix 的层次化文件系统,每次提交都会生成新的 tree 结构,而不是存储整个文件快照。
4.3.6 提交
每次 git commit
都会创建一个新的提交对象,该对象指向当前 tree,并记录提交信息。例如,查看最近一次提交的详情:
git show HEAD
4.3.7 标签
Git 标签(tag)用于标记特定的提交,例如创建版本发布标签:
git tag v1.0
查看所有标签:
git tag
结论
本章介绍了 Git 的核心概念,包括版本库、对象存储、索引、路径名与内容的关系、Git 的数据结构,以及 .git
目录的作用。掌握这些概念有助于深入理解 Git 的底层机制,为后续分支管理和协作开发打下基础。