はじめに
Gitにおける merge
コマンドには、--no-ff
オプションが存在する。このオプションの意味を明確に理解するために、まず fast-forward
マージの挙動から整理し、各オプションの挙動の違いを検証してみた。
fast-forward とは何か
Gitにおける fast-forward
(早送り)マージとは、以下のような状況で発生する。
例として、master
ブランチから develop
ブランチを作成し、develop
側で複数回のコミットを行った後、再び master
にマージするケースを考える。
このとき、master
ブランチ側でその間に新たなコミットが1つも行われていなければ、develop
の最終コミットは master
の最新コミットに直結する形となる。この場合、マージコミットを作成することなく、単に master
のHEADを develop
のHEADに移動するだけで履歴が一本化される。この操作がいわゆる fast-forward
マージである。
一方、master
側でも独立したコミットが存在する場合は、履歴の整合性のためにマージコミットを生成する必要が生じる。これが non fast-forward
なマージである。
--ff
または指定なし(デフォルト)
このオプションは「fast-forward が可能であれば、それを行う」というGitのデフォルト動作である。
実行例
git checkout master
git log
git checkout develop
git log
# c6d96fd ver2
# 511c644 ver1
git checkout master
git merge develop
# Updating 9222684..c6d96fd
# Fast-forward ※デフォルトはfast-forward
master のログ(マージ後)
git log
# c6d96fd ver2
# 511c644 ver1
このように、マージコミットは生成されず、履歴は直線的に連結される。
--no-ff
このオプションは、fast-forward 可能な状況であっても、必ずマージコミットを生成するようにGitに指示する。
実行例
git checkout master
git merge --no-ff develop
# Merge made by the 'recursive' strategy.
master のログ(マージ後)
git log
# ab63095 Merge branch 'develop' ※マージコミットが生成されている
# c6d96fd ver2
# 511c644 ver1
マージ履歴が視覚的に明確となり、将来的な変更の追跡がしやすくなる利点がある。
--ff-only
このオプションは、fast-forward マージ以外を拒否する指定である。マージが fast-forward に該当しない場合、Gitは操作を中止し、エラーを出力する。
実行例(失敗ケース)
git checkout master
git log --oneline
# 86261b5 ver4
# c902dfb ver2
git checkout develop
git log --oneline
# 1a6c07d ver3
# 511c644 ver1
git checkout master
git merge --ff-only develop
# fatal: Not possible to fast-forward, aborting.
このように、--ff-only はfast-forwardでのマージが成立しない状況下では一切マージを許可しない。
まとめ
- Gitの merge コマンドには、--ff(デフォルト)、--no-ff、--ff-only の3つのオプションが存在する。
- --ff は最もシンプルな履歴を維持できるが、マージの痕跡が履歴に残らないため、大規模開発では履歴の可読性に劣る場合がある。
- --no-ff を用いることで、どのタイミングでブランチが統合されたのかが履歴に明確に記録されるため、保守・調査の観点では有効である。
- --ff-only は、履歴の明確化とミスの抑止という観点で安全性が高いが、適用場面は限定される。
以上の特性を踏まえ、プロジェクトの規模や運用ルールに応じて、適切なオプションを選定すべき。