ここでは、git apply コマンドで適用可能な Git 用の patch ファイルを作成する方法を示します。 インデックスに追加していない変更を、とりあえずパッチファイルとして残しておきたいような場合は、以下のように作成します。
$ git diff file.txt > file.patch
例えば、インデックスに追加していない変更を以下のように破棄してしまったとしても、
$ git checkout file.txt
パッチファイルが残っていれば、後からその変更分を復活させることができます。
$ git apply file.patch
Linux に標準で付属している patch
コマンドで適用できるパッチファイルを作成するには、git diff
を実行するときに --no-prefix
オプションを指定します。
これにより、パッチファイル内のパス表記が、
--- a/aaa/bbb/ccc/file.cpp
+++ b/aaa/bbb/ccc/file.cpp
のように a
や b
のプレフィックスがついていたものを
--- aaa/bbb/ccc/file.cpp
+++ aaa/bbb/ccc/file.cpp
のように patch
コマンドで解釈できるものに変更できます。
$ git diff --no-prefix file.cpp > file.patch
$ (.git ディレクトリのあるルートディレクトリへ移動)
$ patch -p0 < file.patch
仮にパッチファイルを作るときに --no-prefix
を付けないで作成してしまった場合でも、patch
コマンドの引数で -p1
オプションを付けてパスの階層を調整すれば、そのまま適用することができます。
$ patch -p1 < file.patch
git diff
の出力からパッチファイルを作成すると、そのパッチファイルは .git
ディレクトリのあるディレクトリから適用できる形のパッチファイルとして作成されます。
例えば、.git
ディレクトリと同じ階層に aaa
ディレクトリがあるとして、その中の file.txt
のパッチファイルを作成するとします。
$ cd aaa
$ git diff --no-prefix file.cpp > file.prefix
と実行すると、パッチファイル内のパスの表現は、
--- aaa/file.cpp
+++ aaa/file.cpp
となります。
つまり、このパッチファイルは .git
ディレクトリから patch
コマンドで当てる形で作成されます。
このパッチファイルを、aaa
ディレクトリをカレントディレクトリにして適用できるようにするには、--relative
オプションで、基準となるディレクトリを指定します。
$ git diff --no-prefix --relative=aaa/ file.cpp > file.prefix
これで、aaa
ディレクトリからパッチファイルを当てることができます。
$ cd aaa
$ patch -p0 < file.patch
git format-patch
でパッチファイルを作成すると、そのパッチファイルを受け取った人は、git am
コマンドを使ってコミット履歴をキープして自分のリポジトリにコミットできます。
例えば、以下のように実行すると、コミット履歴からパッチファイルを patches
ディレクトリ作成します。
パッチファイルはコミット 1 つごとに 1 つずつ作られます。
$ git format-patch -o patches fec09ab # fec09ab からの HEAD までのコミット
$ git format-patch -o patches fec09ab.. # 同上
$ git format-patch -o patches fec09ab..HEAD # 同上
作成されたパッチファイルは git am
コマンドで適用することができます(am は apply mailbox の略)。
$ git am patches/0001-HogeHoge.patch
すでにパッチ対象のファイルが更新されていると、git am
でエラーが発生します。
git am
を取り消したい場合は、以下のようにすると、パッチを適用しようとする前の状態に戻ります。
$ git am --abort
git am
に -3
オプションをつけると、修正されたファイルに対してパッチを適用できる可能性があがります。
$ git am -3 patches/0001-HogeHoge.patch
上記のようにしてコンフリクトが発生した場合は、まずは git status
で対象のファイルを確認し、ファイルを修正してコンフリクトを解決します。
その後、以下のようにしてパッチファイルによるコミットを確定させます。
$ git add conflicted_file.cpp
$ git am --resolved