Appearance
.git 目录结构
.git 目录是 Git 仓库的核心,包含了版本控制所需的所有数据。了解其结构有助于深入理解 Git 的工作原理。
objects/:对象存储
所有 Git 对象(Blob、Tree、Commit、Tag)都存储在 objects/ 目录:
.git/objects/
├── 1f/
│ └── 7a8b9c0d1e2f3456789012345678901234567 ← 松散对象
├── ab/
│ └── cdef0123456789012345678901234567890 ← 松散对象
├── info/ ← 包文件信息
└── pack/ ← 打包对象
├── pack-abc123.idx ← 索引文件
└── pack-abc123.pack ← 打包数据查看对象:
bash
# 列出所有对象
find .git/objects -type f
# 查看对象类型
git cat-file -t abc123
# 查看对象内容
git cat-file -p abc123
# 统计对象数量
git count-objects -vrefs/:引用存储
引用(分支、标签、远程追踪分支)存储在 refs/ 目录:
.git/refs/
├── heads/ ← 本地分支
│ ├── main
│ └── develop
├── remotes/ ← 远程追踪分支
│ └── origin/
│ ├── HEAD
│ └── main
└── tags/ ← 标签
├── v1.0.0
└── v1.1.0查看引用:
bash
# 查看分支引用内容(就是一个 SHA-1)
cat .git/refs/heads/main
# abc123456789...
# 列出所有引用
git show-refHEAD:当前分支指针
bash
cat .git/HEAD
# 正常状态(指向分支)
# ref: refs/heads/main
# 分离 HEAD 状态(指向 commit)
# abc123456789...index:暂存区数据
.git/index 是二进制文件,存储暂存区的状态:
bash
# 查看暂存区内容(index 的文本表示)
git ls-files --stage
# 100644 abc123... 0 README.md
# 100644 def456... 0 src/app.jsindex 文件包含:
- 文件路径
- 文件模式(权限)
- 对应的 Blob SHA-1
- 时间戳和文件大小(用于快速检测修改)
config:仓库级配置
bash
cat .git/config
# [core]
# repositoryformatversion = 0
# filemode = true
# bare = false
# logallrefupdates = true
# [remote "origin"]
# url = https://github.com/user/repo.git
# fetch = +refs/heads/*:refs/remotes/origin/*
# [branch "main"]
# remote = origin
# merge = refs/heads/mainhooks/:钩子脚本
Git 钩子是在特定事件发生时自动执行的脚本:
.git/hooks/
├── pre-commit.sample ← .sample 文件是示例,不会自动执行
├── prepare-commit-msg.sample
├── commit-msg.sample
├── post-commit.sample
├── pre-push.sample
├── pre-rebase.sample
└── ...
# 激活钩子:复制并去掉 .sample 后缀,赋予执行权限
cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commitlogs/:引用日志
reflog 存储在 logs/ 目录:
.git/logs/
├── HEAD ← HEAD 的 reflog
└── refs/
├── heads/
│ ├── main
│ └── develop
└── remotes/
└── origin/
└── mainbash
# 查看 HEAD reflog
cat .git/logs/HEAD
# (格式:旧SHA 新SHA 用户 时间 操作描述)其他重要文件
.git/
├── COMMIT_EDITMSG ← 最近一次提交的信息(供编辑器使用)
├── FETCH_HEAD ← 最近一次 fetch 的结果
├── MERGE_HEAD ← 合并过程中,被合并分支的 HEAD
├── MERGE_MSG ← 自动生成的合并提交信息
├── ORIG_HEAD ← 危险操作(reset、merge)前 HEAD 的位置
├── REBASE_HEAD ← rebase 过程中的当前提交
├── packed-refs ← 打包的引用(优化性能)
└── description ← 仓库描述(GitWeb 使用)packed-refs 文件:
bash
cat .git/packed-refs
# # pack-refs with: peeled fully-peeled sorted
# abc123... refs/heads/main
# def456... refs/remotes/origin/main
# ghi789... refs/tags/v1.0.0
# ^jkl012... ← 附注标签指向的 commit(^ 前缀)裸仓库的结构差异
裸仓库(git init --bare)没有工作区,.git/ 目录的内容直接在仓库根目录:
my-repo.git/
├── HEAD
├── config
├── objects/
├── refs/
└── ...手动操作示例
bash
# 手动创建一个分支(底层原理)
echo "abc123456789..." > .git/refs/heads/my-branch
# 等价于:git branch my-branch abc123456789...
# 手动查看 HEAD 指向什么
git symbolic-ref HEAD
# refs/heads/main
# 手动移动 HEAD(切换分支的底层操作)
git symbolic-ref HEAD refs/heads/develop
# 等价于:git switch develop总结
| 目录/文件 | 内容 |
|---|---|
objects/ | 所有 Git 对象(Blob、Tree、Commit、Tag) |
refs/ | 分支、标签、远程追踪分支的引用 |
HEAD | 当前位置的符号引用 |
index | 暂存区状态(二进制) |
config | 仓库级配置 |
hooks/ | 事件钩子脚本 |
logs/ | reflog 数据 |
packed-refs | 优化过的引用存储 |
理解 .git 目录结构,你就理解了 Git 所有概念的物理存储形式。当出现异常情况时,这些知识也能帮助你直接操作底层数据进行修复。