通过 .git 目录理解git原理 (一)译
.git 目录有哪些东西
当你使用 git init
命令创建一个 Git 仓库,Git 将创建一个 .git
的文件夹。这个文件夹包含 Git 工作的所需要用到的所有信息。 要清楚,如果你想在你的项目中删除 Git,但需要保留项目文件,你只需要删除 .git
文件夹即可。
如下你在第一次提交前 .git
文件夹里的内容
1 | |____.git |
HEAD
下文将详细介绍config
这个文件包含你的 Git 仓库的配置信息,这里记录了远程的 url、邮箱、用户名等信息,每次你使用git config --local -l
命令,将展示此文件的配置信息。description
用于 gitweb (比方说 github) 来展示 Git 仓库的描述信息。hooks
这是一个非常有趣的特性。他们是 Git 自带的一组脚本。 Git 会在每个有意义的阶段自动运行这些脚本。这些脚本称作为hooks
。他们在执行commit
、rebase
、pull
… 之前或之后运行这些脚本,脚本的名称表示了何时将运行他们。举个例子,pre-push
脚本将在执行git push
命令之前执行,目的是为了做提交到远程前的一些检查,保持远程仓库和本地仓库的一致性。info/exclude
通常我们是将不希望 Git 管理的文件放在.gitignore
配置文件中。exclude
文件和.gitignore
文件作用相同,只是不会被共享。例如,你不想让 Git 管理跟踪于自定义的 IDE 产生的相关的文件,又不希望放在.gitignore
中被提交上去,就可以用这种方式,虽然这种方式实在没有必要。
提交的内容是什么
每次你创建一个文件,并且跟踪他,Git 将它压缩,并用自己的数据结构保存。被压缩的对象有一个唯一的名字和哈希,存储在 objects
文件夹下。
在浏览 objects
文件夹前,我们必须明白是么是一次 commit
。commit
是一种你工作目录的快照(snapshot),但这还不止于此。
实际上,当您提交 Git 时,只有两件事可以创建工作目录的快照:
- 如果文件没有改变,Git 仅仅将被压缩文件的名称(哈希)记录到快照中。
- 如果文件发生改变,Git 将压缩他,并且将压缩文件存储到
objects
文件夹中。最后,它将压缩文件的名称(哈希)添加到快照中。
这是简化的介绍,整个过程会有点复杂,将在以后的文章中介绍。
一旦创建了快照,快照也将被压缩并以哈希命名,所有这些压缩对象都存放在objects
文件夹中。
1 | |____93 |
这是我创建了一个空文件 file_1.txt
并且提交了它之后 objects
文件夹的内容。如果你的文件哈希值是 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
,Git 将存储这个文件到 e6
子文件夹中,并将文件名命名为 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
, 这种方法会使 objects
文件夹数量最多为 255 个(00 ~ FF)
这里我们看到 3 个哈希值,一个是我们创建的 file_1.txt
文件,一个是我们 commit
时创建的工作目录快照,那另一个是什么呢? 因为提交本身就是一个对象,所以它也被压缩并存储在 objects
文件夹中。
我们需要记住一次 commit
会创建4个信息:
- 各个被
git add
,并发生修改、增加、删除文件本身的哈希文件 - 工作目录快照哈希文件(修改、增加、删除的文件列表)
- 提交者的信息哈希文件,包含作者、commit message
- 上一次提交的hash
我们解压缩一下提交的哈希文件
1 | ➜ git cat-file -p 9381648a3b1fe0eb310bdd9c87f001f83e132375 |
我们看到工作目录快照的哈希信息、作者、和 commit message。
这里有两个信息非常重要:
- tree
86550c31847e518e1927f95991c949fc14efc711
工作目录快照信息 - 由于是第一次提交,没有上一次提交的哈希
如果你再修改一下这个文件,就可以看到 parent
上一次提交的哈希信息
1 | ➜ git cat-file -p dbe709db4cda426395cf23fe3063f18128f339e7 |
工作目录快照信息:
1 | ➜ git cat-file -p 86550c31847e518e1927f95991c949fc14efc711 |
在这里,我们找到了提交文件本身的哈希 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
branch, tags, HEAD 都是指针
我们现在了解了 Git 中的所有内容都是使用正确的哈希值进行访问的。
现在让我们看一下 HEAD
中有什么内容:
1 | ➜ cat HEAD |
HEAD
表示的是当前分支的指针信息,我们在看看 refs/heads/master
是什么内容:
1 | ➜ cat refs/heads/master |
似曾相识的信息,他就是我们第一次提交的哈希信息。这说明分支、标签都是执行提交的指针。这意味着你可以删除所有分支、标签,但他们的提交都保留着,这只会给我们的访问带来一定的困难。如果你想了解更多,你可以阅读 gitbook
原文链接
Git series 1/3: Understanding git for real by exploring the .git directory