それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

patch / diff コマンドを理解する(diff/patch の使い方)

patch コマンドはDiffコマンドで作った差分ファイルを適用します。

実運用でのDiff

Diffは新規ファイルや削除、再帰的にたどるオプションをつけて実行します。

diff -urN older_dir newer_dir > `date +%Y-%m-%d`.patch

-r 再帰的 -N 新規ファイルを空ファイルと見なす -u ユニファイド形式
パッチを適用するには、ディレクトリに入ってパッチを流し込みます。

cd older_dir
patch -p1  < 2011-02-13.patch

これだけでだとなんかよく分からないので、実際にDiffを取ったりPatchを当てて遊んでみた。

diff を取り消したいとき ` -R ` をつける

diff を revert したいときにはオプションで付けられる。これで元にもどる。

cd older_dir
patch -p1  -R  < 2011-02-13.patch

patchコマンドを使って遊んでみた。

ファイル単位の差分とパッチ

ファイルをつくりりました。

misdo
ツイスト
オールドファッション
ポンデリング

このファイルに一行書き加えて別ファイルを作りました。

misdo.2 (misdo に一行加えたモノ)
ツイスト
フレンチクルーラー
オールドファッション
ポンデリング

二つのファイルでパッチを作って当ててみます。

パッチ作成(差分を作成)
 diff -u misdo misdo.2 > misdo.patch
パッチの適用
 patch misdo < misdo.patch

ファイル"misdo"にパッチをあてて "misdo2"の状態にしました。

適用結果
 diff misdo misdo.2 #二つのファイルは同じです。

ディレクト

ディレクトリ内部の差分を取得します。ディレクトリの違いをパッチにすることができます。

ディレクトリの差分を取る

ディレクトリの差分を取れば、中のファイルの差分が出ててきます。

 diff -u shop1 shop2

差分ファイルは次のようになります。

 diff -u shop1/misdo shop2/misdo
--- shop1/misdo 2011-02-12 23:44:39.975532500 +0900
+++ shop2/misdo 2011-02-12 23:57:23.117019000 +0900
@@ -1,4 +1,5 @@
 ツイスト
+フレンチクルーラー
 オールドファッション
 ポンデリング

ディレクトリの差分を適用

patch -p0 # ディレクトリ名
patch -p0  < shop.patch
結果
$ ls -l
合計 1
-rw-r--r--+ 1 takuya None 249 2月  13 01:18 shop.patch
drwxr-xr-x+ 1 takuya None   0 2月  13 01:19 shop1
drwxr-xr-x+ 1 takuya None   0 2月  12 23:57 shop2

カレントディレクトリにパッチを適応したのです。
さらに一段下にいる場合

patch -p1 # ディレクトリの上位一つを無視

 patch -p1 < ../shop.patch
patching file misdo

takuya@letsnote:~/test/shop1$ ls -l
合計 1
-rw-r--r--+ 1 takuya None 92 2月  13 02:21 misdo

このように、どのディレクトリにパッチを当てるかで -p のオプション値が変わるのです。

カレントディレクトリによって次を使い分ける。

patch -p0 # ディレクトリ名
patch -p1 # ディレクトリの上位一つを無視
patch -p2 # ディレクトリの上位二つを無視

diffについて

patchを試すには、差分がないと何もできません。差分はdiffコマンドで作ります。diffコマンドで差分を作ることができます。diffコマンドはファイル・ディレクトリの中身を一行ずつ調べて違いを表示してくれます。まずは、diffコマンドでファイル差分を取得します。

先ほどと同じmisdoファイルでやってみます。

misdo
ツイスト
オールドファッション
ポンデリング

このファイルに一行書き加えたのがmisdo2

misdo.2
ツイスト
フレンチクルーラー
オールドファッション
ポンデリング
差分を取得します
 diff  misdo misdo.2
1a2
> フレンチクルーラー

これが標準形式のDiffです。ぱっと見た目ではわかりにくいです。

diffの出力形式には複数あります。つまり、差分を表現するフォーマットが複数有り、そのどれかから選んで差分を書き出すことができます。

diffの出力形式にはいろいろある

  • 標準形式 オプション無し
  • コンテキスト(context) 形式 オプション -c
  • ユニファイド形式(unified) オプション -u
  • ed 形式 (ed) オプション -e *1
context 形式の差分を作ってみます。
 diff -c  misdo misdo.2
 *** misdo       2011-02-12 23:08:31.144081900 +0900
 --- misdo.2     2011-02-12 23:09:31.048187100 +0900
 ***************
 *** 1,4 ****
 --- 1,5 ----
   ツイスト
 + フレンチクルーラー
   オールドファッション
   ポンデリング
unified形式を作ってみます。
  diff -c  misdo misdo.2
 *** misdo       2011-02-12 23:08:31.144081900 +0900
 --- misdo.2     2011-02-12 23:09:31.048187100 +0900
 ***************
 *** 1,4 ****
 --- 1,5 ----
   ツイスト
 + フレンチクルーラー
   オールドファッション
   ポンデリング

形式の違いについて。

標準形式とed形式は、ファイルの差分情報だけです。この二つはファイル名情報が欠落しています。よってPatchには使いません。*2
 一方、ユニファイド形式とコンテキスト形式はファイル名とディレクトリ情報が記述されています。差分を適用するとき、ユーザーがファイルを指定する必要がなくなります。

従って、PATCHファイルはコンテキスト形式(またはユニファイド形式)で作るそうです。

git/hg などバージョン管理ファイルのDiffを取っちゃう?

.gitの diff 取ってくれたりするので本当に不要だと思います.

diff --exclude=.git -urN from_dir to_dir > `date +%Y-%m-%d`.patch

のように exclude で除外できます.

*1:Vi/edの知識が必要。ここでは触れないことにします。

*2:Patch二つなうならファイル名を指定しなくちゃ行けないので面倒でした。