
內容摘要
用 Diff 比對工具比較兩段文字或檔案:並排與統一檢視、行/詞/字元粒度、空白過濾,以及怎麼讀懂 patch。
Diff 比對工具會直接告訴你兩份文字之間改了什麼——哪些行被新增、哪些被刪除、哪些被改寫——而不是叫你自己用眼睛掃過兩份文件。這篇指南說明怎麼執行比對、怎麼讀結果,以及哪些設定會決定輸出是有效訊號還是一堆噪音。
它適用於原始碼、設定檔、SQL migration、合約與文章,而且比對完全在你的瀏覽器裡完成。要比對兩份 JSON payload 之前,先用 JSON 格式化工具 把兩邊正規化,才不會把縮排也當成變更;如果拿到的是 Base64 編碼後的文字,先用 Base64 編碼 / 解碼 解開。
01Diff 到底在比什麼
Diff 不是逐字元比對相等,而是計出兩邊之間的最短編輯腳本(shortest edit script)——用最少的新增與刪除行數,把一個版本變成另一個——再回報這些新增與刪除:只出現在左邊的行是刪除,只出現在右邊的行是新增,其餘是上下文。Git 預設用的 myers 演算法解的就是同一道問題。
這解釋了為什麼長文件裡的一個小修改只會產生很小的 diff——即使兩份文件差了上百個字元,也只有被改動的行會被標記。實務上有兩個後果值得注意:
- 被搬移的區塊看起來像刪除加新增,因為算法比的是位置而不是意圖。
- 排版變更——重新縮排、換行符號改變、行尾空白——都會被當成真實差異,除非你叫工具忽略它們。
02比對兩段文字
- 把原始版本貼進 Original — 左邊是基準版本。可以貼上、手打,或用 Upload 上傳檔案。
- 把修改版本貼進 Modified — 右邊放新版本。兩邊都能接受大量貼上與檔案上傳。
- 按 Compare — 結果區會用紅色標記刪除、綠色標記新增,摘要則回報有多少個區塊變更、新增與刪除了幾行。
- 在變更之間跳轉 — 用 Previous 與 Next 逐塊移動,不必自己滾動。計數器(例如「3 changes · 2 added · 1 deleted」)會告訴你實際動了多少。
- 選擇並排或統一檢視 — Split 把兩個版本左右對齊;Unified 收成單一 patch 欄位,也就是審閱者熟悉的格式,貼進工單時用的就是它。
- 調整粒度與過濾 — 在 Line、Word 與 Char 之間切換,差異只在排版時打開 Ignore whitespace 或 Ignore case。
- 交換、複製或匯出 — Swap Sides 反轉比對方向,Copy 取出任一欄,Export .patch 下載標準統一差異檔,也就是
git apply讀得懂的格式,可直接附在審閱裡。
03行、詞或字元粒度
行粒度是預設值,也是程式碼與設定檔的正確選擇,因為審閱就是以行為單位,git 回報變更的方式也是。
詞粒度會保留被改的那一行裡沒動的部分,所以段落中改一個詞不會看起來像整句重寫。文章、commit message 與翻譯適合用這個。
字元粒度再深一層,用來抓看不見的變更:換了引號、改了分隔符,或是一個長得像普通空白的不斷行空格(non-breaking space)。當你知道確切的樣式後,正則表達式測試工具 可以幫你在整份檔案裡找出並取代所有出現的位置。
04忽略空白與忽略大小寫
兩份看起來一模一樣的檔案,還是可能在你沒打算的地方不同。把 JSON 重新縮排、CRLF 換成 LF,或編輯器補上的行尾空白,都會產生蓋掉真正變更的 diff 噪音。
Ignore whitespace 會把連續空白與 tab 收攏,並在比對行時忽略前後空白,所以純粹重新排版的檔案會回報沒有變更——等同 GNU diffutils 的 diff -w 與 diff -b。Ignore case 會把 ALPHA 與 alpha 視為相同(diff -i),比對設定鍵或 SQL 關鍵字時很方便。
05讀懂統一差異檔
以下是統一差異裡的單一 hunk:刪除行以 - 開頭、新增行以 + 開頭,沒改動的上下文行以空格開頭。在 hunk 標頭裡,@@ -12,7 +12,8 @@ 表示這個 hunk 從第 12 行開始,在原始檔涵蓋 7 行,在修改檔涵蓋 8 行。
--- original
+++ modified
@@ -12,7 +12,8 @@ export function useUser(userId) {
const [data, setData] = useState(null);
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
06變更長什麼樣子
被改掉的設定值
輸入
timeout = 30
retries = 3
log_level = "info"
輸出
timeout = 30
- retries = 3
+ retries = 5
- log_level = "info"
+ log_level = "debug"
一次重構,並移除空白噪音
輸入
const total = items.reduce((sum, item) => sum + item.price, 0)
輸出
const total = items
.filter((item) => item.active)
.reduce((sum, item) => sum + item.price, 0)
打開 Ignore whitespace 之後,只會回報新增的 .filter 那一行;拆成多行的 .reduce 不會被當成重寫。
先檢查空白,再懷疑邏輯
如果每一行都被標成變更,兇手通常是縮排或換行符號,而不是程式邏輯。先打開「忽略空白」再看。
07為什麼 diff 出現你沒改的變更
| 你看到的 | 原因 | 修好的設定 |
|---|---|---|
| 重新排版後每一行都變了 | 兩個空白 vs 四個空白,或 tab vs 空白 | Ignore whitespace |
| 沒有可見差異卻每一行都變 | CRLF vs LF 換行 | Ignore whitespace,或先正規化換行 |
| 一模一樣的程式碼被標成不同 | 編輯器補上的行尾空白 | Ignore whitespace |
| 某個常數到處都被改名 | 只差大小寫的變更 | 只想看結構變更時用 Ignore case |
| 一個區塊同時被刪除又新增 | 程式碼被搬移了 | 先看統一檢視再判斷是不是重寫 |
如果兩邊都不在版控裡,瀏覽器比對就是唯一選擇。清理步驟可以看 如何格式化、驗證與壓縮 JSON,它能在你開始比對前先去掉大半噪音。
08資料來源
- GNU Diffutils 手冊 — Unified Format(取用日期:2026-10-10)
- GNU Diffutils 手冊 — Detailed Description of Unified Format(取用日期:2026-10-10)
- GNU Diffutils 手冊 — White Space(取用日期:2026-10-10)
- POSIX diff — Shell and Utilities(取用日期:2026-10-10)
- Myers, An O(ND) Difference Algorithm and Its Variations(1986)(取用日期:2026-10-10)
- git diff — Git 官方文件(取用日期:2026-10-10)
- git apply — Git 官方文件(取用日期:2026-10-10)
- gitattributes — Git 官方文件(取用日期:2026-10-10)
- git-config — diff.algorithm(取用日期:2026-10-10)
並排或統一檢視比對兩段文字,支援行、詞與字元三種粒度。
Diff 比對工具常見問題
Diff 工具和 git diff 一樣嗎?
比對邏輯相同,輸出也符合 [git 的統一差異格式](https://www.gnu.org/software/diffutils/manual/html_node/Unified-Format.html),也就是 [git diff](https://git-scm.com/docs/git-diff) 印出來的格式。差別在於 git diff 只能處理版本庫裡的檔案,這個工具可以比對任意兩段文字,包含不在版控裡的內容。
可以比對兩個 JSON 檔嗎?
可以,但如果兩者只差在排版,請先格式化兩邊或打開忽略空白,否則每一行重新縮排都會被當成變更。
工具會偵測搬移的行嗎?
不會。搬移的區塊會被記成刪除加新增,因為行比對看的是位置。這和 git 的行為一致,也是多數審閱者預期的結果。
可以比對多大的文字?
伺服器端沒有限制,但比對在瀏覽器裡跑。幾 MB 的檔案都很順;更大的日誌建議先依時間範圍過濾。
比對結果可以還原嗎?
Swap Sides 會反轉比對方向,Clear All 會清空兩邊。比對本身不會被儲存。
我的文字會被上傳嗎?
不會,兩邊的內容與比對結果都留在你的瀏覽器裡。
相關文章
- 格式化、驗證與壓縮 JSON
比對前先把 payload 整理乾淨。
- 在不犧牲畫質的前提下壓縮圖片
格式選擇、質素設定與常見錯誤。
相關工具
- Diff 比對工具
並排與統一模式的文字比對。
- JSON 格式化工具
比對前先正規化 JSON。
- 正則表達式測試工具
在文字裡比對與取代樣式。
- Base64 編碼 / 解碼
檢查被編碼過的內容。