esm アジャイル事業部 開発者ブログ

永和システムマネジメントアジャイル事業部の開発者ブログです。

パッチファイルの構造

TL;DR - patch(1) に渡すパッチファイルの最初の方には色々書ける。

こんにちは、hibariya です。これまで曖昧に理解していたパッチファイルのフォーマットについて調べました。たまに diff や git の出力するパッチを patch コマンドで既存のファイルに適用する機会があります。git の吐くパッチというとこういうのです。

commit fc787cd3fc0b69526d8686e529e7574b5be9497c
Author: Hibariya <hibariya@gmail.com>
Date:   Tue Nov 8 18:49:32 2016 +0900

    Resolve all messages in advance

diff --git a/frontend/app/routes/stars.js b/frontend/app/routes/stars.js
index 80b476b..59e6947 100644
--- a/frontend/app/routes/stars.js
+++ b/frontend/app/routes/stars.js
@@ -21,11 +21,19 @@ let StarsRoute = Ember.Route.extend(MousetrapRoute, {
   },
 
   model({query}) {
+    let stars;
+
     if (query) {
(長いので以下略)

パッチファイルの先頭にあるもの

git show -p で出したパッチのはじめには、上のようにコミットの情報があります。これらの行は patch に渡す情報としては不要そうですが、そのままでも patch -p1 < patchfile と渡すと問題なく適用されます。

先頭の不要な情報は patch がいい感じに無視してくれているのでしょうか。気になります。手元のシェルで man 1 patch してみました。

patch tries to skip any leading garbage, apply the diff, and then skip any trailing garbage. Thus you could feed an article or message containing a diff listing to patch, and it should work.

なるほど、やはり不要な情報 (garbage) を無視してくれているんですね。だから英語や日本語でコメントを書いたりできる。実際にコメントが書かれている例を探してみたところ、Pure Data (extended) の Debian 向けパッチに見つけました。

Description: hard code to Debian's /usr/bin/wish8.5
 Force pd-gui.tcl to use /usr/bin/wish8.5 so that it always uses Tk 8.5
 regardless of how the 'wish' alternatives are setup.
Author: Hans-Christoph Steiner <hans@eds.org>

--- pd-extended-0.43.4.orig/pd/tcl/pd-gui.tcl   (revision 16941)
+++ pd-extended-0.43.4/pd/tcl/pd-gui.tcl        (working copy)
@@ -1,6 +1,6 @@
 #!/bin/sh
 # This line continues for Tcl, but is a single line for 'sh' \
-    exec wish "$0" -- ${1+"$@"}
+    exec /usr/bin/wish8.5 "$0" -- ${1+"$@"}
 # For information on usage and redistribution, and for a DISCLAIMER OF ALL
 # WARRANTIES, see the file, "LICENSE.txt," in this distribution.
 # Copyright (c) 1997-2009 Miller Puckette.

適用する目的を同じファイルに書けるのは便利そうです。

パッチの本体

ところで patch はどうやってパッチの本体を見分けているのでしょうか。ぱっと見、最初の空行で分かれているように見えますが、せっかくなので一応確認してみましょう。また man を見てみます。

patch takes a patch file patchfile containing a difference listing produced by the diff program and applies those differences to one or more original files, producing patched versions.

patch は diff の出力を受けとることを想定しているということなので、diff のフォーマットを見ると良さそうです。よく使う Unified Format の説明を見つけました。

The unified output format starts with a two-line header, which looks like this:

--- from-file from-file-modification-time
+++ to-file to-file-modification-time

Comparing and Merging Files: Detailed Unified

予想通り、この ---+++ で始まる行から先がパッチの本体でした。なるほどー。これで、これからはパッチがどこから始まるか一目で分かるし、心置きなくコメントが書けそうです。

おわりに

パッチファイルについて簡単に調べてみました。当たり前かもしれないし、使う頻度を考えると少しトリビアルかもしれない内容でしたが、いつかどこかでなにかのお役に立てばと思います。