PATCH(1)

名称
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*

関連項目
diff(1)

パッチ作成者への注意
パッチを作って送付しようとする際に留意すべき点がいくつかあります。 第 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 はそれをリバースパッチと考え、適用したパッチを外すかどうか尋ねてきます。 これも特徴の一つと解釈可能でしょう。