git merge オプションの --ff, --no-ff, --ff-only の違い
Git コマンド git merge で使われる次の 3 つのオプション --ff, --no-ff, --ff-only の違いを図付きで, できるだけわかりやすく解説します.
git merge --ff
の場合
git merge --ff
でブランチ同士をマージさせると, そのマージがファストフォワードとなる場合, マージコミットを作らず, HEAD だけ移動させます.
このオプションは git merge
コマンドのデフォルトになります.
次のようなヒストリで:
A --- B --- C <- feature
/
/
D --- E --- F --- G <- master <- HEAD
次のコマンドを実行すると:
git merge --ff feature
このようなメッセージが表示され:
Updating c7897ae..1115653
Fast-forward
example.txt | 3 +++
1 file changed, 3 insertions(+)
次のようなヒストリになります:
D --- E --- F --- G --- A --- B --- C (HEAD -> master, feature)
この --ff
オプションは git merge
でマージする時のデフォルトなので, merge.ff
の設定をいじられていない場合, git config --global merge.ff true
などと設定する必要はありません.
git merge --no-ff
の場合
git merge --no-ff
でブランチ同士をマージさせると, そのマージがファストフォワードとなる場合であっても, マージコミットを作ります.
次のようなコミットで:
A --- B --- C <- feature
/
/
D --- E --- F --- G <- master <- HEAD
次のコマンドを実行すると:
git merge --no-ff feature
次のようなコミット作成画面が表示され:
Merge branch 'feature'
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
それをコミットすると, 次のようなメッセージが表示され:
Merge made by the 'recursive' strategy.
example.txt | 3 +++
1 file changed, 3 insertions(+)
次のようなヒストリになります:
A --- B --- C <- feature
/ \
/ \
D --- E --- F --- G --------------- H <- master <- HEAD
また --no-ff
オプションは refs/tags/
階層の通常の場所に保存されていない注釈付きタグや署名付きタグをマージする時のデフォルトになるようです.
もしこの --no-ff
オプションを git merge
でマージするときのデフォルトと設定する場合, 一例として git config --global merge.ff false
で設定できます.
git merge --ff-only
の場合
git merge --ff-only
の場合, 現在の HEAD
が最新状態もしくはマージがファストフォワードでない場合, そのマージは拒否され, ノンゼロステータスで終了します.
次のようなヒストリで:
A --- B --- C <- feature
/
/
D --- E --- F --- G <- master <- HEAD
次のコマンドを実行すると:
git merge --ff-only feature
次のようなメッセージが表示され:
fatal: Not possible to fast-forward, aborting.
そのマージはファストフォワードとならないので, 中止されます.
なのでヒストリは変わらず元のままです:
A --- B --- C <- feature
/
/
D --- E --- F --- G <- master <- HEAD
もしこの --ff-only
オプションを git merge
でマージするときのデフォルトと設定する場合, 一例として git config --global merge.ff only
で設定できます.
まとめ
git merge
の --ff
オプションは, git merge
コマンドのデフォルトなので, merge.ff
の値を true
以外に設定していない限り, 付けても意味はありません.
--no-ff
オプションは, 本来ファストフォワードとなるマージを, そのようにせず代わりにマージコミットを作ります. マージされるブランチとマージするブランチの本来のヒストリを残せるので, どのようにコミットが作られてきたかという経緯をそのまま残したい場合に使われます.
--ff-only
オプションは, 現在の HEAD
が最新状態もしくはマージがファストフォワードでない場合, マージを拒否するので, マージコミットを作るようなマージを防ぐことができます. ファストフォワードマージのみ行いたいという場合に使われます.
ファストフォワードマージはそのままにするのか, それともマージコミットを作るのか, もしくはファストフォワードとならないマージは中止させるのかというのはそれぞれの状況によるかと思います.
それら 3 つのオプションの違いを表で表すと次のようになります:
マージが | FF の場合 | FF でない場合 |
---|---|---|
--ff | そのまま | そのまま |
--no-ff | FF にしない | そのまま |
--ff-only | そのまま | 拒否する |
それぞれの状況に合わせて, より良いと思われる方法を選択していただければと思います.
参考資料
関連記事
Git で変更されたファイルを部分的にステージする方法2018.11.01
Git の 'detached HEAD' 状態とその注意点2018.05.31
Git の Reset, Checkout, Revert の違い2018.06.01
git reset --soft, --mixed, --hard の違い2018.05.29
Git の HEAD^ と HEAD~ の違い2018.05.30