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

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

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

- コミットAの後にmainブランチ, developブランチに派生しています。
- mainブランチに対してdevelopブランチの内容をマージしていきます。
・git checkout main
・git merge 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」の履歴はすっきり見えます(線形で余計なコミットがない)。
→ すっきり見れる分、「コミットB」や「コミットD」のことを考慮したマージのコメントを書きましょう。

結果的に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」の結果とはどう頑張っても一緒にはなりませんでした。
(参考) Revertは?
GitHub.comのPull Requestを見る限り、全てのパターンでRevert可能でした。

※ただ、今回は複雑な衝突は考慮していないため、抜け漏れがあったらごめんなさい。
まとめ
本記事ではGitHub.com上の3種類のマージについて、イメージ図とコマンド例と共に、概要レベルで説明してみました。
- Create a merge commit
→ デフォルトでまぁまぁわかりやすい。 - Squash and merge
→ マージ元のコミット履歴をまとめたい場合に使える。 - Rebase and merge
→ マージ先のブランチ履歴をまっすぐ(線形)にしたい場合に使える。チェリーピック相当。
GitHub.com上での操作であればマージの取り消しである「Revert」も簡単に出来そうです。
→ OSS開発も盛んで色々なコントリビューターがいるGitHubには重要な要素なんだと考えます。
何か発見したらフィードバックしていきたいと思います。

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