你手上有同一份東西的兩個版本——改前改後的文件、兩份設定檔、同事重寫過的段落——需要知道「到底改了哪裡」。兩邊並排慢慢讀又慢又容易漏。**diff(差異比對)**一秒就搞定。
改一個字實際上長什麼樣。 我們給文字比對工具同樣兩行的兩個版本,只有最後一個字不同 ——
dog對cat。輸出把the quick brown fox當成沒有標記的共同行,然後把有變動的那一行顯示兩次:一次標−(刪除)、一次標+(新增)。這是關於 diff 最該懂的一件事:它不會告訴你「有一個字改了」。行才是單位,所以改一個字元,仍然會顯示成整行刪除加整行新增。這也是為什麼把檔案重新排版會讓 diff 變得毫無用處 —— 即使實質內容一個字都沒變。
這是真正的輸出,不是對輸出的描述。 同樣兩行的兩個版本,只差最後一個字,丟進我們的文字比對工具:
the quick brown fox − jumps over the lazy dog + jumps over the lazy cat共同的那一行沒有標記;有變動的那一行出現兩次,一次
−一次+。這是關於 diff 最該記住的事:單位是行,所以改一個字元仍然是整行刪掉、整行插入。這也是為什麼重新排版一個檔案會毀掉 diff —— 即使實質內容一個字都沒變。
diff 到底做什麼
diff 演算法會找出「把一段文字變成另一段」所需的最少新增與刪除,再用顏色標出來:綠色是新增、紅色是刪除、無色是沒變。這就是「追蹤修訂」和所有 code review 背後的同一套技術。
行比對 vs 字比對
有兩種好用的粒度:
- 行比對以整行為單位。最適合程式碼、設定檔、CSV 與清單——這些的「改動」通常是整行被新增、刪除或替換。
- 字比對逐字比。最適合文章散文——你會想看到一句話裡只有「某一個字」變了,而不是整行紅綠一片。
先用行比對;當某行顯示有變、你卻看不出差在哪,再切到字比對。
「以什麼為單位」這個問題,在我們自己的輸出上有可量的答案。兩個只差一個字的版本產生了三行、不是一行:共同的那行沒有標記,然後有變動的那行出現兩次 —— 一次 −、一次 +。行 diff 沒辦法說「有一個字改了」,因為行才是它的單位。這也是為什麼重新排版一個檔案(重新折行、重新縮排)會毀掉 diff,即使語意完全相同。
怎麼讀結果
- 一紅一綠相鄰 = 那行被編輯了(先刪掉、再以新樣子加回)。
- 單獨一綠 = 新增。
- 單獨一紅 = 刪除。
- 下方摘要(例如
+3 −1)讓你一眼看出改動規模。
讀它就變得很機械:沒標記的活下來、− 是離開的、+ 是新來的。我們那次執行的結果正好是 the quick brown fox / − / jumps over the lazy dog / + / jumps over the lazy cat —— 注意「移除」與「新增」那兩行是相鄰的,那就是「這一行被改了」而不是「真的被刪掉或插入」的視覺線索。
下面是我們自己的文字比對工具對「改一個字」實際回傳的結果 —— 同樣的兩行文字,只有最後一個字不同:
the quick brown fox
−
jumps over the lazy dog
+
jumps over the lazy cat
回來的是三行,不是一行。共同的那行沒有標記,然後有變動的那行出現兩次:一次在 −、一次在 +。行 diff 沒辦法回報「有一個字改了」,因為行才是它比較的單位。
為什麼在瀏覽器本機比
diff 常牽涉敏感內容——合約、設定檔裡的密鑰、還沒發布的文案。用會上傳的線上工具是多餘的風險。文字比對工具全程在你的瀏覽器本機比對:兩個版本都不離開你的裝置。
第三種粒度:字元比對
遇到很短又密集的字串,連字比對都嫌粗。字元比對逐字元比,適合「差在一個字元就是全部關鍵」的場合——訂單編號裡對調的數字、雜湊值或 API 金鑰裡一個錯字元、藏在長 token 裡的一個手誤。字比對會把整個 token 標成有變,字元比對則直接指到差的那個字元。
口訣:檔案與清單用行比對,文章散文用字比對,代碼與識別碼用字元比對。
這個單位也解釋了為什麼重新排版會毀掉 diff。我們把同樣三個詞餵了兩次,一次寫成一行、一次寫成三行,內容完全沒動:
−
one two three
+
one
+
two
+
three
每一行都被標記了。什麼都沒改,只是重新折行。詞層或字元層的 diff 在這裡會回報「沒有變動」—— 「以什麼為單位」這個爭論,用一次量測就結束了,不需要辯論。
什麼時候會用到 diff
- 審閱修改——看清同事、編輯,或 AI 改寫到底動了你草稿的哪裡。
- 比對版本——合約、條款、設定檔改動前後的差別。
- 驗證複本——確認兩份匯出、兩份翻譯、兩份清單是不是逐字元一致。
- 追近似重複——兩段看起來一樣、結果卻不同的文字。
常見誤解
- diff 不會辨識「搬移」——把一段剪下貼到下面,多數工具會顯示成「一刪一增」,而不是「移動」。
- 整行被標色不代表整行都改了——行比對模式下,只改一個字也會把整行標起來,切到字比對或字元比對才看得到真正的改動。
- 看不見的字元也算數——兩行看起來一樣,可能只差一個行尾空白、一個 Tab 或一種換行符;那是真的差異,不是工具出錯,也正是移除換行與重複行指南裡整理步驟要預防的。
標記還讓另一個區別看得見。插入回傳的是
alpha
+
beta
gamma
刪除回傳的是
alpha
−
beta
gamma
真正的插入或刪除,只有一行被標記;而修改會產生相鄰的一組 −/+。那個「相鄰」是大家最先學會讀的線索,也解釋了為什麼「搬動過的程式碼」在審查時看起來雜訊那麼大 —— 搬動是一個刪除加一個插入,離得很遠,沒有東西把它們配成一對。
小技巧:先整理格式,diff 更乾淨
如果兩份檔案只差在行尾空白、Tab 或換行符,diff 會很雜。先把兩份都用文字清理器跑一遍——去頭尾空白、統一空白——真正的差異就會突顯出來。