Gitの cherry-pick は、あるブランチでのコミットを別のブランチに取り込むコマンドでありとても便利です。便利なのですが、チェリーピックで複数のコミットを対象にした時に稀に無いと思っていたコードの衝突が起きることがあります。これは例えば、次の流れで起きます。
- ファイルAをブランチX上のコミットαで変更する
- ファイルAの変更をブランチX上のコミットβで差し戻す
- ファイルAをブランチY上のコミットγで変更する
- チェリーピックでコミットα、コミットβを含むコミットらをブランチYに取り込もうとする
この流れだとコミットγとコミットα、コミットβがコンフリクトします。コンフリクトしますが、チェリーピックの対象をまとめるとファイルAについての変更はないので、そもそもファイルAでコンフリクト自体を起こさないで欲しいです。
この問題を回避するために有効なのが、チェリーピックの対象となるコミットを事前にスカッシュしてまとめておくという方法です。複数のコミットを1つにスカッシュすることで、それぞれのコミット間で発生していた差分の相殺をGitが1つのまとまった変更として扱えるようになります。こうすると最終的には変わっていないファイルに対する無意味な衝突を避けやすくなります。
CLIでスカッシュは次のようにできます。
# まず次のコマンドを実行します。 git rebase -i <まとめたいコミットらの最新のコミットのリビジョン番号> # ターミナルに以下のような表示がされます。 pick b5c6d7e 修正6 pick c3d4e5g 修正5 pick d1c2b3f 修正4 pick e8f9a10 修正3 # これを次のようにまとめたいコミットをpickからsquashに変えて保存します。 # 次の例ならば修正6に修正3~5の内容が含まれるようになります。 pick b5c6d7e 修正6 squash c3d4e5g 修正5 squash d1c2b3f 修正4 squash e8f9a10 修正3
PhpStormのGitタブのようなGUIならばコミットを複数選択して「コミットをスカッシュ」などの操作ができます。大体のGUIはできるはずです。
あとはスカッシュしたコミットをチェリーピックし、必要ならばスカッシュしたコミットを元に戻せば完了です(まとまった1コミットの方が見やすく、リモートのコミットログと差異がないなら戻す必要はないです)。チェリーピックは次のようにできます。
git cherry-pick <スカッシュ済みコミットのリビジョン番号>
スカッシュを戻すにはブランチをスカッシュしていないリモートに合わせるように戻す方法とGitの機能で戻す方法があります。
リモートに合わせるように戻すなら次の方法があります。
# リモート/ブランチ名 git reset --hard origin/develop
Gitの機能で戻す場合はgit reflogとログを参照したresetが使えます。これは次のようにできます。
git reflog # ↑のコマンドを実行すると次のような表示がされます。 1b766f78 (HEAD -> develop, origin/develop) HEAD@{0}: reset: moving to origin/develop 6ea3f999 HEAD@{1}: rebase (finish): returning to refs/heads/develop 6ea3f999 HEAD@{2}: rebase (pick): xxxxxxxxxxxxx c39731e4 HEAD@{3}: rebase (pick): xxxxxxxxxxxxx 25adc334 HEAD@{4}: rebase (pick): xxxxxxxxxxxxx 75aa37ae HEAD@{5}: rebase (squash): xxxxxxxxxxxxxx d08482aa HEAD@{6}: rebase (squash): # This is a combination of 6 commits. c1940459 HEAD@{7}: rebase (squash): # This is a combination of 5 commits. 08e39632 HEAD@{8}: rebase (squash): # This is a combination of 4 commits. 973d839b HEAD@{9}: rebase (squash): # This is a combination of 3 commits. 2ab16f7e HEAD@{10}: rebase (squash): # This is a combination of 2 commits. e40b2062 HEAD@{11}: rebase (start): checkout a4dff918d75a888f06835ad5f5a5e5ef7312a939 1b766f78 (HEAD -> develop, origin/develop) HEAD@{12}: commit: xxxxxxxxxxxxxx 7284996e HEAD@{13}: commit: xxxxxxxxxxxxxx 0a052e40 HEAD@{14}: commit: xxxxxxxxxxxxxx # 戻したい地点のハッシュでリセット git reset --hard e40b2062
こんな感じでスカッシュを使ってチェリーピックを快適にすることができます。