patch - diff ファイルをオリジナルのファイルに適用する |
patch [options] [origfile [patchfile]] [+ [options] [origfile]]... ですが、たいていは以下のようにします。 patch <patchfile |
patch は、 diff プログラムによって生成された 4 つの形式の差分情報を含む パッチファイルを受け付け、オリジナルファイルにその差分を当てて、パッ チ 済みのバージョンを生成します。 デフォルト動作では、オリジナルは ".orig" の拡張子 (長いファイル名を扱え ないシステムでは "~") を付けてバックアップとして残した上で、オリジナ ル ファ イルはパッチ済みのバージョンに置き換えられます。オリジナルをバック アップする拡張子はオプション −b (−−suffix), −B (−−prefix) あるい は −V (−−version−control) によって、あるいは環境変数 SIMPLE_BACKUP_SUFFIX に よっても変更できます。環境変数による指定はオプション指定によって上書 き されます。 バックアップファイルが既に存在していた場合、 patch は新しいバックアップ ファイル名として、ファイル名本体の中で最初に出てくる英小文字の部分を 大 文 字に替えたものを使います。英小文字の部分がなかった場合は、ファイル名 の最初の 1 文字削除したものとし、既存のバックアップファイル名と合致しな くなるまでこれを繰り返します。 ファイルの出力先は −o (−−output) で指定することができますが、もしそこに 既に同じファイル名のファイルが存在していたら、まずバックアップが作ら れ ます。 patchfile が指定されない場合やハイフンである場合、パッチは標準入力から 読み込まれます。 −i 引数が指定された場合、標準入力の代りに、これに続 く ファイル名が使用されます。 −i ディレクティブは 1 度のみ使用可能です。 patch が最初に行う作業は、差分情報がどんな形式か判別することです。これ は、オプション −c (−−context), −e (−−ed), −n (−−normal), −u (−−unified) に よっ て 形 式 を 指 定 することもできます。 context diff (old-style, new-style, unified) および normal diff は patch 自身によりパッチが当 て ら れ ます。 ed diff だった場合は、パイプを通して単にパッチファイルをエ ディタ ed に入力するだけです。 patch は、差分情報の前に含まれるゴミをスキップし、差分を適用し、そし て 後 に含まれるゴミをスキップしようとします。ですから差分情報が入った記事 やメッセージなどをそのまま patch に与えても、うまく動作するはずです。差 分 全体が一定量だけインデントされていても、そのことを考慮のうえ処理され ます。 context diff の場合、そして normal diff の場合もいくらかあてはまりま す が、 patch はパッチに書かれた行番号が正しくない場合にそれを検知し、各 hunk (パッチの各々の単位)を適用する正しい場所を見つけようと試みます。ま ず hunk に書かれた行番号に対し、前回 hunk を適用した際に用いたオフセッ トを加算あるいは減算します。それが正しい場所でなければ、 patch は一定の 行 数だけその前後を走査し、hunk のコンテキスト(context)にマッチする行を 探します。一番最初は、 patch はコンテキスト中の全ての行が一致する場所を 探 します。一致する場所が見つからない場合、パッチが context diff 形式で あり、しかも最大曖昧度(maximum fuzz factor)が 1 以上に設定され て い れ ば、 コンテキストの最初と最後の行を無視して再度走査を行います。それでも 見つからない場合、最大曖昧度が 2 以上なら、コンテキストの最初と最後の 2 行 を 無 視 して再度走査します。 (デフォルトの最大曖昧度は 2 です) もし patch がパッチを当てる場所を見つけられなかった場合、その部分の差分情 報 を リジェクトファイルに出力します。リジェクトファイルは、通常、出力ファ イルに ".rej" の拡張子 (長いファイル名を扱えないシステムでは "#") を 付 けたものになります。 (注意: 入力パッチが context diff であっても normal diff であっても、リジェクト部分は context diff 形式で出力されます。入力 が normal diff の場合、コンテキストの多くは単なる null になります。) こ のリジェクトファイルに出力される時の差分情報に付けられている行番号 は、 元 の パッ チファイルにあるものと違ったものになっている可能性もあります が、元のものよりは場所的により近い位置になっていると思われる行番号に な ります。 パッチの各 hunk が処理される毎に、そのパッチ処理が成功した(succeeded)の か失敗した(failed)のかの別と、 patch が推定したパッチ適用行位置(新し い ファ イルにおける行番号) が報告されます。この位置が差分中に示された行番 号と異なる場合、そのズレ(オフセット)も報告されます。 hunk のひとつだ け が 大きなオフセットで適用された場合、それは誤った位置に適用されたことを 意味する「かも」しれません。またパッチ適用に際して曖昧度(fuzz factor)が 用 いられた場合もその旨報告されます。この場合は少し疑ってみるべきでしょ う。 もし、オリジナルファイルがコマンドラインで指定されなかった場合、 patch は、 エディットすべきファイル名を、差分情報の前に付加されているゴミの中 から見つけようとします。 context diff のヘッダの場合、 ファ イ ル 名 は "***" もしくは "---" で始まる行から探し、既存ファイルに一致する最も短い 名前が用いられます。 context diffには上のような行が含まれますが、 も し ヘッダに "Index:" という行があったら patch はここから得たファイル名を使 うことを試みます。 context diff ヘッダは Index 行に優先して用いら れ ま す。 もしファイル名を見つけることができなかった場合、パッチすべきファイ ル名を入力するよう求めます。 もしオリジナルファイルが見つからないかリードオンリーであるけ れ ど も、 SCCS か RCS ファイルが存在する場合、 patch はそのファイルのゲットもしく はチェックアウトを試みます。 加えて、もし差分の前のゴミの中に "Prereq: " という行が含まれていれ ば、 patch はその行に必要条件 (通常はバージョン番号) が書いてあるものとみな して最初の word を取りだし、オリジナルファイルの中に同じ word がある か どうかを調べます。もしその word が発見できなければ、 patch は処理を実行 してよいか、確認を求めるようになります。 結局のところ、ニュースリーダを使っているときに、パッチを含んだ記事に 対 して |
| patch -d /usr/src/local/blurfl |
のように指示してやれば、blurfl ディレクトリにあるファイルに記事から直接 パッチをあてることができる、ということです。 パッチファイルに、1 つ以上のパッチが含まれていた場合、 patch は、各々が 別 々のパッチファイルであるものと思って処理を実行します。この場合、パッ チを当てるべきオリジナルファイルは、今まで説明したように、各々の差分 情 報 の中から抽出でき、また、各差分記述の前にあるゴミの部分を調べることで ファイル名やリビジョンレベル等の重要事項が得られる、と仮定していま す。 この他に、’+’ で繋げてファイル名を並べることで、 2 番目以降のファイル名 を指定することもできます (ただし、この場合でも、パッチ当てた後の新し い ファイル名を指定することはできません)。 patch には次のようなオプションがあります: |
−b suff, −−suffix=suff |
".orig" や "~" の代わりに suff がバックアップファイルの拡張子とし て解釈されるようにします。 |
−B pref, −−prefix=pref |
pref が、バックアップファイル名の前に付けるプレフィックスとして解 釈されるようにします。この指定を行うと −b の指定は無視されます。 |
−c, −−context |
パッチファイルを context diff 形式として解釈します。 |
−C, −−check |
どういう処理が行われるか確認します。しかし実行はしません。 |
−d dir, −−directory=dir |
dir をディレクトリとみなし、処理の前にそのディレクトリに移動しま す。 |
−D sym, −−ifdef=sym |
"#ifdef...#endif" 構造を用いて差分を示します。差分情報を切り替 え るシンボルとして sym が用いられます。 |
−e, −−ed |
パッチファイルを ed スクリプト形式として解釈します。 |
−E, −−remove−empty−files |
パッチ適用後、空のファイルは削除するようにします。 |
−f, −−force |
ユーザは処理内容を正確に把握しているものとみなし、 patch は何も尋 ねず、次のように仮定して処理を進めます。すなわち、パッチすべき オ リ ジ ナ ルファイルを見つけることができなかった場合はスキップしま す。 ‘‘Prereq:’’ のバージョンが正しくなくても、パッチを実行 し ま す。 パッチ済みと思われても、リバースパッチではないと仮定します。 なお、このオプションは、 patch が表示するメッセージを抑制し ま せ ん。メッセージを止めるには −s を使います。 |
−t, −−batch |
−f と同様ですが、次のように仮定します。パッチすべきオリジナルファ イルを見つけることができなかった場合はスキップします( −f と 同 じ)。 ‘‘Prereq:’’ のバージョンが正しくない場合は、スキップしま す。パッチ済みと思われる場合は、リバースパッチと仮定します。 |
−F number, −−fuzz=number |
最大曖昧度を設定します。このオプションは context diff 形式にの み 適 用 さ れ、 hunk の適用位置を探す際に最大 number 行だけ無視しま す。この値を大きくするとパッチが間違ってあたる可能性も増えるこ と に注意して下さい。デフォルト値は 2 であり、 context の行数(通常は 3)より大きい値にはしません。 |
−i patchfile |
標準入力の代りに patchfile を適用するよう、 patch に指示します。 |
−I, −−index-first |
patch に、‘‘Index:’’ 行を context diff のヘッダより優先して扱わせ ま す。 PATCH_INDEX_FIRST 環境変数を設定すれば同じ効果が得られま す。 |
−l, −−ignore−whitespace |
パターンマッチの条件を緩くし、タブおよび空白に関する違いは無視 し ま す。パターン中の連続する任意個の空白は、入力ファイル中の連続す る任意個の空白にマッチします。しかし普通の文字は正確に合致しな け ればなりません。 context の各行に対して入力ファイル中にマッチする 行がなければなりません。 |
−n, −−normal |
パッチファイルを normal diff 形式として解釈します。 |
−N, −−forward |
リバースパッチ、もしくはすでにパッチ済みであると思われるパッチ を スキップします。 −R も参照して下さい。 |
−o file, −−output=file |
file を出力ファイル名と解釈します。 |
−p[number], −−strip[=number] |
パス名の除去カウント(strip count)を設定します。パッチ作成者と異な るディレクトリにファイルを置いている場合、パッチファイル中のパ ス 名 をどのように解釈するか、を指示します。除去カウントは、パス名の 先頭から何個のスラッシュを除去するか、を指定するものです(その間に あ る ディレクトリ名も取り除かれます)。例えば、パッチファイル中の ファイル名が |
/u/howard/src/blurfl/blurfl.c |
であった場合、 −p あるいは −p0 オプションを指定すると、パス名は全 く修正されません。 −p1 を指定すると、最初のスラッシュがない |
u/howard/src/blurfl/blurfl.c |
となり、 −p4 を指定すると |
blurfl/blurfl.c |
、 そして −p を全く指定しないと "blurfl.c" となります。ただし、そ の前のパス(u/howard/src/blurfl)が相対パスとして存在する場合 は 別 で、 その場合、パス名全体は無修正のままです。最後に、こうして得ら れたファイルを、カレントディレクトリあるいは −d オプションで指 定 したディレクトリ内で探します。 |
−r file, −−reject−file=file |
file をリジェクトファイル名として解釈します。 |
−R, −−reverse |
このパッチが新旧 2 つのファイルを入れ換えて作成したものであること を patch に知らせます。 (ええ、たまにはそういうことも起きると思っ て います。人間ってそういうものです。) patch は各 hunk を適用する 前に新旧を入れ換えます。リジェクトファイルは入れ換え後の形式で 出 力 されます。 −R オプションは ed スクリプト形式の差分には使えませ ん。逆操作の手順をつくり出すには情報が不足しているからです。 もしパッチ中の最初の hunk が失敗すれば、 patch はそれをリ バー ス パッ チにしてうまく適用できるかどうか試します。もしうまくいけば、 −R オプションをセットしてパッチを当てますか、と尋ねられます。そう し ないと答えれば、パッチは通常通り適用されていきます。 (注: パッ チが normal diff 形式で、しかも最初のコマンドが追加 (つまり本来は 削除)であると、この方法ではリバースパッチを検出できません。空のコ ンテキストはどこにでもマッチするので、追加操作は常に成功してし ま う からです。幸い、発見的には、パッチは行を削除するよりも追加ある いは修正するものがほとんどであるため、 normal diff 形式のリバース パッチは削除から始まって失敗におわることがほとんどです。) |
−s, −−silent, −−quiet |
エラーの場合以外、静かに処理を行います。 |
−S, −−skip |
パッ チファイル中のこのパッチを無視し、次のパッチから処理を続ける ように指示します。例えば |
patch -S + -S + <patchfile |
と指定すると、3 つのパッチのうち、1 番目と 2 番目のパッチを無視し ます。 |
−u, −−unified |
パッチファイルを unified diff 形式 (unidiff) として解釈します。 |
−v, −−version |
patch コマンドのリビジョンヘッダとパッチレベルを表示します。 |
−V method, −−version−control=method |
バッ クアップファイル名の作成方法として method を用います。作成さ れるバックアップのタイプは環境変数 VERSION_CONTROL でも指定できま す が、このオプションはそれに優先します。 -B はこのオプションに優 先し、バックアップファイルを作る際に常にプレフィックスが用いら れ るようにします。環境変数 VERSION_CONTROL および -V オプションの引 数の指定は、GNU Emacs の ‘version-control’ 変数と同様です。より分 かりやすい同義語も認識されます。有効な値は以下の通り(一意に短縮す るのも可): |
‘t’ または ‘numbered’ |
常に数字を付けたバックアップファイルを作ります。 |
‘nil’ または ‘existing’ |
すでに数字付きバックアップファイルが存在する場合は、数字付 きバックアップを行い、それ以外の場合は、単純なバックアップ を行います。これがデフォルトです。 |
‘never’ または ‘simple’ |
常に単純なバックアップを行います。 |
−x number, −−debug=number |
内部のデバッグフラグに値を設定します。 patch コマンドにパッチをあ てる人だけに関係するものです。 |
Larry Wall <lwall@netlabs.com> |
TMPDIR |
テンポラリファイルを置くディレクトリ。デフォルトでは /tmp |
SIMPLE_BACKUP_SUFFIX |
バックアップファイルに付ける拡張子を指定します。デフォ ル ト で は、 ".orig" もしくは "~"。 |
VERSION_CONTROL |
数字付きバックアップファイルが作成される際に選択します。 |
$TMPDIR/patch* |
パッ チを作って送付しようとする際に留意すべき点がいくつかあります。第 1 に、patchlevel.h というファイルを管理することで皆は大変幸せになれます。 作 成したパッチファイルの最初の差分はこの patchlevel.h にパッチをあて、 パッチレベルをインクリメントします。パッチの中に Prereq: 行を入れておけ ば、順番通りにパッチを適用しない限り警告が出ます。第 2 に、context diff ヘッダか Index: 行で正しくファイル名を指定していることを確認し て 下 さ い。 サブディレクトリにあるファイルにパッチをあてようとする場合は、必要 に応じて −p オプションを指定するよう、ユーザに伝えて下さい。第 3 に、空 の ファイルと新規ファイルを比較する差分を送付することで、新しいファイル を生成することができます。これは、ターゲットディレクトリにその新ファ イ ルがまだ存在しない場合にのみ有効です。第 4 に、リバースパッチを送付しな いように気を付けて下さい。そのパッチは適用済なのかと皆が混乱します。 第 5 に、例えば 582 個の差分をたったひとつのファイルに突っ込んでハイサヨナ ラとすることもできることはできますが、何か発狂しそうになったときに備 え て、 関係あるパッチをいくつかの独立したファイルにまとめあげるほうがおそ らく賢明でしょう。 |
ここに列挙しきれないほどたくさんありますが、一般に patch がパッチファイ ルを解釈できないことを示しています。 メッ セージ "Hmm..." は、パッチファイル中に処理できないテキストが存在し ていること、そして patch はそのテキスト中にパッチがあるかどうか、もし存 在 すればどういう形式のパッチであるかを推測しようとしていることを示して います。 ひとつでもリジェクトファイルが作成されれば、 patch は 0 でない 終 了 ス テー タスで終了します。いくつものパッチを繰り返し適用する場合は、この終 了ステータスをチェックし、パッチが部分的にしか適用されていないファイ ル に対してさらなるパッチをあてないようにすべきです。 |
patch は ed スクリプト形式では行番号のズレを示せません。また normal diff 形式でも、行番号の誤りを指摘できるの は "change" コ マ ン ド や "delete" コマンドが現れる場合だけです。 context diff 形式で曖昧度 3 を 指定した場合も同様の問題があります。適切な対話インタフェースが追加さ れ る までは、こういう場合は context diff を見比べて修正が意味的に正しいか どうか確認すべきでしょう。もちろん、エラーなくコンパイルできれば、 パッ チ はうまく適用されたという小さなサインにはなりますが、必ずしもいつもそ うだというわけではありません。 たとえ多くの類推を行わなくてはならない場合でも、 patch は通常、正しい結 果 を生成します。しかし、結果が正しいと保証できるのは、パッチを作成した のと正確に同じバージョンのファイルに対してパッチを適用した場合 だ け で す。 |
多めの deviant オフセットと入れ換えコードにより、部分的なマッチングに関 して更に賢くできますが、そのためにはパスを追加する必要がありそうです。 コードが複製されている場合(例えば #ifdef OLDCODE ... #else ... #endif に よって)、 patch は両者にパッチをあてることができません。そしてそこで パッチコマンドがうまくいった場合、そのパッチはおそらく誤って適用され て おり、おまけに「成功しました」と報告してきます。 既に適用済のパッチをあてると、 patch はそれをリバースパッチと考え、適用 したパッチを外すかどうか尋ねてきます。これも特徴の一つと解釈可能で しょ う。 |