知其然,知其所以然
Git 内部原理 2026-10-12

credential helper 协议

实测 git 的凭据协议:用 git credential fill / approve / reject 驱动 helper 的 get / store / erase,stdin 是 key=value 行;useHttpPath 决定是否传 path;用 git http-backend 起一个要求 Basic 认证的本机服务,看到 401 → helper get(带 wwwauth 质询)→ 带认证的请求 → store,密码错则 erase;多个 helper 取凭据按顺序第一个给出的赢、存凭据广播;credential-store 明文保存,权限 600。

Git credential helper 凭据 认证 真实验证 动画演示
Git 内部原理 2026-10-12

clean/smudge filter 与自定义 merge driver

实测 clean/smudge 过滤器:add 时 clean 后存进 blob(工作区不变),checkout 时 smudge;status/diff 在内容或 stat 变化时调用 clean;clean 有损时真实内容会在检出时丢失;hash-object --no-filters 看原样内容;clean(smudge(x)) 必须等于 x;自定义 merge driver 收到 %O %A %B %L %P,退出 0 采用 %A 里的结果;内置 text/binary/union 对同一冲突的处理。

Git clean smudge filter merge driver gitattributes 真实验证 动画演示
Git 内部原理 2026-10-12

git maintenance 的任务

实测 git maintenance:10 个任务名各自改变仓库的什么(loose-objects 两次才清理松散对象、pack-refs、commit-graph、geometric-repack、gc);prefetch 把远程分支下载到 refs/prefetch;maintenance.strategy 的四种取值实际启动的子命令;--auto 的阈值(commit-graph.auto 与 loose-objects.auto 默认 100,达到才运行);maintenance.<任务>.enabled 的效果。

Git maintenance gc commit-graph prefetch loose-objects strategy 真实验证 动画演示
Git 内部原理 2026-10-12

大仓库:对象数量增长时 status 和 log 的耗时

实测对象数量增长时各命令的耗时:提交数 1,000 → 40,000 时 status 与 log -1 不变、整段历史的遍历随提交数增长;文件数 1,000 → 50,000 时 status、add -A、commit 随文件数增长;松散对象的遍历比打包慢约 10 倍、占盘约 32 倍;带路径的 log 在 commit-graph 与 --changed-paths 下从 246 ms 降到 76 ms;file:// 克隆的耗时与大小。

Git 大仓库 性能 status log commit-graph clone 真实验证 动画演示
Git 内部原理 2026-10-11

手工解开 .git/objects 里的 blob、tree、commit:原始字节长什么样

在真实的 git 2.54.0 仓库里手工解开 .git/objects:blob 是“blob 长度\0内容”,tree 是模式、名字、20 字节二进制 hash 的连续条目,commit 是几行头加说明的纯文本;只用 Python 的 zlib 沿 HEAD 往下走一遍,结果与 git ls-tree -r 完全一致。

Git 对象存储 blob tree commit zlib 真实验证 动画演示
Git 内部原理 2026-10-11

SHA-1 怎么算出来的:对象头加内容,手算结果与 git 一致

用 Python 的 hashlib 手算 git 的 hash:blob 是 SHA-1("blob 长度\0内容"),tree 与 commit 同一公式,手算结果与 git hash-object、write-tree、commit 全部一致;改一个字节 160 位里有 86 位翻转;同内容不同文件名或权限的 blob hash 相同;同样 12 字节放进四种对象类型得到四个不同的 hash。

Git SHA-1 hash-object 对象模型 真实验证 动画演示
Git 内部原理 2026-10-11

tree 对象:100644、100755、120000、160000 四种模式

在真实仓库里放进普通文件、可执行文件、符号链接和子模块,对照 git ls-tree 与 tree 对象的原始字节:四种模式 100644、100755、120000、160000;符号链接的 blob 内容就是目标路径;子模块条目是子仓库的 commit hash,在主仓库里根本找不到这个对象;写其它模式时 git 会规整成这四种之一。

Git tree 文件模式 符号链接 子模块 gitlink 真实验证 动画演示
Git 内部原理 2026-10-11

commit 对象:parent 个数、author 与 committer 的区别

在真实仓库里数 commit 对象的 parent 行(根提交 0、普通 1、合并 2、章鱼合并 3);用 amend 和 cherry-pick 验证 author 保留、committer 与时间改变;同一提交的两个时间戳互相独立,头部的时区只影响显示;parent 的顺序决定 HEAD^1 / HEAD^2 / --first-parent 的含义。

Git commit parent author committer 真实验证 动画演示
Git 内部原理 2026-10-11

注解标签与轻量标签:tag 对象里有什么

在真实仓库里区分轻量标签与注解标签:轻量标签只是一个 ref 文件(对象数不变),注解标签多一个 tag 对象(对象数 3 → 4,ref 指向它而不是 commit);读 tag 对象原文,用 ^{} 剥开;describe 默认只看注解标签;标签可以指向 tag、tree、blob;push --follow-tags 只推注解标签;删标签后 tag 对象成为悬空对象。

Git tag 注解标签 轻量标签 真实验证 动画演示
Git 内部原理 2026-10-11

改一个字,后面所有 commit 的 hash 为什么全变

在 5 个提交的链上改第 2 个提交的一个字:第 1 个 hash 不变,第 2~5 个全变,尽管后三个的内容一个字没动;原因是 parent 行进了 commit 的 hash;只改说明时 tree 完全不变,改文件内容只让被改的那个 tree 变;改最新的提交只影响 1 个。

Git hash Merkle filter-branch 历史改写 真实验证 动画演示
Git 内部原理 2026-10-11

SHA-256 仓库:object-format 不同的仓库结构有什么变化

在真实 git 2.54.0 里创建 --object-format=sha256 仓库并与 sha1 仓库对比:repositoryformatversion 变成 1,hash 40 位变 64 位,blob 公式换成 SHA-256 手算一致,tree 条目的 hash 20 字节变 32 字节(10 个文件 359 → 479 字节),index 786 → 970 字节;两种仓库之间 fetch 直接报 mismatched algorithms。

Git SHA-256 object-format 对象模型 真实验证 动画演示
Git 内部原理 2026-10-11

空目录为什么提交不了

在真实仓库里验证空目录提交不了:git add 成功但什么都不加,clone 出来没有它;暂存区只有文件路径;手工用 mktree / commit-tree 造出带空 tree 条目的提交,fsck 不报错,检出时 git 也不会创建空目录;常用的 .gitkeep 与 .gitignore 两种占位做法。

Git 空目录 .gitkeep tree 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号