XingPiaoLiang's

Back

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
bash

Git Internal Object - Blob#

Blob(Binary Large Object),是被版本控制系统追踪的文件内容的本身。

Generally speaking: 每一个被 Git 跟踪的文件,都会被保存为一个 blob 对象。

  • blob 只保存文件的内容,不保存文件的其他元数据信息
  • Git 使用 SHA-1 对文件内容
Git Internal
https://astro-pure.js.org/blog/git-internal
Author erasernoob
Published at June 6, 2025
Comment seems to stuck. Try to refresh?✨