Linuxエンジニアらしいパッチのつくりかた

以前 diffコマンドを使ってソースコードのパッチの作ったところ、こんなのLinuxエンジニアじゃないじゃん。と笑われてしまいました。

diffコマンドでのパッチの作り方をググった時、どのオプションを作るべきかわからなかったり、そもそもどのオプションを付けるかさえ考えない人もいるかもしれません。

かっこいいLinuxエンジニアになるためには、適切なオプションを付けましょう！

## diffコマンドでのパッチの作り方

Linuxカーネルのドキュメントフォルダ(Documentation/）には、`SubmittingPatches`というドキュメントがあります。
このドキュメントの１章には以下のように書かれています。

```
Use "diff -up" or "diff -uprN" to create patches.  git generates patches
in this form by default; if you're using git, you can skip this section
entirely.
```

パッチを作るためには、`diff -up`もしくは`diff -uprN`コマンドを使いましょう。

つまり、

**1つのソースコードに対するパッチを作成する**
`diff -up [オリジナルソース] [修正後ソース]`

**ディレクトリ以下のソースコードに対するパッチを作成する**
`diff -uprN [オリジナルソースディレクトリ] [修正後ソースディレクトリ]`

とします。

### オプションの意味を理解しておく

では、diffコマンドで使うべきオプション`u`、`p`、`r`、`N`はどんなオプションでしょうか？
詳細は`man diff`などを見ればわかるので、ざっくり記載しておきます。

| オプション | 意味                            |
|:---------:|--------------------------------|
| u         |unified形式で出力する             |
| p         |変更箇所の関数名(C言語)を表示する  |
| r         |サブディレクトリを再帰的に比較する |
| N         |比較するファイルが無い場合、同名の空ファイルがあるのと同じ動作をする |

テスト用のソースコードはhello worldのスペルを間違えたもので確認する。


```:修正前
#include <stdio.h>

int main(int argc, char **argv)
{
	/* Test for diff patch.
	 * -4
	 * -3
	 * -2
	 */
	printf("Hello word!!\n");
	return 0;
	/* +2
	 * +3
	 * +4
	 */
}
```

```:修正後
#include <stdio.h>

int main(int argc, char **argv)
{
	/* Test for diff patch.
	 * -4
	 * -3
	 * -2
	 */
	printf("Hello world!!\n");
	return 0;
	/* +2
	 * +3
	 * +4
	 */
}
```

#### 「u」オプション

`u`オプションを付加すると、差分ファイルの情報と、修正箇所の前後3行を出力してくれる。
どこが修正されたかわかりやすくなる。

```
user@debian7:~/$ diff -u  source_org/c_lang/hello.c source/c_lang/hello.c
--- source_org/c_lang/hello.c	2015-02-22 15:11:44.218901466 +0900
+++ source/c_lang/hello.c	2015-02-22 20:11:18.528031250 +0900
@@ -7,7 +7,7 @@
 	 * -3
 	 * -2
 	 */
-	printf("Hello word!!\n");
+	printf("Hello world!!\n");
 	return 0;
 	/* +2
 	 * +3
```

#### 「p」オプション

`p`オプションを付加すると、差分ファイルの情報と、修正対象箇所の関数名を出力してくれる。

```
user@debian7:~/$ diff -p  source_org/c_lang/hello.c source/c_lang/hello.c
*** source_org/c_lang/hello.c	2015-02-22 15:11:44.218901466 +0900
--- source/c_lang/hello.c	2015-02-22 20:11:18.528031250 +0900
*************** int main(int argc, char **argv)
*** 7,13 ****
  	 * -3
  	 * -2
  	 */
! 	printf("Hello word!!\n");
  	return 0;
  	/* +2
  	 * +3
--- 7,13 ----
  	 * -3
  	 * -2
  	 */
! 	printf("Hello world!!\n");
  	return 0;
  	/* +2
  	 * +3
```

#### 「r」オプション

`r`オプションを付加すると、ディレクトリ以下を再帰的に比較してくれる。

このとき、source/qtディレクトリに新たに生成されたhello_qt.cppファイルは差分がある事を知らせてくれている。


```
user@debian7:~$ diff -r  source_org/  source/
diff -r source_org/c_lang/hello.c source/c_lang/hello.c
10c10
< 	printf("Hello word!!\n");
---
> 	printf("Hello world!!\n");
source/qtだけに発見: hello_qt.cpp
```

#### 「N」オプション

`N`オプションを付加すると、片側にしか無いファイルは差分がある事だけではなく、全行を差分として表示してくれる。

```
user@debian7:~$ diff -N  source_org/qt/  source/qt
diff -N source_org/qt/hello_qt.cpp source/qt/hello_qt.cpp
0a1,11
> #include <QApplication>
> #include <QLabel>
> 
> int main(int argc, char **argv)
> {
> 	QApplication app(argc, argv);
> 	QLabel* label = new QLabel("<i>Hello Qt!</i>");
> 
> 	label->show();
> 	return app.exec();
> }
```


## gitコマンドでのパッチの作り方

`SubmittingPatches`にあるようにgit diffのコマンドでは全てオプションがついた状態と同じに出力される
gitコマンドの詳細は、ここには書きません。。。

```
user@debian7:~/$ git diff c976c2f4f
diff --git a/c_lang/hello.c b/c_lang/hello.c
index bab4f9d..53eafda 100644
--- a/c_lang/hello.c
+++ b/c_lang/hello.c
@@ -7,7 +7,7 @@ int main(int argc, char **argv)
         * -3
         * -2
         */
-       printf("Hello word!!\n");
+       printf("Hello world!!\n");
        return 0;
        /* +2
         * +3
diff --git a/qt/hello_qt.cpp b/qt/hello_qt.cpp
new file mode 100644
index 0000000..aa85988
--- /dev/null
+++ b/qt/hello_qt.cpp
@@ -0,0 +1,11 @@
+#include <QApplication>
+#include <QLabel>
+
+int main(int argc, char **argv)
+{
+       QApplication app(argc, argv);
+       QLabel* label = new QLabel("<i>Hello Qt!</i>");
+
+       label->show();
+       return app.exec();
+}
```

## まとめ

* ファイル単位でパッチを作る場合は`diff -up`コマンドで行う
* ディレクトリ単位でパッチを作る場合は`diff -uprN`コマンドで行う
* git diffコマンドを使う場合は、diffの`-uprN`オプションと同じ形式で出力される