Blob: Binary Large OBject
SHA: Secure Hash Algorithm
对象之间的指向关系如下,通过记录 SHA-1 哈希值来实现对象之间的引用。
例如 Commit 2
对象存储一个指向 Tree
对象的 SHA-1 值,以及它Parent Commit
(即Commit1
) 的 SHA-1 值。
特别注意几个地方
Tree SHA-1
指向项目根目录状态的 tree 对象Parent(s) SHA-1
指向一个或多个父提交对象commit
都指向一个完整的项目快照(通过 tree 对象),而不是记录文件间的差异。差异是在需要时(如 git diff
)动态计算出来的。COMMIT1 --> COMMIT2 --> COMMIT3 --> ... | | | v v v TREE TREE TREE / | \ / | \ / | \v v v v v v v v vB B T B B T B B B / \ / \ v v v v B B B B
一般我们关心的是Commit
对象,它们通过Parent SHA-1
形成一个有向无环图 - DAG,每个提交对象都指向它的父提交对象。通过这个结构,Git 可以高效地跟踪项目的历史版本。
一个分支可能会有多个 parent commit,例如下面合并操作产生的Merge commit
,它就有两个父节点
可以用上面所说的 plumbing commands 验证 git object 的内容
# 查看blob对象的内容$ git cat-file -p 38223a8b88cb79e6c50587200dddaa2bee632039*.log*.log.*history.txt**/state.yml**/state.jsonmisc/yasb/*.pyelevated-state.jsonlazy-lock.json*.bak# mac.DS_Store# chrome extension*.pak# 查看当前HEAD指向的commit对象的内容$ git cat-file -p HEAD~tree 6aa9038b7598f6c2fd28e1452ec12ce704889868parent df297f141f21ac41c6a225214b35729209e30b63parent b0a01d5c938c4bf617141898ecda2bfeeba39408author Efterklang <[email protected]m> 1747413172 +0800committer Efterklang <[email protected]m> 1747413172 +0800Merge branch 'main' of github.com:Efterklang/config# 上面输出了一个tree对象的SHA-1值,查看tree对象的内容$ git cat-file -p 6aa9038b7598f6c2fd28e1452ec12ce704889868100644 blob 38223a8b88cb79e6c50587200dddaa2bee632039 .gitignore100644 blob 1af14d0fa103a0b5dd83294bbffe622afb7fc3b7 .gitmodules100644 blob 5acc0b549e71749f3dcfed94df73799688f3fca5 LICENSE.md100644 blob 5f01256728f790fb046b4a5ddf56b686711c1479 README.md040000 tree b5e786a9baf2ddc55c0dcf76f0aaf33c914d271b application040000 tree 9c417f15cdf72696abfd4b9d0de89922c714ca3e assets160000 commit b8891c5fb72485316fba54d2c1310320c9ebf4d5 dotbot100755 blob 841bc2e32b2f56a44569d24a481c6d4902dfcf68 install.ps1100755 blob 89195ec2a3b9f68939b77a6b71d0834ffc1603e2 install.sh100644 blob 7f6171b6606dbd811e4ce74b445ba08e09c86545 linux.yaml100644 blob 522b64e9e3533bf61720e054667189eda272727e mac.yaml040000 tree e9734049cb57b7427d64b24691a8ac7849352538 misc040000 tree 18a69f6feba9237aeccac753abe939f3218ccfa3 packages040000 tree 70301eeee8f9a1f3db7d7c6e35c7da73deaf83f0 shells040000 tree 62f6055d5e5983c976802e570c565b4e68b2068d terminal040000 tree adf3d257c2b7e8b63677d0488bf8939d00a7ace8 tui_cli100644 blob 551b11fa060531730df24bf230182d8bf3052526 windows.yaml
引用类型 | 存储位置 | 主要用途 | 示例 |
---|---|---|---|
Local Branch | refs/heads/ | 标记本地开发线 | refs/heads/master |
Remote Branch | refs/remotes/ | 跟踪远程仓库分支 | refs/remotes/origin/master |
Tag | refs/tags/ | 标记特定提交点 | refs/tags/v1.0 |
HEAD | .git/HEAD | 指向当前工作点 | HEAD |
在 Git 中,“引用” (reference, 通常简写为 ref) 是指向提交对象 (commit object) 或其他引用 (如另一个分支或标签) 的指针。它们是 Git 用来追踪历史和分支的便捷方式。常见的引用有分支名 (如 main, feat/gjx) 和标签名 (如 v1.0.0
Git Refs: What You Need to Know | Atlassian Git Tutorial关于 Git Refs 的详细介绍可以参考这篇文章。
Ref 的设计有这么几个好处:
HEAD 是 Git 中最重要和最常用的特殊引用,通常指向当前检出的本地分支的最新提交(Symbolic HEAD
),但也可以“分离”出来直接指向某个特定提交(Detached HEAD
)。储在项目根目录下的 .git/HEAD
文件中。
另外,在执行git merge
, git cherry-pick
, git rebase
等操作时,Git 会创建一些临时引用,如 MERGE_HEAD
, CHERRY_PICK_HEAD
, REBASE_HEAD
等。这些引用用于跟踪正在进行的操作的状态。
在 Git 的内部实现中,branch 实际上是对某个提交(commit)的引用。存储在 .git/refs/heads/
目录下
例如,我建了main
,bugfix/fix1
,bugfix/别急
, feat/gjx
四个分支,在文件系统中体现为:
$ ll ./.git/refs/heads/drwxr-xr-x - gjx 21 May 00:25 bugfixdrwxr-xr-x - gjx 21 May 00:24 feat.rw-r--r-- 41 gjx 18 May 23:17 main$ tree ./.git/refs/heads/./.git/refs/heads/├── bugfix│ ├── 别急│ └── fix1├── feat│ └── gjx└── main
Git 分支名允许使用 /
作为分隔符,这是因为在 .git/refs/heads/
目录下,Git 会将分支名中的 /
解释为子目录分隔符。这样在大型 repo 中,可以使用层级结构来组织分支,便于管理和查找。有兴趣可以参考Conventional Branch
Ref 本身是一个文本文件,内容就是一个 SHA-1 哈希值,指向当前分支的最新提交对象。比如我用cat
命令查看一下bugfix/fix1
分支的内容,输出一行 SHA-1 哈希值,参考上面的操作,看下这个分支的内容。
# 分支就是一文本文件,直接cat出来$ cat .git/refs/heads/bugfix/fix1 File: .git/refs/heads/bugfix/fix1 Size: 41 B1 eac2c62fcf0fe905ea475d1eb94d0e6d42916da8# 看看这个commit的内容$ git cat-file -p eac2c62fcf0fe905ea475d1eb94d0e6d42916da8tree b09d937e4cdc5628e5818b08c7f3c303b5223470parent c53af81f5493d6c7aa1b7da30670da8b168d2c5cauthor Efterklang <[email protected]m> 1747581423 +0800committer Efterklang <[email protected]m> 1747581423 +0800feat(sketchybar): add more app icons
不过多赘述,日常中也不建议使用,just for fun
# 查看所有引用$ git show-refeac2c62fcf0fe905ea475d1eb94d0e6d42916da8 refs/heads/bugfix/别急eac2c62fcf0fe905ea475d1eb94d0e6d42916da8 refs/heads/bugfix/fix1eac2c62fcf0fe905ea475d1eb94d0e6d42916da8 refs/heads/feat/gjxeac2c62fcf0fe905ea475d1eb94d0e6d42916da8 refs/heads/maineac2c62fcf0fe905ea475d1eb94d0e6d42916da8 refs/remotes/origin/HEADeac2c62fcf0fe905ea475d1eb94d0e6d42916da8 refs/remotes/origin/main# 查看符号引用, 我现在在bugfix/别急分支上$ git symbolic-ref HEADrefs/heads/bugfix/别急
Git turns 20: A Q&A with Linus Torvalds - The GitHub Blog
Git Refs: What You Need to Know | Atlassian Git Tutorial
Conventional Branch
Learn Git Data Structure Design