diff 與 patch:檔案差異比較與套用 文章首圖

diff 與 patch:檔案差異比較與套用

前言

在 Linux 系統管理與程式開發的世界裡,檔案版本的追蹤與差異比對是日常不可或缺的工作。當你需要知道兩個檔案哪裡不同,或者想將一組修改應用到另一個檔案時,diffpatch 這對黃金組合便顯得分外重要。雖然現代開發者常使用 Git 等版本控制系統,但理解底層的 diff 機制對於除錯、自動化腳本撰寫以及伺服器間的配置同步仍有極高的實用價值。今天,我們將深入探討這兩個指令的用法,並透過實際範例展示如何高效地管理檔案差異。

diff:檢視檔案差異的利器

diff 指令的核心功能是比較兩個檔案或目錄的內容,並輸出它們之間的差異。在 Ubuntu 22.04 或 Debian 12 上,你無需安裝額外套件即可直接使用它。

基本用法與輸出解讀

假設我們建立兩個檔案 file_a.txtfile_b.txt,內容如下:

$ echo "Hello World" > file_a.txt
$ echo "Hello Linux" > file_b.txt

執行 diff file_a.txt file_b.txt 後,你會看到類似以下的輸出:

1c1
< Hello World
---
> Hello Linux

這串輸出包含三個部分:

  1. 位置資訊1c1 表示第一個檔案的第 1 行被「更改」(change)為第二個檔案的第 1 行。
  2. 原始內容:以 < 開頭的是 file_a.txt 的內容。
  3. 新內容:以 > 開頭的是 file_b.txt 的內容。
  4. 分隔線--- 用來區隔兩邊的內容。

常用選項解析

在日常使用中,預設的輸出格式對於人類閱讀尚可,但對於機器處理或大型檔案則不夠直觀。以下是幾個實用的選項:

  • -u (unified format):這是生成 patch 檔最常用的格式,它會顯示上下文行,讓讀者更容易理解修改發生在哪裡。
  • -r (recursive):當比較目錄時,此選項會遞迴比較子目錄中的所有檔案。
  • -q (brief):僅顯示哪些檔案不同,不顯示具體差異內容,適合快速檢查。

讓我們來看看使用 -u 選項的效果:

$ diff -u file_a.txt file_b.txt
--- file_a.txt  2023-10-27 10:00:00.000000000 +0800
+++ file_b.txt  2023-10-27 10:05:00.000000000 +0800
@@ -1 +1 @@
-Hello World
+Hello Linux

這裡的 @@ -1 +1 @@ 表示在兩個檔案中,差異都位於第 1 行。- 代表刪除,+ 代表新增。

patch:將差異應用於檔案

如果 diff 負責「發現」差異,那麼 patch 就是負責「應用」這些差異的執行者。它可以將 diff 產生的差異檔套用回原始檔案,使其與目標檔案一致。

生成與套用 Patch 檔

首先,我們生成一個差異檔 changes.patch

$ diff -u file_a.txt file_b.txt > changes.patch

現在,我們想將 changes.patch 套用回 file_a.txt,使其變成 file_b.txt 的內容。請注意,patch 指令會修改原始檔案,建議先備份:

$ cp file_a.txt file_a_backup.txt
$ patch file_a.txt changes.patch
patching file file_a.txt

執行後,檢查 file_a.txt 的內容:

$ cat file_a.txt
Hello Linux

可以看到,file_a.txt 已經成功被修改。

處理目錄與遞迴套用

當你需要更新整個專案目錄時,可以使用 -R 選項來反轉 patch(即從目標還原回原始),或使用 -p0-p1 來處理路徑層級。例如,在比較兩個專案目錄時:

$ diff -ruN old_project/ new_project/ > project_diff.patch

這裡的 -N (new-file) 選項非常重要,它確保了如果新目錄中有舊目錄沒有的檔案,這些新增的檔案也會被包含在差異中。

常見問題

1. 套用 patch 時出現 "Hunk #1 FAILED" 錯誤

這是新手最常遇到的問題。原因通常是原始檔案與生成 patch 時的檔案內容不一致(例如中間被手動修改過,或換行符號 CRLF vs LF 不同)。

解決方案: 使用 --dry-run 參數先預覽套用結果,確認是否有衝突:

$ patch --dry-run file_a.txt changes.patch

如果確認是換行符號問題,可以使用 dos2unix 工具統一格式,或手動檢查檔案內容是否與預期一致。若檔案差異過大,可能需要重新生成 patch 檔。

2. 如何比較兩個目錄並只列出新增或刪除的檔案?

除了檢視內容差異,有時我們只關心檔案清單的變化。

解決方案: 使用 diff -rq 可以簡潔地列出哪些檔案不同。若想知道具體是新增還是刪除,可以結合 comm 指令,但對於目錄結構比較,diff -rq 已足夠快速。若需更詳細的統計資訊,可加上 --brief

小結

diffpatch 是 Linux 世界中輕量卻強大的工具。它們不僅適用於程式碼比對,更廣泛應用於系統配置文件的管理與同步。透過熟練掌握 -u-r-N 等選項,以及理解 patch 套用的機制,你可以更高效地處理版本控制以外的檔案同步需求。雖然 Git 等現代工具提供了更完善的歷史追蹤功能,但理解底層的 diff 邏輯,能讓你在面對伺服器除錯或自動化腳本開發時,擁有更深的掌控力與靈活性。