Git Internal
explore the basic .git/ directory and the internal git
Git-internal#
探究 Git 的基本原理。
.git Directory#
.git 文件夹包括以下组成部分:
$ tree .git -L 1
.git
├── COMMIT_EDITMSG
├── FETCH_HEAD
├── HEAD
├── ORIG_HEAD
├── branches
├── config
├── description
├── hooks
├── index
├── info
├── lfs
├── logs
├── objects
├── packed-refs
└── refs
8 directories, 8 files
bash.git/config#
配置文件,包含了这个 repository 的具体的配置信息:
- username,email
- remote,branch 具体示例如下:
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
[submodule]
active = .
[remote "origin"]
url = https://github.com/erasernoob/blog.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
vscode-merge-base = origin/main
toml我们也可以通过 git config list
命令来具体查看配置文件信息。
.git/description#
该文件主要被 GitWeb 程序进行使用来展示当前仓库的描述信息,对 Git 的本身功能没有影响。当前博客仓库内容如下:
Unnamed repository; edit this file 'description' to name the repository.
bash.git/HEAD#
HEAD 头节点是一个指针,指向当前工作分支的最新的一次提交的引用。当我们执行 git checkout main
时头节点 HEAD 此时便指向 main 分支的最新 commit 。
Detached HEAD: 头节点分离状态,执行
git checkout abc1234
此时 HEAD 不再指向分支名而是指向某一个具体的 Commit 正常状态:HEAD
指向某一个分支比如main
ref: refs/heads/main
bash.git/info#
该文件主要的角色类似于本地 .gitignore , info 文件中包含了那些没有被 .gitignore 文件包含的需要 excluded 的文件/文件夹。这些只针对于该本地仓库,非常适合在进行多人协作开发项目的时候,不想更改远程项目的 .gitignore 且想让某些本地文件不被 git 追踪的情况。
$ cat .git/info/exclude
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
bash.git/hooks#
该文件夹中包含了 Git 操作时的钩子函数。包括 commit, receive, merge 等等操作,这些钩子函数会在执行这些操作前后自动运行,非常适合更新代码 style 或者设置运行 pre-commit-test等等检查。
git 初始化时,会自动生成一些 hook sample:
hooks/
├── applypatch-msg.sample
├── commit-msg.sample
├── fsmonitor-watchman.sample
├── post-update.sample
├── pre-applypatch.sample
├── pre-commit.sample
├── pre-merge-commit.sample
├── pre-push.sample
├── pre-rebase.sample
├── pre-receive.sample
├── prepare-commit-msg.sample
├── push-to-checkout.sample
├── sendemail-validate.sample
└── update.sample
0 directories, 14 files
bash.git/objects#
这个文件夹存储了 git 版本管理所需要的所有数据文件(blob, commit, trees, tags…)。文件夹中使用 SHA-1 哈希算法值来组织所有数据。其中,前两个字符用于标识文件夹,其余的字符用于表示文件名称。
├── 14
│ └── 7401cd376d0d784cd49294ab579e72b369cf43
├── 2d
│ └── 428d2dab4b0228e1f8b7f484f52a8846877575
├── 3b
│ └── af62bdb5a9e9357ea6359961a8a21da167e08b
├── 4f
│ └── 279b4644358a80f38205348fb7835da2b9efec
├── f3
│ └── ca32b917ce91a33b2ec5f5d8619d3f5ed65428
├── fa
│ └── 70230dc9dda1b7be205c4f04ee350a33ca931f
├── ff
│ └── 4bde24abd82a8112149af9d4889fe116726280
├── info
└── pack
bash.git/refs#
在这个文件夹中保存了对数据对象(主要是 commit )的引用,这些引用的存储形式为 file,内容通常是以 SHA-1 哈希值的 commit 节点对象,本质就是指向特定 commit 的指针i
refs/
├── heads
│ └── main
├── remotes
│ └── origin
│ ├── HEAD
│ └── main
└── tags
4 directories, 3 files
bash.git/COMMIT_EDITMSG#
该文件中存储的是最新一次 commit 的信息。
erasernoob:/blog/.git# cat COMMIT_EDITMSG
feat: 修正发布时间
bash.git/index#
也被称作 staging area file,该文件持续追踪当前工作目录(未提交)和最新一次 commit(HEAD)之间的差异。当我们执行 git commit
命令时,Git 会直接使用这个 index 文件来创建一个新的 commit 对象。
.git/logs#
顾名思义,这个文件夹中存储着各种指针(reference)的的历史记录(Branch,Tags, HEAD…)
tree logs
logs
├── HEAD
└── refs
├── heads
│ └── main
└── remotes
└── origin
├── HEAD
└── main
4 directories, 4 files
bashGit Internal Object - Blob#
Blob(Binary Large Object),是被版本控制系统追踪的文件内容的本身。
Generally speaking: 每一个被 Git 跟踪的文件,都会被保存为一个 blob 对象。
- blob 只保存文件的内容,不保存文件的其他元数据信息
- Git 使用 SHA-1 对文件内容