GitHubでのPull Requestのオプション指定と罠
この記事は KINTO テクノロジーズアドベントカレンダー 2024 の 13 日目の記事です 🎅🎄
はじめに
こんにちは。KINTO ONE開発部の新車サブスク開発グループでフロントエンド開発を担当しているITOYUです。
エンジニアの皆さん、GitHub を使っていますか?我々 KINTO テクノロジーズでも GitHub を利用しています。
チーム開発をする上で Pull Request 機能を使ってコードレビューとマージを行っています。
マージの実行時にオプション指定をすることが出来るのですが、オプション指定をすることが出来るのをご存知でしょうか?
各オプションの違いの説明と、私が過去に躓いた罠について説明します。

何を説明するのか
- GitHub 上での Pull Request のマージオプション
Create a merge commitSquash and mergeRebase 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!
【PjM】KINTO開発推進G/東京
KINTO開発部 KINTO開発推進グループについてKINTO開発推進グループでは、クルマのサブスクリプションサービスである『 KINTO ONE 』をはじめ、国内向けサービスのプロジェクト計画立案からリリース、運用保守に至るまでのプロジェクト管理を行っています。
【KINTO FACTORYバックエンドエンジニア(リーダークラス)】FACTORY EC開発G/東京・大阪
KINTO FACTORYについて自動車のソフトウェア、ハードウェア両面でのアップグレードを行う新サービスです。トヨタ/レクサス/GRの車をお持ちのお客様にOTAやハードウェアアップデートを通してリフォーム、アップグレード、パーソナライズなどを提供し購入後にも進化続ける自動車を提供するモビリティ業界における先端のサービスを提供します。



