【Linux】 diff & patch コマンド ~ パッチ適用 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2015/01/26/000000

で、Antにてpatch を当てることを大昔にやったが
Linuxコマンドでやることになったので、メモっておく

目次

【1】diffコマンド:差分ファイル作成方法
 1)オプション
【2】patchコマンド:パッチ適用
 補足:元に戻すには
【3】サンプル
 お題1:単一ファイル
 お題2:ディレクトリ
【4】トラブル
 1)パッチ適用時にエラー「FAILED at 2 (different line endings)」

【1】diffコマンド:差分ファイル作成方法

# -u: unified形式で出力する
diff -u [元ファイル] [変更後ファイル] > [パッチファイル]

パッチファイルの作成(ディレクトリ)

diff -u -r [変更前のディレクトリ] [変更後のディレクトリ] > [パッチファイル]

1)オプション

# オプション 説明
1 -u unified形式で出力する
2 -c context diff形式で出力する
3 -r サブディレクトリを再帰的に比較する
4 -N 比較するファイルが無い場合、同名の空ファイルがあるのと同じ動作をする

【2】patchコマンド:パッチ適用

patch -u [適用するファイル名] < [パッチファイル名]

ディレクトリ版

 patch [-u(または -c)] -p-d 適用するディレクトリ名 < パッチファイル名

補足:元に戻すには

patch -u -R < [パッチファイル]

ディレクトリ版

patch -R -p-d 適用するディレクトリ名 < パッチファイル名

【3】サンプル

お題1:単一ファイル

* 以下の修正前ファイル「orig.java」と修正後ファイル「after.java」で
 パッチファイルを作成し、適用してみる

orig.java

package com.sample;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World! Mike!!");
    }
}

after.java

package com.sample;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World! Tom!!");
    }
}

Step1: diffコマンド

diff -u orig.java after.java > diff.patch

diff.patch

--- orig.java  2023-10-16 13:56:15.995180400 +0900
+++ after.java  2023-10-16 13:56:39.898804100 +0900
@@ -2,6 +2,6 @@
 
 public class HelloWorld {
     public static void main(String[] args) {
-        System.out.println("Hello World! Mike!!");
+        System.out.println("Hello World! Tom!!");
     }
 }

Step2: patchコマンド

# patch -u [適用するファイル名] < [パッチファイル名]
patch -u orig.java < diff.patch

# 差分がないことを確認
diff orig.java after.java

おまけ:元に戻す

patch -u -R < diff.patch

# 元に戻ったか確認
diff orig.java after.java
5c5
<         System.out.println("Hello World! Mike!!");
---
>         System.out.println("Hello World! Tom!!");

お題2:ディレクト

ディレクトリ構成

+ abc/orig1.java << 中身は上記の「orig.java」と同じ
+ def/orig1.java << 中身は上記の「after.java」と同じ

Step1: diffコマンド

diff -u -r abc def > diff2.patch

Step2: patchコマンド

$ patch -u -p0 -d abc < diff2.patch
can't find file to patch at input line 4
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff -u -r abc/orig1.java def/orig1.java
|--- abc/orig1.java     2023-10-17 00:28:36.986857200 +0900
|+++ def/orig1.java     2023-10-17 00:37:41.920665700 +0900
--------------------------
File to patch: orig1.java
patching file orig1.java

# 確認
diff -r -s abc def
Files abc/orig1.java and def/orig1.java are identical

おまけ:元に戻す

# patch -R -p数 -d 適用するディレクトリ名 < パッチファイル名
patch -R -p0 -d abc < diff2.patch
can't find file to patch at input line 4
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff -u -r abc/orig1.java def/orig1.java
|--- abc/orig1.java     2023-10-17 00:28:36.986857200 +0900
|+++ def/orig1.java     2023-10-17 00:37:41.920665700 +0900
--------------------------
File to patch: orig1.java
patching file orig1.java

# 確認
diff -r -s abc def
diff -r -s abc/orig1.java def/orig1.java
5c5
<         System.out.println("Hello World! Mike!!");
---
>         System.out.println("Hello World! Tom!!");

【4】トラブル

1)パッチ適用時にエラー「FAILED at 2 (different line endings)」

$ patch -u orig.java < diff.patch
patching file orig.java
Hunk #1 FAILED at 2 (different line endings).
1 out of 1 hunk FAILED -- saving rejects to file orig.java.rej

対応策

* orig.java/after.java/diff.patchに対して以下を行う
 + コードをUTF-8に統一
 + 改行コードをLFに統一

参考文献

https://qiita.com/astro_super_nova/items/e30dcaf4d106deebc63c
https://mrgoofy.hatenablog.com/entry/20101019/1287500809

関連記事

Ant で、差分ファイルを適用する ~ Patch ~
https://dk521123.hatenablog.com/entry/2015/01/26/000000