Gitを使ってチーム開発をしていると特定のファイルにだけ変更を適応したい場面があります。
そんなときはgit diff
と git apply
を使いましょう。
使用ケース
- 特定のブランチやコミットから一部の変更だけ取り入れる
-
cherry-pick
より柔軟に対応可
-
- コードレビューなどの修正提案を渡す
-
git stash
の代用
パッチとは
Gitではパッチ作成にgit diff
を、パッチ適応にgit apply
を使います。パッチとは差分を意味します。一般にはソフトウェアの不具合を修正したり、機能を追加したりするために使われる更新プログラムを指すことが多く、修正プログラムやアップデートとも呼ばれることがありますが、これも広義では差分を意味しています。Gitの場合は単純に差分をパッチと呼びます。
git diff
は差分を表示するコマンドですが、これがパッチの形式になっていることが確認できます。
git apply
コマンドでは「指定された差分出力(つまり「パッチ」)を読み取り、ファイルに適用します。」と説明されています。
コマンド解説
git diff
パッチファイルへの出力
$ git diff > patch
$ git diff [オプションや種々の指定] > patch
git diff
は単に差分を出力するだけですが、これをファイルにリダイレクトすることでパッチファイルを作成できます。
作業ツリーに関する差分
$ git diff (1)
$ git diff --cached (2)
$ git diff HEAD (3)
-
ステージングと作業ツリーとの間の変更
-
ステージングと最後のコミットとの間の変更:
git commit
でコミットされる内容 -
作業ツリーと最後のコミットとの間の変更:
git commit -a
でコミットされる内容
特定のブランチやコミットとの差分
$ git diff commitA..commitB (1)
$ git diff commitA...commitB (2)
- 特定のコミット間の差分
- 両者のコミットの共通の祖先(マージベース)からcommitBの間の変更
ブランチを指定することも可能です。Gitではブランチ名=そのブランチの最新コミットなのでgit diff topic..main
のようにコミットをブランチに置き換えればOKです。
(1)はgit diff commitA commitB
のように..
を省くこともできますが使用を推奨します。..
はコミット間を表すgit共通の記法なので、他のコマンドでも使えます。
(2)はGitHubのPull Requestの「Files changed」タブで表示される差分と同じものをイメージしてください。
ファイルの指定
$ git diff ファイル名
コマンドの最後にファイルやディレクトリを指定することで特定の変更だけを取り出すことができます。
git apply
パッチを適応
$ git apply patch
主なオプション
# 適用した変更を取り消す
git apply --reverse patch
# パッチを適用せず、変更の概要を表示する
git apply --stat patch
# パッチを適用せず、エラーが出るか確認する
git apply --check patch
応用例
$ git diff feat_ref~1..feat_ref path/to/directory > patch
$ git apply patch
feat_ref
ブランチの上から1つ目のコミットのうち、path/to/directory
下にある差分だけを適用にしたい場合、上記のようなコマンドで実現できます。
補足
- stashの代用について
- 柔軟に扱える
- reflogが使えない
- linuxに似たコマンド
diff
とpatch
- ファイル間の差分を抽出し適用するコマンド
-
git diff --no-index
とgit apply
で同じ
-
git format-patch
とgit am
は使わない