如何比較文字檔案:Diff 工具與技巧
比較文字是開發者的日常工作。無論是審查程式碼變更、除錯組態差異,還是合併文件,理解 diff 輸出都是必備技能。本指南涵蓋有效文字比對的演算法、工具與技巧。
理解 Diff 輸出
經典的統一 diff 格式顯示兩個檔案之間的變更:
--- original.txt
+++ modified.txt
@@ -1,5 +1,6 @@
Line 1: unchanged
-Line 2: removed text
+Line 2: modified text
+Line 2.5: added line
Line 3: unchanged
Line 4: unchanged
-Line 5: also removed
- 以
-開頭的行是被移除的(來自原始檔案) - 以
+開頭的行是新增的(在修改版本中) - 以
(空格)開頭的行是未變更的上下文 @@標記顯示受影響的行號
Diff 演算法
Myers 演算法
Git 和大多數 diff 工具使用的預設演算法。它找出最短編輯腳本——將一個檔案轉換為另一個檔案所需的最少插入和刪除次數。對大多數內容都能產生清晰、易讀的 diff。
Patience Diff
更適合結構化文字,如原始碼。它不只是找最短編輯,而是先匹配兩個檔案中都出現的唯一行,再對它們之間的區段進行 diff。這通常能產生與邏輯程式碼區塊更對齊的有意義 diff。
git diff --patience
Histogram Diff
Patience diff 的改良版,自 2.x 版本以來成為 Git 的預設演算法。它能更好地處理重複行,並在檔案有重大結構變更時產生更乾淨的輸出。
線上比較文字
若要不安裝工具就能快速比較,我們的文字 Diff 檢查器直接在瀏覽器中提供並排和內嵌 diff 檢視。貼上兩段文字,即可看到即時標示的差異——所有處理都在本機完成。
命令列 Diff 工具
diff (POSIX)
經典的 Unix 工具:
# Unified format (most readable)
diff -u file1.txt file2.txt
# Side-by-side
diff -y file1.txt file2.txt
# Ignore whitespace
diff -w file1.txt file2.txt
# Recursive directory comparison
diff -r dir1/ dir2/
git diff
即使不在 Git 儲存庫中,git diff 也能提供更優質的輸出:
# Compare two files
git diff --no-index file1.txt file2.txt
# Word-level diff (highlights changed words, not whole lines)
git diff --word-diff
# Stat summary (files changed, insertions, deletions)
git diff --stat
colordiff / delta
用於彩色終端輸出:
# colordiff: drop-in replacement for diff
colordiff file1.txt file2.txt
# delta: modern diff viewer for Git
git diff | delta
程式碼審查中的 Diff
有效的程式碼審查取決於可讀的 diff。以下是提升 diff 品質的技巧:
1. 保持提交聚焦
跨越數百行的大型 diff 很難審查。每次提交應只處理一個關注點:
- 將格式化變更與邏輯變更分開
- 將大型重構拆分為漸進式步驟
- 在一次提交中移動檔案,在另一次提交中修改它們
2. 使用單字層級 Diff
當一行中有一個小修改埋在很長的字串裡時,行層級 diff 會隱藏實際的變更:
# Shows only the changed words, not entire lines
git diff --word-diff
3. 在審查中忽略空白
格式化變更會在有意義的 diff 中增加雜訊:
git diff -w # Ignore all whitespace changes
git diff -b # Ignore whitespace amount changes
4. 帶上下文審查
更多上下文行有助於理解周圍的程式碼:
git diff -U10 # Show 10 lines of context (default is 3)
處理合併衝突
當 Git 遇到衝突的變更時,會在檔案中標記衝突:
<<<<<<< HEAD
const timeout = 5000;
=======
const timeout = 10000;
>>>>>>> feature-branch
解決步驟:
- 理解兩邊的變更——各自為何而改?
- 決定保留哪個版本,或將它們合併
- 移除衝突標記
- 測試結果
對於複雜的合併,使用三方合併工具,它會在兩個版本旁邊同時顯示共同祖先。
比較非文字內容
JSON Diff
標準文字 diff 處理 JSON 時有困難,因為鍵順序和格式化的變更會產生雜訊。語義化 JSON diff 比較的是實際的資料結構。查看我們的 JSON Diff 工具進行結構化比較。
CSV Diff
表格資料需要欄位感知的比較。標準 diff 將每一行視為字串,會遺漏儲存格層級的變更。
二進位檔案
Diff 無法有意義地比較二進位檔案。對於圖片,使用視覺 diff 工具。對於文件,先轉換為文字,或使用格式專屬的比較工具。
自動化中的 Diff
CI/CD 管線
使用 diff 在測試中驗證預期輸出:
command_under_test > actual_output.txt
diff expected_output.txt actual_output.txt
# Exit code 0 = identical, 1 = different
組態漂移偵測
將正式環境組態與預期狀態進行比較:
diff deployed_config.yaml expected_config.yaml
文件變更追蹤
追蹤文件變更以供審查:
git diff --stat HEAD~5..HEAD -- docs/
常見問題
Diff 輸出中的「hunk」是什麼意思?
Hunk 是 diff 中一個連續的變更區塊。每個 @@ 行開始一個新的 hunk。Git 會將鄰近的變更合併到同一個 hunk 中——如果兩個變更在 3 行以內(預設上下文),它們會出現在同一個 hunk 中。可以使用 git add -p 獨立暫存各個 hunk。
如何在 Git 中比較兩個分支?
使用 git diff branch1..branch2 查看兩個分支之間的所有差異。加上 --stat 可以看到摘要,或 -- path/to/file 比較特定檔案。若要比較分支自分岔以來新增的內容,使用三個點:git diff branch1...branch2。
相關資源
- 文字 Diff 檢查器 — 在瀏覽器中並排比較文字
- JSON Diff 除錯指南 — JSON 資料的結構化比較
- Regex 速查表 — 用模式比對找出特定變更