如何构建 `Git diff` 驱动
Source: Hacker News
自 2024 年 11 月 起,我一直想写一篇关于如何使用 git diff 为文件之间的比较创建外部命令的文章。
在实现 renovate-packagedata-diff 时,我发现几乎没有关于如何做到这一点的文档,因此值得写篇博客来介绍。
(我后来发现,在 Git Diffs 手册页 中确实有 一些 文档,只是并不容易被发现。)
这件事已经在我的待办事项里搁置了一段时间,最近又被 Andrew Nesbitt 在其关于 Git Diff Drivers 的优秀文章以及本周对使用 oasdiff 对 OpenAPI 规范进行 diff 的探索所提醒。
我想借此机会写一篇博客,介绍这项技术的工作原理,并另外发布一篇关于将 oasdiff 作为 diff driver 使用的文章(链接)。
注意: 这是一个我们希望在输出中展示更多信息的场景,不能仅依赖
textconv方法将(二进制)文件转换为更易比较的文本格式。在许多情况下,使用textconv已足够。
Source: …
我们需要处理哪些参数?
虽然许多工具如果期望以 tool [before] [after] 的形式运行,开箱即用,但 git diff 会向调用的外部工具传递 7 个参数。这提供了更丰富的数据,可能会很有用。
实例演示
更新已有文件
renovate-packagedata-diff
renovate/github-co-cddo-api-catalogue.json # 1: 仓库中的文件名
/tmp/git-blob-shryRa/github-co-cddo-api-catalogue.json # 2: “之前”的文件
f0a1311ae439fff36f994a3be5d5a7eb7d7a34dc # 3: “之前”文件的 SHA‑1 哈希
100644 # 4: “之前”文件的八进制模式
/tmp/git-blob-y2mrZp/github-co-cddo-api-catalogue.json # 5: “之后”的文件
e39975894a72f706e6a59bccf31120ffaa219ff3 # 6: “之后”文件的 SHA‑1 哈希
100644 # 7: “之后”文件的八进制模式添加新文件
renovate-packagedata-diff
renovate/github-co-cddo-api-catalogue.json # 1: 仓库中的文件名
/dev/null # 2: “之前”
. # 3: “之前”文件的 SHA‑1 哈希
. # 4: “之前”文件的八进制模式
/tmp/git-blob-iAbnMD/github-co-cddo-api-catalogue.json # 5: “之后”
5c55e5b99b21db68c360419d44dac906c336bec6 # 6: “之后”文件的 SHA‑1 哈希
100644 # 7: “之后”文件的八进制模式删除文件
renovate-packagedata-diff
renovate/github-co-cddo-api-catalogue.json # 1: 仓库中的文件名
/tmp/git-blob-aBldZ4/github-co-cddo-api-catalogue.json # 2: “之前”
6b24e38aa4aac8e00e44ab68e156744138ef6afc # 3: “之前”文件的 SHA‑1 哈希
100644 # 4: “之前”文件的八进制模式
/dev/null # 5: “之后”
. # 6: “之后”文件的 SHA‑1 哈希
. # 7: “之后”文件的八进制模式- 当文件被创建或删除时使用
/dev/null。 - 在这些情况下不相关的参数会以
.形式提供。
如果希望你的命令同时处理普通调用和 git diff 参数,也可以检查环境变量 GIT_PAGER_IN_USE 是否已设置。
使用 oasdiff 的示例
正如在我关于此的另一篇文章中所述,凭借上述信息,编写一个轻量级的包装器来比较 OpenAPI 规范的 oasdiff 工具是很直接的。
一个最小实现:
#!/usr/bin/env bash
# A diff driver for `git diff` to provide a human‑readable changelog for a given OpenAPI spec
# (based on https://www.jvt.me/posts/2026/04/11/oasdiff-driver/)
if [[ "$2" == "/dev/null" ]]; then
echo "$1 was added"
exit 0
elif [[ "$5" == "/dev/null" ]]; then
echo "$1 was deleted"
exit 0
fi
# Prefer colour always reported
oasdiff changelog "$2" "$5" --color always此脚本不处理权限更改,如有需要可以报告,并且基于文件的 SHA‑1 校验和缓存结果可能是值得的。