前回深夜テンションで書いた記事が軽くバズってしまった @tsuboyataiki です。
一つの大きな機能作成で、複数の作業が同時並行になってしまい、別ブランチの特定の作業(コミット)が必要になるタイミングがありました。
そこで社員の方からcherry-pickの使い方を教えていただいたので残しておこうと思います。
cherry-pickって?
**"cherry pick"**は直訳すると「(いいところだけ)つまみ食いする」みたいな意味があるそうです。
Gitの機能としては、リファレンスより以下のような記述があります。
Given one or more existing commits, apply the change each one introduces, recording a new commit for each.
訳:1つ以上の既存のコミットを前提として、それぞれが導入する変更を適用し、それぞれの新しいコミットを記録します。
要は「別のブランチ(ワークツリー)にある変更(コミット)を持ってこれるよ」という感じです。
ユースケースは?
プロダクト・システムで大きな機能を作成するとき、表示部分、管理部分、データの関連付けなどごとにブランチを分けて作業することが多いでしょう。
その時、「管理部分作成で作ったメソッド持ってきたい」とか「別ブランチで定義した配列が必要になった」みたいなことがよく起きます。
そのような際にcherry-pickを使うことで、コミットログの整合性を取りながら特定の変更を持ってくることが出来ます。
使い方
コマンドの基本は以下の感じです。
$ git cherry-pick コミットのハッシュ値
実際に使用する際は、以下のように$ git log
などで確認してから使うのが一般的かと思います。
$ git log
commit 645b44d687dea267b8b15657fb91fd7bc88f8bca (HEAD -> tsuboya-20200608, origin/tsuboya-20200608)
Author: TsuboyaTaiki <tsuboyataiki@taiki-mac.local>
Date: Mon Jun 8 17:13:50 2020 +0900
パスワードのバリデーション修正
( .. 省 略 .. )
$ git switch tsuboya-20200607
$ git cherry-pick 645b44d687dea267b8b15657fb91fd7bc88f8bca
[tsuboya-20200607 d719a90] パスワードのバリデーション修正
Author: TsuboyaTaiki <tsuboyataiki@taiki-mac.local>
Date: Mon Jun 8 17:13:50 2020 +0900
1 file changed, 1 insertion(+), 1 deletion(-)
↑で、別ブランチでのコミットを持ってこれました。
ここで$ git log
で変更が反映されているか確認すると...
$ git log
commit d719a90b3667b1e866ea3938f1ca400782e2d133 (HEAD -> tsuboya-20200607)
Author: TsuboyaTaiki <tsuboyataiki@taiki-mac.local>
Date: Mon Jun 8 17:13:50 2020 +0900
パスワードのバリデーション修正
うまく行っていれば、このようにコミットログで確認できます。
コンフリクトが起きた場合
上記で紹介した例はあくまでコンフリクト(各ブランチの変更内容の競合)が起きてない場合に過ぎません。
ただ実際のところ体感半分くらいの確率でコンフリクトは起きるのでその場合の対処も紹介します。
$ git cherry-pick a37ed09019cc569c5d95e253d5f39729f7e2b2b5
Auto-merging app/models/account.rb
CONFLICT (content): Merge conflict in app/models/account.rb
error: could not apply a37ed09... change coment BBB
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
$
実際にコンフリクトが起きると、このようにコンフリクトが起きている箇所や、該当する編集内容が表示されます。また、先ほどうまく行った場合と違ってこの時点ではコミットはまだ反映されていません。
では、エディタで該当箇所を見てみると...
Current Change
とIncoming Change
という形で分かれている状態になっていますね。
Current Change
を反映したい場合は、下の画像の赤丸の「Accept Current Change」を選択し、Incoming Change
の場合は青丸の方を選択すると、選択した方が反映されます(僕の場合はVSCodeで操作しています)。
あとは忘れずに$ git add
と$ git commit
をして終了です。
もしcherry-pickの操作をなかったことにしたい場合は、以下のようにHEADとステージングをリセットすれば大丈夫です(まだコミットしてない変更内容も消えてしまうので注意)。
$ git reset HEAD
$ git restore . # コンフリクトが起きたファイルだけでもOK
※このやり方は僕が試しただけなのでもっと適したやり方があれば教えていただけると幸いです。