代码 diff 在编辑长度与可读性间取舍
Git 文本差异默认采用 Myers 路径;选择 patience 时先利用双方唯一的公共行建立锚点,再处理锚点之间的差异。
相关概念
工程问题#
重复括号、空行与重排代码可能产生多种合法对齐;较短的插删序列未必最便于审查。
实际实现#
Myers 搜索编辑图中的路径,Git 实现含成本启发式。Patience 用哈希记录唯一公共行,选取保持顺序的锚点并递归,无锚点区域回退到经典 diff。
处理流程#
- 读取两份文本并准备行记录。
- 按参数选择 Myers 或 patience。
- 搜索编辑路径,或先构造有序锚点。
- 合并子区域结果并输出差异块。
源码片段#
固定版本 · 原文摘录xdiff/xpatience.cv2.46.0 · L356–L368
356 result = find_longest_common_sequence(&map, &first);357 if (result)358 goto out;359 if (first)360 result = walk_common_sequence(&map, first,361 line1, count1, line2, count2);362 else363 result = fall_back_to_classic_diff(&map,364 line1, count1, line2, count2);365 out:366 xdl_free(map.entries);367 return result;368}patience_diff
Patience 先求保持顺序的公共唯一行序列,有锚点便递归处理分隔区域;没有合适锚点则调用经典 diff 回退。此分支之前已构建行哈希映射,Myers 编辑路径核心在 xdiffi.c。
片段展示 patience 的算法组合和回退;Git 默认 Myers 路径与最小化选项在外部分派,不意味着默认启用 patience。
收益与取舍#
工程分析带来的收益
- 默认算法提供通用的文本差异计算。
- Patience 可改善部分重复和重排代码的对齐。
付出的代价
- 默认启发式不保证最短编辑结果。
- Patience 依赖合适锚点,也不保证结果总更易读。
可比较的选择
--minimal投入更多计算寻找更小差异,但最少改动行数不等于语义最佳对齐。
版本与适用范围#
限 Git 2.46.0 内置文本行 diff;外部 diff 驱动、二进制比较及配置覆盖另论。算法识别文本变化,不理解代码语义。
参考来源#
源码、官方文档与原始论文02
Git 2.46.0 Patience 锚点与回退
源码2.46.0xdiff/xpatience.c · xdl_do_patience_diff; find_longest_common_sequence; fall_back_to_classic_diff
相关实现与比较#
4 个相关案例QEMU TCG 用 QHT 保存 TranslationBlock 索引,帮助复用与当前客体执行状态一致的翻译结果。
附源码片段 · 缓存与复用
libvirt 为 Domain 对象维护 UUID 与名称两个哈希索引,两个入口指向同一个对象。
附源码片段 · 索引与查找
把上下文身份编码进块哈希,让重复请求共享已经计算的 KV cache。
附源码片段 · 缓存与复用
Redis 有序集合既要按成员查分数,也要按分数和名次遍历;较大集合通过两种索引服务这些访问方式。
附源码片段 · 索引与查找