はじめに
この記事では、パッチファイルを渡された時の対応として
git applyを使えるようになろうという趣旨です。
適用自体、そこまで難しくはないと思いますが、
初めてやってみるときなどはよくわからないと思います。
使う場面、コマンドの使い方、注意点などをまとめていきます!
どんなときに使う?
以下のような状況で git apply は特に役に立ちます:
| 場面 | 説明 |
|---|---|
| ネットワーク隔離環境での差分受け渡し | リモートリポジトリにアクセスできない環境で、USB/メールで .patch/.diff を渡され、それを適用したいとき |
| 別ブランチ・別リポジトリへの取り込み | 修正差分をブランチ A → ブランチ B に“そのまま”持っていきたいけど、履歴を汚したくない等の場合 |
| レビュー差分の動作確認 | レビュー担当から差分だけを送ってもらい、それをローカルで反映して動作確認したいとき |
| 部分適用/除外適用 | パッチの中に複数ファイル/複数変更が含まれており、そのうち一部だけ取り込みたい/除きたいとき |
| 安全チェックとしての “ドライラン” | 実際に適用する前に、パッチがきちんと適用できるかを確認したいとき |
| 衝突対応時の部分適用 | パッチの一部が現在のコードと合わず適用できないときに、適用可能な部分だけ当てて .rej ファイルを生成する |
git applyの使い方
git applyは、Gitのコミット履歴(マージやリベース)を使わずに、ソースコードの変更差分を記録したパッチファイルを現在の作業ディレクトリに柔軟かつ安全に適用したい場合に利用されます。
つまり、誰かから受け取った差分を、現在の作業中のファイルに、履歴を汚さずに反映させたいときに使います!
使い方は慣れれば簡単なので気楽に見てみてください!
具体例
どんな感じで使われるかを具体的に見ていきます。
手元にtest.cppがあるとします。(ファイル形式は関係ないです。)
ただのHello Worldを出力するファイルです。
#include <iostream>
using namespace std;
int main() {
cout << "Hello World" << endl;
return 0;
}
もし、何かの要因でパッチファイルが作成され
次のようなファイル(test.diff)が渡されるとします。(.patchもあります。)
Hello Worldを出力せずに、「修正しました!」と出力されるように変更されています。
diff --git a/src/practice/test.cpp b/src/practice/test.cpp
index 5721695..6cdcb1c 100644
--- a/src/practice/test.cpp
+++ b/src/practice/test.cpp
@@ -2,7 +2,7 @@
using namespace std;
int main() {
- cout << "Hello World" << endl;
+ cout << "修正しました!" << endl;
return 0;
}
ここで私たちがすべきことは、
- パッチファイルが手元の修正でコンフリクトが起こらないか確認する
- パッチファイルを適用する
- 修正内容をコミットする
という流れになります。
パッチファイルがコンフリクトが起きないか確認
次のコマンドで確認できます。
(必要なファイルは同じディレクトリにあるとします。)
--checkオプションで実際に修正を適用する前にコンフリクトが起こらないかを確認してくれます。
ここを確認せずにコンフリクトが起こると
.rejファイルが生成され、手動でコンフリクトを修正する必要があります。
$ git apply --check test.diff
$ echo $?
0
補足として、コンフリクトが起こる状況を見てみます。
パッチファイルはHello Worldを出力する行を消していますが、
手元の修正では、その行に文字列を追加しています。
#include <iostream>
using namespace std;
int main() {
cout << "Hello World" << "コンフリクト起こるよ、、、"<< endl;
return 0;
}
この状態で、git apply --checkを使ってみます。
$ git apply --check test.diff
error: patch failed: src/practice/test.cpp:2
error: src/practice/test.cpp: patch does not apply
パッチが失敗するよ〜というエラーが出ていますね。
こうなってしまったら、手元の修正内容を確認してコンフリクトが起きないように調整してください、、、
パッチを適用する
コンフリクトが起きないことを確認したら、
git applyコマンドを実行します。
$ git apply test.diff
src/practice/test.diff:10: trailing whitespace.
cout << "修正しました!" << endl;
warning: 1 line adds whitespace errors.
引数ですが、パッチファイルだけで大丈夫です。
パッチファイル自体にどのファイルに対して修正するという情報が入っています。
※ 警告が出ていますが、修正の適用はできているのでここでは無視します。
修正内容をコミットする
ここまでできたら、普段のように手元で修正したような状態と同じです。
git statusで状態を確認して、必要な分だけコミットすればOKです!
もし自分がパッチファイルを作る時は?
これも簡単で、git diff <target> > hogehoge.patchを実行するだけです。
git diffの差分をリダイレクトでファイルに書き込んでいます。
作成された、hogehoge.patchを共有すればOKです!