.git
这个隐藏文件夹可以视为 git 的本地仓库,其内部文件主要由以下部分组成,有些是文件有些是文件夹。
└── .git
├── COMMIT_EDITMSG # 保存最新的commit message
├── config # 仓库的配置文件
├── description # 仓库的描述信息,主要给 gitweb 使用
├── HEAD # 指向当前分支
├── hooks # 存放一些shell脚本,可以设置特定的git命令后触发相应的脚本,.sample 后缀的脚本文件不会被执行
├── index # 二进制暂存区(stage)
├── info # 仓库的其他信息
│ └── exclude # 本地的排除文件规则,功能和 .gitignore 类似,区别在于 .gitignore 会被提交到版本库中,info/exclude 文件中的排除规则不会被提交到版本库
├── logs # 保存所有更新操作的引用记录,主要用于 git reflog 等
├── objects # 所有文件的存储对象,以 hash 值最为目录名,前两位 hash 值作为父目录
└── refs # 具体的引用,主要存储分支和标签的引用,是提交对象(commit object)的指针,把 hash 映射为 branch name
其中四个条目很重要:HEAD 文件、index 文件,objects 目录、refs 目录。
HEAD 文件通常是一个符号引用(symbolic reference),指向目前所在的分支。某些情况下,HEAD 文件可能会包含一个 git 对象的 SHA-1 值,譬如 checkout FETCH_HEAD 后。
- index 文件保存暂存区信息
- objects 目录存储所有数据内容
- refs 目录存储指向数据(分支、远程仓库和标签等)的提交对象的指针
对象
git 内部有三类对象,数据对象、树对象和提交对象。
- 数据对象(blob object),只存文件内容
- 树对象(tree object),组织结构并存储文件名
- 提交对象(commit object),包含提交信息和树对象
git对象存储
向 Git 仓库提交的所有对象都会有个头部信息一并被保存。
头部信息内容为:类型(blob、tree、commit) + 文件长度 + null
每次我们运行 git add 和 git commit 命令时,Git 所做的工作实质就是将被改写的文件保存为数据对象,更新暂存区,记录树对象(index 文件),最后创建一个指明了顶层树对象和父提交的提交对象。
底层工具
git 附带了一些底层工具,可以进行一些诸如 hash 计算等的底层操作,实际上 git 的各个命令也都是利用底层工具实现的。
git hash-object 计算 hash 键值。 -w 会指示该命令不要只返回键,还要将该对象写入数据库中。
1 2
# 对一个文件进行 hash 计算, 并写该文件到 git 库 $ echo 'test content' | git hash-object -w --stdin
git cat-file 显示文件内容
1 2 3 4
# 显示文件内容 $ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 # 显示文件类型 $ git cat-file -t d670460b4b4aece5915caf5c68d12f560a9fe3e4
git update-index 创建暂存区
1 2 3 4
# 从 git 库创建暂存 $ git update-index --add --cacheinfo 100644 `blob hashcode` test.txt # 从工作区创建暂存 $ git update-index --add new.txt
git write-tree 生成树对象
1 2
# 从暂存区生成树对象 $ git write-tree
git commit-tree 生成提交对象
1 2 3 4
# 首次提交,无父提交 $ echo 'first commit' | git commit-tree `tree hashcode` # 非首次提交,有父提交 $ echo 'second commit' | git commit-tree `tree hashcode` -p `parent commit hashcode`