GitHubでPull Requestをマージする際は、3種類のマージを選択可能です。
- Create a merge commit (default)
- Squash and merge
- Rebase and merge

これらは公式サイトに説明が掲載されていますが、自分なりに理解を深めるため、絵を書いたり、Gitコマンドでの再現方法に触れました。

以下、目次となります。
前提
マージ前は、次のようなブランチを想定しています。

- コミットAの後にブランチ内容が派生しています。
- mainブランチ、developブランチでは異なるファイルを変更しています。
→ 説明簡略化のためマージは自動的に解消するようにしている。 - mainブランチに対してdevelopブランチの内容をマージしたいです。

Create a merge commit
直訳で「1個のマージコミットを作る」です。

- マージ先である「main」には「develop」の各コミットが取り込まれます。
- マージ先である「main」にはマージしたことを示すマージコミット(E)が作られます。
通常のgitコマンドでは次の通りです。
git checkout main
git merge --no-ff develop
※git checkout(ブランチ移動)は最近はgit switchでもOKのようです。
Squash and merge
直訳で「押しつぶしてマージ」です。

- マージ先である「main」には「develop」のコミット「B」「D」をsquashした(押しつぶしてまとめた)コミット「E」が追加されます。
- 「main」の履歴はすっきり見えます。
→ ただし新しく追加されたコミット「E」でしっかりコメントを書かないと何がマージされたのか辿りにくくなるかもしれませんね。

結果的に1個の機能をマージする等であれば、1個のコミットポイントですっきり見れますね。
通常のgitコマンドでは次の通りです。
git checkout main
git merge --squash develop
git commit -m "comment"
※git merge –squash <ブランチ名>の段階では、squashされた内容が入ってくるだけでコミットはされません。内容を確認した上で自分で明示的にコミットします。
Rebase and merge
直訳で「土台にしてマージ」です(適当)。

- マージ先である「main」という土台を維持して、後ろに「develop」のコミット「B」「D」が新しいコミット「B’」「D’」として追加されます。
- 追加されたコミット「B’」「D’」のコミットハッシュは新しいものとなります。
公式サイトにも書かれていますが、一般的なrebaseとは異なるようです。強制プッシュ(-f)といった過去のコミット履歴を改変しているわけではありません。だからチーム開発におけるカオスなことにはならないと思います。
通常のgitコマンドではcherry-pickを使えば良いと思われます(現状の理解)。
git checkout main
git cherry-pick コミットBのハッシュ
git cherry-pick コミットDのハッシュ
今回の前提条件だとcherry-pickで該当のコミットを引っ張ってきているだけです。
※rebaseコマンドを色々と組み合わせたのですが、github.comの「rebase and merge」の結果とはどう頑張っても一緒にはなりませんでした。
あと、本ケースはmainブランチとConfliectがある場合は選択出来ません。
→ 一旦developブランチでConflict解消しないと、そもそもマージ出来ませんからね。。
(参考) Revertは?
GitHub.comのPull Requestを見る限り、全てのパターンでRevert可能でした。

※ただ、今回は複雑な衝突は考慮していないため、抜け漏れの可能性は否定できません。
まとめ
本記事ではGitHub.com上の3種類のマージ(Create a merge commit、Squash and merge、Rebase and merge)について概要レベルで説明しました。
- マージのイメージ図
- コマンド例
個人的にはなんとなくイメージ出来たかと思います。また、GitHub.com上での操作であればマージの取り消しである「Revert」も簡単に出来そうです(といっても実際にはためらいますが)。
また、何か発見したらフィードバックしていきたいと思います。

最後までお読みいただきありがとうございました。
コメント