本文へスキップ / Skip to main content
KINTO Tech Blog

約7分で読めます

Development

GitHubでのPull Requestのオプション指定と罠

GitHubでのPull Requestのオプション指定と罠 cover
再生速度
要約を読む

Pull Requestのマージオプションが間違った使い方で使われると、コミット履歴が壊れたり、差分が出てトラブルになることがあります。 そこで、3つのマージオプションの違いと、私が実際に間違えた2つの罠を説明します。 その結果、チームのコード履歴が乱れ、差分が出て開発が遅れました。 その問題を解決するために、各オプションの使い分けと、設定の確認を徹底しました。 まず、Create a merge commitはマージ時に新しいコミットを作成し、元のコミットのハッシュを保持します。 これにより、どのブランチがいつマージされたかが一目でわかります。 このオプションは、複数の変更をそのまま残したい場合に使います。 実際にはマージ後の履歴に元のコミットが残り、マージの痕跡が明確になります。 次に、Squash and mergeは複数のコミットを1つにまとめてマージします。 これにより、コミット履歴がシンプルになり、変更の流れが見やすくなります。 小さな変更をまとめて1つのコミットにしたいときや、履歴を整えたいときに使います。 マージ後に履歴は1つだけになり、細かい変更が見えにくくなるため、使い分けが重要です。 そして、Rebase and mergeはマージ元のコミットをそのままdevelopブランチにコピーし、マージコミットを作りません。 これにより、コミット履歴が綺麗に直線的に保たれます。 ただし、これはgit rebaseとは異なり、新しいコミットとして作成されるため、ハッシュが変わってしまいます。 実際の開発で、このオプションを使い誤解をもたらし、差分が出て開発が遅れました。 その結果、私が間違えたのは2つです。 1つ目は、Rebase and mergeをgit rebaseと混同して使ったこと。 ブランチをリベースするにはforce pushが必要ですが、このオプションはその代わりに使えると思い込んで使いました。 しかし、実際にはハッシュが変わるので、差分が出て開発が進まなくなりました。 2つ目は、自分が前回使ったオプションが、次のPull Requestでもデフォルトになることです。 私はいつもSquash and mergeを使っていたので、その設定がそのまま継続され、後からRebase and mergeが使われていたことに気づきました。 この設定は、前のマージの結果が次に影響するため、無意識にミスを招きます。 最終的に、各オプションに目的を合わせて使うことで、コミット履歴の品質が向上しました。 Create a merge commitは履歴の明確さを保ち、Squash and mergeはシンプルさを重視、Rebase and mergeは変更の流れを追いたいときに使います。 そして、毎回マージ前にオプションを確認することで、誤った設定による事故を防ぐようになりました。

AI が生成した要約です。正確な内容は本文をご確認ください。

この記事は KINTO テクノロジーズアドベントカレンダー 2024 の 13 日目の記事です 🎅🎄

はじめに

こんにちは。KINTO ONE開発部の新車サブスク開発グループでフロントエンド開発を担当しているITOYUです。

エンジニアの皆さん、GitHub を使っていますか?我々 KINTO テクノロジーズでも GitHub を利用しています。
チーム開発をする上で Pull Request 機能を使ってコードレビューとマージを行っています。

マージの実行時にオプション指定をすることが出来るのですが、オプション指定をすることが出来るのをご存知でしょうか?
各オプションの違いの説明と、私が過去に躓いた罠について説明します。

option_select

何を説明するのか

  • 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 履歴
develop_history

feature ブランチの commit 履歴
feature_history

GitHub 上での Pull Request のマージオプション

Create a merge commit

Create a merge commit は、feature ブランチのコミットを hash 値を保持したまま develop ブランチにマージした後、新たにマージコミットを作成します。
実際にマージを行うと以下のようなコミット履歴になります。

マージ後の develop ブランチの commit 履歴
create_merge_commit

hash 値が保持されたまま develop ブランチにマージされていることが確認できます。そして新たにマージコミットが作成されていることが確認できます。

特徴

  • マージ元のコミット履歴の hash 値が保持される
  • マージコミットが作成されることでマージによる形跡が残る

使用例

  • 複数のコミットをそのまま保持したい場合
  • マージの履歴を明確に残したい場合

Squash and merge

Squash and merge は、feature ブランチのコミットを 1 つのコミットにまとめて develop ブランチにマージします。
実際にマージを行うと以下のようなコミット履歴になります。

マージ後の develop ブランチの commit 履歴
squash_and_merge

feature ブランチでは複数の commit がありましたが、develop ブランチには 1 つの commit しか存在していません。

特徴

  • マージ元のコミット履歴が1つにまとめられる

使用例

  • コミット履歴をシンプルに保ちたい場合
  • 小さな変更をまとめて1つのコミットにしたい場合

Rebase and merge

Rebase and merge は、feature ブランチのコミットを develop ブランチの最新のコミットの直後にコピーし、develop ブランチにマージします。
その際コミットはまとめられず、feature ブランチのコミット履歴がそのまま develop ブランチにマージされます。

マージ後の develop ブランチの commit 履歴
rebase_and_merge

この際マージコミットが作成されていないことが確認できます。

特徴

  • マージ元のコミット履歴がそのまま 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オプションを使ってマージを行った後、差分が無いかチェックして見ました。
after_rebase

めちゃくちゃ差分がありました。

一見 develop ブランチと feature ブランチのコミット履歴は同じに見えますが、hash 値が異なっていました。
rebase_compare

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をマージする際には、今設定されているオプションが何なのかを必ず確認してからマージを行うことで予期せぬ事故を防ぐようにしましょう。

Facebook

Follow Us

XConnpassWantedly

KINTOテクノロジーズの最新情報をSNSで発信中!イベント・テックブログ更新情報もお届けします。