知其然,知其所以然
Gin 框架内部原理 2026-10-11

测试:httptest 与 CreateTestContext

在 Gin v1.12.0 里实测测试写法:NewRecorder + ServeHTTP 的默认值(RemoteAddr 192.0.2.1);CreateTestContext 的 Context 没有 Request、Params 与路由;记录器的 w.Header() 能看到写完才设的头,而 Result() 与真实客户端看不到;go test 里默认是 debug 模式;ServeHTTP 约 2.1 µs,真实 HTTP 约 53.1 µs。

Gin 测试 httptest CreateTestContext Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

基准:Gin 与标准库 ServeMux(Go 1.22+ 的模式匹配)

在 Gin v1.12.0 与 Go 1.27.1 的 http.ServeMux 之间做对等的比较:行为差异(405、HEAD、尾斜杠、通配符值是否带斜杠);路由匹配 Gin 26~102 ns、ServeMux 130~201 ns,Gin 命中 0 次分配;但 handler 写一个小 JSON 时 ServeMux 517 ns、Gin 589 ns,路由的差异被淹没。

Gin http.ServeMux 基准测试 路由性能 Go 1.22 Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

Handle、Any 与自定义 HTTP 方法

在 Gin v1.12.0 里用真实 curl 实测自定义方法与 Any:Handle 注册 PURGE / PROPFIND / REPORT 等方法并正常匹配;Any 注册 9 个方法(包含 TRACE、CONNECT),Match 只注册指定的;HEAD 与 OPTIONS 不会自动处理,方法名区分大小写;打开 HandleMethodNotAllowed 后 Allow 头里包含自定义方法。

Gin 自定义HTTP方法 Handle Any Match HEAD OPTIONS Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

中间件里起的 goroutine 发生 panic:Recovery 管不管

用真实进程实测 handler 里起的 goroutine 发生 panic:Recovery 管不到,整个进程以退出码 2 崩溃(即使 handler 早已返回),同时在途的其它请求也全部失败;handler 里直接 panic 则被 Recovery 接住;给 goroutine 加 recover 的 safeGo 写法能让服务继续运行。

Gin goroutine panic Recovery 崩溃 Go 真实验证 动画演示
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号