PATCH(1) | General Commands Manual | PATCH(1) |
patch - オリジナルファイルに差分ファイルを適用する
patch [options] [originalfile [patchfile]]
通常はもっと簡単に
patch -pnum <patchfile
patch は、プログラム diff で生成された差分リストを含むパッチファイル patchfile を引数に取り、 1 個または複数のオリジナルファイルにこれらの差分を適用し、 パッチの当たったバージョンを生成する。 通常、オリジナルファイルは パッチの当たったバージョンと置き換わる。 バックアップを作成することもできる ( -b または --backup オプションを参照 ) 。 通常、パッチを当てるファイルの名前はパッチファイルから得られる。 ただし、パッチの当たるファイルが 1 個だけの場合、 orginalfile としてコマンドラインで指定することができる。
実行すると、 patch は差分 (diff) リストの形式を判別する。 ただし、 -c (--context), -e (--ed), -n (--normal), -u (--unified) オプションのどれかが指定された場合、自動判別は行なわれない。 コンテキスト diff (old-style, new-style, unified) および ノーマル diff は patch プログラム自身がパッチを適用する。 いっぽう、 ed diff はパイプを通じて ed(1) エディタに流し込まれるだけである。
patch は差分の前にあるゴミを読み飛ばし、差分を適用し、 そして後ろにあるゴミを読み飛ばそうとする。 そのため、差分リストを含む記事やメッセージを patch に流し込むことができ、それで動作するはずである。 diff 全体が一定量インデントされている場合や、 コンテキスト diff が CRLF で終わる行を含んでいる場合、 インターネット RFC 934 で規定されるように "-" で始まる行の先頭に 1個または複数個の "- " が付いている場合には、 これらは考慮される。
コンテキスト diff や ノーマル diff ( ノーマル diff の場合の適用範囲はやや狭い ) の場合、 patch はパッチ中の行番号の誤りを検出することができ、 パッチのそれぞれの塊 (hunk) について、正しい位置を見つけようとする。 最初は、hunk に書かれた行番号に 直前の hunk を適用した際のオフセットを加減した位置ではないかと推測する。 もしそれが正しい位置ではない場合、 patch は hunk 中のコンテキストに一致する行が前後にないかを探す。 まず、 patch はコンテキストのすべての行が一致する位置を探す。 そのような位置が見つからない場合で、かつコンテキスト diff であり、 かつ fuzz factor (曖昧度合い) の最大値が 1 以上の場合、 コンテキストの最初と最後の行を無視してもう一度探す。 それも失敗し、 fuzz factor の最大値が 2 以上の場合、 コンテキストの最初と最後の 2 行ずつを無視してもう一度探す。 ( デフォルトの fuzz factor の最大値は 2 である。 ) patch は、パッチのその hunk を適用する位置を見つけられない場合、 その hunk を reject (却下) ファイルに書き出す。 通常、 reject ファイルの名前は出力ファイルの後ろに .rej を付けたものか、 .rej を付けるとファイル名が長くなりすぎる場合には # を付けたものとなる ( もし # 1 文字を付けても長くなりすぎる場合には、 ファイル名の最後の文字を # に置き換える ) 。 ( reject (却下) された hunk は入力されたパッチの形式にかかわらず、 通常のコンテキスト diff の形式で出力される。 入力がノーマル diff の場合、コンテキストの多くは単純に空になる。 ) reject ファイル中の hunk に付けられた行番号はパッチファイルのものとは 異なるかもしれない。 reject ファイル中の行番号は、古いファイルにおける位置ではなく、 patch が新しいファイルの中で hunk が当たると思うおおよその位置になっている。
それぞれの hunk の処理が終わると、 hunk が失敗したかどうかや、 もし失敗した場合、 patch が ( 新しいファイルの ) どの行に その hunk が当たると思ったかが通知される。 hunk が diff に示された行番号と異なる位置に適用された場合は、 そのオフセットが通知される。 大きなオフセットが 1 個だけ通知された場合、 ある hunk が間違った位置に適用された かもしれない。 一致する位置を探すために fuzz factor が使われたかどうかも通知されるが、 その場合には少々不審に思ったほうがよい。 --verbose オプションを指定すると、 hunk がぴったり一致した場合にも通知される。
コマンドラインでオリジナルファイル origfile が指定されなかった場合、 patch は diff の前にあるゴミから次のような規則を使って 編集すべきファイルを判別しようとする。
まず、 patch は候補となるファイル名の順序付きリストを次のようにして作る:
そして patch は候補リストから次のようにファイル名を選択する:
空でないファイル名のリストから 最適な (best) ものを選ぶために、 patch はまずパス名の要素が最も少ないものを選び、 その中からベースネームの最も短いものを選び、 さらにその中から最も短いものを選び、 最後に、残った中で最初の名前を選ぶ。
さらに、前のゴミに Prereq: という行が含まれる場合、 patch はその必要条件の行から最初の単語 ( 通常はバージョン番号 ) を取り、 オリジナルファイルにその単語があるかどうかをチェックする。 もしない場合、 patch は処理する前に確認を求める。
すべての結論は、 ニュースリーダを使っているときには、 次のような感じにすればよいということである:
| patch -d /usr/src/local/blurfl
こうすれば、ディレクトリ blurfl にあるファイルに、パッチを含む記事から直接パッチを当てることができる。
パッチファイルに複数のパッチが含まれている場合、 patch は、それぞれが別々のパッチファイルから入力されたかのように当てようとする。 このときは、とりわけ、 パッチを当てるファイルの名前はそれぞれの差分リストから決まらなければならず、 それぞれの差分リストの前のゴミにはファイル名やリビジョン番号といった 必要なことがらが含まれていることが求められる。
/u/howard/src/blurfl/blurfl.c
であったとすると、 -p0 とするとファイル名全体が変更されずに用いられ、 -p1 とすると
u/howard/src/blurfl/blurfl.c
のように先頭のスラッシュが取り除かれ、 -p4 とすると
blurfl/blurfl.c
のようになり、 -p を指定しなければ blurfl.c となる。 最終的に参照されるディレクトリは カレントディレクトリ、または -d オプションで指定されたディレクトリである。
--quoting-style オプションのデフォルト値は環境変数 QUOTING_STYLE で指定することができる。 環境変数が設定されていない場合、デフォルト値は shell である。
パッチの最初の hunk が失敗すると、 patch は hunk を反転させて当たるかどうかをみる。 もし当たる場合、 -R オプションをセットするかどうかを尋ねる。 もし当たらない場合、通常の方法を継続する。 ( 注意: この方法では、 ノーマル diff で最初のコマンドが追加の ( つまり、本来は削除であった ) 場合に 反転されたパッチを検出することができない。 それは、空のコンテキストはどこにでもマッチするために、 追加は常に成功するからである。 幸い、ほとんどのパッチは行を追加するか、変更するものであって、 削除するものは少ないため、 経験的にいって、反転したノーマル diff のほとんどは削除から始まっていて、 失敗してくれる。 )
method の値は GNU Emacs の `version-control' 変数と同様である。 patch はもっと分かりやすい同義語も理解する。 method の有効な値は次のとおりである ( 区別が付けば短縮形を用いてもよい ):
番号付きまたは簡易バックアップの場合、 バックアップファイルの名前が長すぎると、 代わりにバックアップサフィクス ~ が使われる。 ~ を付加しても長すぎる場合、 ファイル名の最後の文字が ~ に置き換えられる。
-Z または --set-utc および -T または --set-time オプションは、通常はファイルのオリジナルの時刻が パッチヘッダ中の時刻と一致しない場合や 内容がパッチとぴったり一致しない場合には、ファイルの時刻を設定しない。 しかし、 -f または --force オプションが指定された場合、ファイルの時刻は強制的に設定される。
diff の出力形式の制限のため、 これらのオプションでは 内容の変化しないファイルの時刻は更新されない。 また、これらのオプションを使った場合には、 パッチの当たったファイルに依存するファイルを削除して ( 例えば make clean で ) 、 あとで make を実行したときにパッチの当たったファイルの時刻で 混乱しないようにしなければならない。
Marshall T. Rose and Einar A. Stefferud, Proposed Standard for Message Encapsulation, Internet RFC 934 <URL:ftp://ftp.isi.edu/in-notes/rfc934.txt> (1985-01).
パッチを送ろうとする場合に心に留めておかなければならない点がいくつかある。
パッチを機械的に作ること。 よい方法は diff -Naur old new のようなコマンドを使うことである。 new と old はそれぞれ新旧のディレクトリである。 old と new には 1 個もスラッシュがあってはいけない。 diff コマンドのヘッダに含まれる日時は伝統的な Unix 形式を使って 協定世界時で書かれていなければならない。 そうすれば パッチを受け取った人が -Z または --set-utc オプションを使うことができる。 次のものは Bourne シェル形式を使ったコマンド例である:
LC_ALL=C TZ=UTC0 diff -Naur gcc-2.7 gcc-2.8
受け取る人にはパッチの当て方を伝える。 つまり、どのディレクトリに cd すればよいかとどの patch オプションを使えばよいかを伝える。 オプション文字列は -Np1 が推奨される。 受け取った人になったつもりで手順を試し、 オリジナルファイルのコピーを取って、作ったパッチを当ててみる。
送り出すパッチファイルの最初の diff として、 パッチレベルをインクリメントしていく patchlevel.h ファイルを入れておくと、 多くの人の面倒を軽減できる。 パッチに Prereq: 行を加えておけば、 順番を間違えて警告を食らうのを防ぐことができる。
/dev/null や 日時が Epoch (1970-01-01 00:00:00 UTC) の空のファイルと 作成したいファイルを比較した diff を送ることで、 ファイルを作成することができる。 この方法はターゲットのディレクトリに作成したいファイルが まだ存在しない場合に限って動作する。 反対に、削除したいファイルと日時が Epoch の空のファイルを比較した コンテキスト diff を送ることで、ファイルを削除することができる。 ファイルは patch が POSIX 準拠でなく、 -E または --remove-empty-files オプションが指定されない場合に削除される。 ファイルを作成したり削除したりするパッチを生成する簡単な方法は、 GNU diff の -N または --new-file オプションを使うことである。
受け取った人が -pN オプションを使うことが想定される場合、 次のようなパッチを送らないこと:
diff -Naur v2.0.29/prog/README prog/README
--- v2.0.29/prog/README Mon Mar 10 15:13:12 1997
+++ prog/README Mon Mar 17 14:58:22 1997
なぜなら二つのファイル名は異なる数のスラッシュを含んでおり、 patch のバージョンによって ファイル名を異なるように解釈するからである。 混乱を避けるために、代わりに次のようなパッチを送ること:
diff -Naur v2.0.29/prog/README v2.0.30/prog/README
--- v2.0.29/prog/README Mon Mar 10 15:13:12 1997
+++ v2.0.30/prog/README Mon Mar 17 14:58:22 1997
バックアップファイルと名前が同じファイル、例えば README.orig と比較したパッチを送らないこと。 この方法では patch が混乱して、 正しいファイルではなく バックアップファイルにパッチを当ててしまうかもしれないからである。 そうではなく、 ファイル名が同じで別のディレクトリにあるファイルどうし、例えば old/README と new/README を比較したパッチを送ること。
反転したパッチを送らないように注意すること。 もうパッチを当てたのかと思ってしまうからである。
自動生成されるファイル ( 例えば、 makefile に configure: configure.in という行がある場合の configure というファイル ) を変更するパッチを作らないようにすること。 受け取った人は自動生成されるファイルを再生成することができるからである。 自動生成されるファイルの diff を送らなければならない場合、 UTC を用いて diff を作り、 受け取った人に -Z または --set-utc オプションを使ってパッチを当ててもらい、 パッチの当たったファイルに依存する、 パッチの当たっていないファイルを削除してもらう ( 例えば make clean で ) 。
582 もの差分リストを 1 個のファイルに入れなくても済むのであれば、 ぐちゃぐちゃになってしまった場合に備えて 関連するパッチを別々のファイルにまとめておくのが賢明である。
エラーは一般に、 patch がパッチファイルを解析できなかったことを示している。
--verbose オプションを指定した場合、 Hmm... はパッチファイルの中に処理されなかったテキストがあり、 patch がテキストの中にパッチがあるかどうかを 必死に探そうとしていることを表している。 パッチが見つかると、そのパッチがどんな種類のものかを示す。
patch の終了ステータスは、 すべての hunk の適用に成功した場合に 0 、 一部の hunk が適用できなかった場合に 1 、 もっと深刻な問題に見舞われた場合に 2 となる。 バッチ処理で複数のパッチを適用する場合、 終了ステータスをチェックして、 部分的にしかパッチの当たっていないファイルに 以降のパッチを当てないようにすることが必要である。
コンテキスト diff は空のファイルや空のディレクトリ、 シンボリックリンクなどのスペシャルファイルの作成や削除を 確実に表すことはできない。 所有者やアクセス権限、あるファイルが 別のファイルのハードリンクであることといった ファイルメタデータの変更を表すこともできない。 もしそのような変更も必要であれば、 別に手順書 ( 例えば、シェルスクリプト ) を用意して、 パッチに添付しなければならない。
patch は、 ed スクリプト中の行番号がはみ出しているかどうかは分からないし、 ノーマル diff の行番号の間違いは 変更や削除を見つけた場合に限って検出できる。 fuzz factor が 3 のコンテキスト diff も同じ問題に遭遇するかもしれない。 適当な対話式のインタフェースが導入されるまでは、 このような場合はコンテキスト diff を作って 変更が妥当かどうかを確認しなければならない。 もちろん、エラーなくコンパイルできたことは パッチがうまく当たったよい証拠になるが、必ずしもそうとはいえない。
patch は多数の推測が必要な場合であっても、通常は正しい結果を出す。 しかし、結果が正しいことが保証されるのは、 そのパッチが生成されたファイルと全く同一のバージョンの ファイルに適用された場合だけである。
POSIX 標準は patch の古典的な振る舞いと異なる振る舞いを規定している。 patch のバージョン 2.1 およびそれ以前 ( これらは POSIX に 準拠していない ) と 相互に運用しなければならない場合、これらの違いを知っておく必要がある。
また、古典的な patch はパスプレフィクスを取り除く際、スラッシュの数を単純に数えていた。 今日の patch はパス名の要素を数える。 つまり、 1 個または複数の隣接するスラッシュの列は 1 個のスラッシュとして数えられる。 互換性を最大限に保つために、 ファイル名に // を含むパッチは送らないようにすること。
反対に、 POSIX patch では、不整合があってもバックアップは一切作られない。 GNU patch では、この振る舞いは --no-backup-if-mismatch オプションか、 --posix オプションまたは POSIXLY_CORRECT 環境変数で POSIX 準拠にするかで有効になる。
古典的な patch の -b suffix オプションは GNU patch の -b -z suffix オプションと同等である。
-c -d dir -D define -e -l -n -N -o outfile -pnum -R -r rejectfile
バグは電子メールで <bug-gnu-utils@gnu.org> へ報告してください。
patch は部分一致や大きく逸脱したオフセットやひっくり返ったコードに対して もっと賢くすることもできるだろうが、その道は長いだろう。
コードが重複している場合 ( 例えば #ifdef OLDCODE ... #else ... #endif のように区切られている場合 ) 、 patch は両方のバージョンにパッチを当てることはできない。 もしパッチが当たったとしたら、 間違ったほうにパッチが当たってしまっていることもよくあり、 それでも成功したから続きをやれというだろう。
すでに当たっているパッチを当てようとすると、 patch はパッチが反転していると思い、パッチを戻すかを尋ねる。 これは機能のひとつとみなすことができよう。
Copyright 1984, 1985, 1986, 1988 Larry Wall.
Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 Free
Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.
Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be included in translations approved by the copyright holders instead of in the original English.
オリジナルの patch は Larry Wall が書いた。 Paul Eggert は恣意的な制限を取り除き、 バイナリファイルへの対応や、ファイルの時刻設定、ファイルの削除を追加した。 また、より POSIX に準拠するようにした。 ほかには Wayne Davison が unidiff への対応を追加し、 David MacKenzie がコンフィグレーションとバックアップへの対応を追加した。
2005/08/08 | GNU |