GitHubでのPull Requestのオプション指定と罠
この記事は KINTO テクノロジーズアドベントカレンダー 2024 の 13 日目の記事です 🎅🎄
はじめに
こんにちは。KINTO ONE開発部の新車サブスク開発グループでフロントエンド開発を担当しているITOYUです。
エンジニアの皆さん、GitHub を使っていますか?我々 KINTO テクノロジーズでも GitHub を利用しています。
チーム開発をする上で Pull Request 機能を使ってコードレビューとマージを行っています。
マージの実行時にオプション指定をすることが出来るのですが、オプション指定をすることが出来るのをご存知でしょうか?
各オプションの違いの説明と、私が過去に躓いた罠について説明します。
何を説明するのか
- GitHub 上での Pull Request のマージオプション
Create a merge commit
Squash and merge
Rebase and merge
- 罠
Rebase and merge
とgit rebase
は一緒じゃない- 自分が前に実行したオプションが次回のデフォルトになる
前提
-
develop ブランチと feature ブランチが存在している
-
develop ブランチから feature ブランチを切って作業をして、develop ブランチに対して Pull Request を作成する
-
develop ブランチと feature ブランチのコミット履歴は以下のようになっている
develop ブランチの commit 履歴
feature ブランチの commit 履歴
GitHub 上での Pull Request のマージオプション
Create a merge commit
Create a merge commit
は、feature ブランチのコミットを hash 値を保持したまま develop ブランチにマージした後、新たにマージコミットを作成します。
実際にマージを行うと以下のようなコミット履歴になります。
マージ後の develop ブランチの commit 履歴
hash 値が保持されたまま develop ブランチにマージされていることが確認できます。そして新たにマージコミットが作成されていることが確認できます。
特徴
- マージ元のコミット履歴の hash 値が保持される
- マージコミットが作成されることでマージによる形跡が残る
使用例
- 複数のコミットをそのまま保持したい場合
- マージの履歴を明確に残したい場合
Squash and merge
Squash and merge
は、feature ブランチのコミットを 1 つのコミットにまとめて develop ブランチにマージします。
実際にマージを行うと以下のようなコミット履歴になります。
マージ後の develop ブランチの commit 履歴
feature ブランチでは複数の commit がありましたが、develop ブランチには 1 つの commit しか存在していません。
特徴
- マージ元のコミット履歴が1つにまとめられる
使用例
- コミット履歴をシンプルに保ちたい場合
- 小さな変更をまとめて1つのコミットにしたい場合
Rebase and merge
Rebase and merge
は、feature ブランチのコミットを develop ブランチの最新のコミットの直後にコピーし、develop ブランチにマージします。
その際コミットはまとめられず、feature ブランチのコミット履歴がそのまま develop ブランチにマージされます。
マージ後の develop ブランチの commit 履歴
この際マージコミットが作成されていないことが確認できます。
特徴
- マージ元のコミット履歴がそのまま develop ブランチにマージされる
- マージコミットが作成されないので、コミット履歴が綺麗になる
- マージ元の hash 値とは異なり、新たなコミットとして作成される
使用例
- コミット履歴をそのまま保持しつつ、マージコミットを作成したくない場合
- リベースを行ってコミット履歴を整理したい場合
罠
上記では各オプションの説明をしました。ここからは私が過去に躓いた罠について説明します。
Rebase and merge
とgit rebase
は一緒じゃない
中規模プロジェクト用の開発ブランチを用意して共同で開発をしていました。
そこでブランチ元のdevelopブランチが更新されたのでプロジェクト用のブランチをgit rebase
を利用してコミット履歴を整理しようと考えました。
ただそうなるとforce push
が必要になるので、共同で作業しているブランチにはforce push
を避けたいと考えました。
そこでGitHub PullRequest機能のオプションのRebase and merge
を使えば代用可能なのではないかと考えました。
そうすることでコミット履歴も綺麗に保たれ、ローカルでの作業もなくなり安全だと考えました。
さて、develop ブランチに feature ブランチから出した Pull Request をRebase and merge
オプションを使ってマージを行った後、差分が無いかチェックして見ました。
めちゃくちゃ差分がありました。
一見 develop ブランチと feature ブランチのコミット履歴は同じに見えますが、hash 値が異なっていました。
Rebase and merge
の特徴の1つに「マージ元の hash 値とは異なり、新たなコミットとして作成される」というものがあるためです。
Rebase and merge
を実行した時とgit rebase
を実行した時には挙動が異なるので、同一の挙動を期待してはいけないと学びました。
自分が前に実行したオプションが次回のデフォルトになる
これは罠というか、不注意によるミスです。
前提として、私のチームではいつもSquash and merge
を利用して作業ブランチのコミット履歴を綺麗に保っています。
先ほどRebase and merge
による実験をして失敗に終わった後、通常の作業に戻りました。
そして私の出した Pull Request が approve されたのでいつも通りマージを行いました。
そこで気付く違和感。何かがおかしい。
なぜかRebase and merge
が実行されている...
Pull Request のマージオプションは、自分が前に実行したオプションが次回のデフォルトになるようです。ちょっと考えれば当たり前のことですね。
今まで意識していなかったので気付かなかったのですが、オプションをいじる際は次の Pull Request にも影響があるので注意が必要だと学びました。
まとめ
GitHubのPull Requestマージ時のオプション指定の特徴を踏まえた上で、目的に合わせて適切なオプションを選択することが重要です。
私は以下のような使い分けをしています。
Create a merge commit
: マージ元のコミットハッシュを保持し、マージの履歴を明確に残したい場合に使用します。これにより、どのブランチがどのタイミングでマージされたかが一目でわかります。Squash and merge
: 作業コミットを1つにまとめて、コミット履歴をシンプルに保ちたい場合に使用します。これにより、細かいコミットが1つにまとめられ、履歴が見やすくなります。Rebase and merge
: マージコミットを作成せずに、コミット履歴を直線的に保ちたい場合に使用します。これにより、変更の流れが追いやすくなり、履歴が綺麗になります。
また、Pull Requestをマージする際には、今設定されているオプションが何なのかを必ず確認してからマージを行うことで予期せぬ事故を防ぐようにしましょう。
関連記事 | Related Posts
We are hiring!
【フロントエンドエンジニア(コンテンツ開発)】新車サブスク開発G/東京
新車サブスク開発グループについてTOYOTAのクルマのサブスクリプションサービスである『 KINTO ONE 』のWebサイトの開発、運用をしています。業務内容トヨタグループの金融、モビリティサービスの内製開発組織である同社にて、自社サービスである、クルマのサブスクリプションサービス『KINTO ONE』のWebサイトコンテンツの開発・運用業務を担っていただきます。
【フロントエンドエンジニア】新車サブスク開発G/東京
新車サブスク開発グループについてTOYOTAのクルマのサブスクリプションサービスである『 KINTO ONE 』のWebサイトの開発、運用をしています。業務内容トヨタグループの金融、モビリティサービスの内製開発組織である同社にて、自社サービスである、TOYOTAのクルマのサブスクリプションサービス『KINTO ONE』のWebサイトの開発、運用を行っていただきます。