关于 文本比较与差异检查
文本比较与差异检查器把同一份文本的两个版本并排放好,标出改动的位置。粒度由你选择——字符、单词或行——另有四个归一化选项决定「什么才算差异」。结果显示为两个面板:A 中高亮删除内容,B 中高亮新增内容。
一次 diff 是在回答一个你没说出口的问题,而粒度就是你说出它的方式。行模式回答「哪些行被改了」,这正是版本控制展示的东西,也是评审需要的。单词模式回答「这句话里改了什么」,它把连续空白视为无意义,所以重新折行根本不产生差异。字符模式回答「究竟哪几个字符不同」,这是比对哈希或端口号时唯一有用的模式。选错粒度,你会得到一个技术上正确、却恰好藏住了目标改动的结果。
如何使用这个开发者工具
- 把原始版本粘贴到面板 A,修改后的版本粘贴到面板 B。
- 选择粒度:文件和配置用「行」,正文用「单词」,短值用「字符」。
- 四个归一化选项要在第一次运行之前就设好,而不是之后再补。忽略大小写、忽略空白差异、忽略空行、忽略行序,默认全部关闭。
- 执行比较,两个结果面板一起读。面板 A 是原文并高亮删除内容,面板 B 是新版并高亮新增内容。
- 如果整份文件看起来全变了,打开「忽略空白差异」再跑一次。两次结果之差会告诉你,这次改动是实质性的还是纯粹排版。
实例:配置文件里一个字符的改动
同一份服务配置的两个版本,只差端口号里的几位数字。在行模式下,工具会把整行报告为被替换——对「哪一行变了」这个问题这是正确答案,对「哪个字符变了」就令人抓狂。
A:
server:
host: api.internal
port: 8080
retries: 3
timeout: 30
B:
server:
host: api.internal
port: 8443
retries: 3
timeout: 30面板「A 差异」
server:
host: api.internal
port: 8080 <- 高亮为删除
retries: 3
timeout: 30
面板「B 差异」
server:
host: api.internal
port: 8443 <- 高亮为新增
retries: 3
timeout: 30把同一对文本切到字符模式,结果会收窄到真正变动的三位数字:080 标为删除,443 标为新增,开头的 8 保持不变。在「已经知道该看哪一行」之后,这是对的模式;用它来「找出那一行」,则是错的模式。
粒度与四个归一化选项
前三行是模式开关,后四行是复选框。换行符不在表内,是因为比较前两侧的 CRLF 和 CR 都已转为 LF,混合换行永远不会被当成差异。
| 设置 | 比较时看到的单位 | 要当心什么 |
|---|---|---|
| 字符模式 | 逐个字符,空白也算 | 超过几行就读不下去,速度也更慢 |
| 单词模式 | 空白分隔的记号,连续空白视为无意义 | 重新折行完全不产生差异 |
| 行模式 | 整行,包含行尾换行 | 改一个字符也会被报告为整行替换 |
| 忽略大小写 | 两侧先转成小写 | 会掩盖只改了大小写的真实重命名 |
| 忽略空白差异 | 连续空格与制表符压成一个,换行两侧空格去掉 | 在 Python、YAML 这类缩进即语法的语言里会掩盖真实改动 |
| 忽略空行 | 两侧的空行与纯空白行都被丢弃 | 会掩盖夹具文件和 Markdown 里有意保留的空行 |
| 忽略行序 | 两侧先按行排序再比较 | 确实不同的两份文件可能比出完全相同 |
常见问题排查
内容看着一样,却每一行都被报告为改动。
成因 有什么东西重写了每一行的空白:跑过格式化器、缩进从制表符换成了空格,或者编辑器保存时清掉了行尾空格。这里的元凶不是换行符,因为比较之前两侧的 CRLF 和 CR 都已归一化为 LF。
解决办法 打开「忽略空白差异」再跑一次。如果差异随之清零,说明这次改动纯属排版。请把格式化和逻辑改动分成两次提交,好让下一个评审者一次只看一样。
被整块搬走的内容,被报告成一处删除加一处一模一样的新增。
成因 算法匹配的是最长公共子序列,它没有「移动」这个概念。把四行从文件开头挪到结尾,表达出来就是开头删掉这四行、结尾新增同样的四行。
解决办法 打开「忽略行序」确认两份文件包含的行确实相同,然后再关掉,专门审视位置的变化。遇到大规模重排,就把每个被搬动的块和它的新位置单独比较。
打开「忽略行序」之后,两份明显不同的文件比出了完全相同。
成因 这个选项会在比较前把两侧逐行排序,等于彻底丢掉顺序信息。只要两份文件包含的行集合相同,无论怎么排列都会判为相同。
解决办法 只把它当作快速的成员关系检查,性质和列表比较工具一样。顺序有含义的文件绝不能靠它放行,比如路由表、中间件链或迁移脚本序列。
段落重新折行之后,单词模式说没有差异。
成因 单词模式在设计上就把连续空白视为无意义,所以换个位置断行、把两个空格改成一个,都不算差异。
解决办法 对正文来说这通常正是你要的。当你检查的对象本身就是空白时,比如夹具文件或定宽报表,请切到行模式或字符模式。
适合用这个工具的场景
- 比较两套环境的配置文件,看清到底哪些值不同。
- 检查某个自动化工具改了文件里的什么,尤其是这次改动没有走版本控制的时候。
- 用单词模式评审改写过的段落,结果读起来很像修订标记。
- 确认两个长值——令牌、校验和、Base64 数据块——是否一致,不一致时找出从哪里开始分叉。
应该换用别的工具的场景
- 比较只关心成员关系、不关心顺序的两份列表。列表比较工具直接回答这个问题,还会把交集给成可复制的列表。
- 比较键顺序不同的两份 JSON。请先用 JSON 格式化工具处理两边,或者比较解析后的值,否则文本 diff 会把每个换位的键都报成改动。
- 合并改动或审阅分支历史。文本 diff 没有共同祖先的概念,三路合并请交给 Git。
隐私与数据处理
两份文本都在当前浏览器标签页内比较,绝不上传、不保存、不记录日志。做 diff 是个容易带进敏感材料的习惯——生产配置对预发配置、故障前后的日志摘录——所以请只粘贴刚好能体现这处改动的最小片段。本地处理只能保证内容不进我们的服务器,不构成把材料从原系统里复制出来的理由。
相关开发者工具
常见问题
需要担心 Windows 换行符吗?
不需要。比较之前两侧的 CRLF 和 CR 都会转换为 LF,所以一份在 Windows 上保存、一份在 Linux 上保存的文件,不会仅因此产生差异。这是少数几个「换行符已经帮你处理好了」的地方。
应该从哪个模式开始?
几乎总是行模式。它对应文件真实的编辑和评审方式,能最快缩小范围。确定了要看哪一行之后再切字符模式;文本是正文而不是代码时,用单词模式。
diff 能告诉我哪个版本是对的吗?
不能。它只报告差异,差异本身不含方向,也不含对错。该保留哪个版本,要靠测试、评审,以及文件所属的那个系统来决定。
为什么开了忽略空白,第一行的缩进还在?
这个选项把连续空格和制表符压成一个空格,并去掉换行两侧的空格。文本最开头的空白并不紧邻换行,因此可能留下一个空格。只要两侧处理方式一致,它对比较结果没有影响。
能一次比较两份以上的文本吗?
一次不行,而且三方比较本质上是另一种操作,它需要一个共同祖先才能把每处改动归属清楚。请先比 A 和 B,再比 B 和 C;需要调和对同一原件的两处编辑时,用 Git 的合并工具。
能处理多大的文本?
比较在当前标签页内运行,因此受浏览器内存和所选模式的共同限制。几千行文件用行模式很轻松;同样的输入换成字符模式,会明显更慢,也难读得多。