Gitでコードを管理していると、異なるブランチを統合する「マージ」が必要になります。その際、git merge
コマンドを使用しますが、git merge
にはいくつかのオプションがあり、オプションによって挙動が変わります。
このブログでは、以下の4つの主要オプションについて、「使い方」や「メリット/デメリット」をわかりやすく解説します。
--ff
--ff-only
--no-ff
--squash
git mergeのオプションの種類
git merge
には以下に示すオプションがあり、それぞれが異なる動作をします。
--ff
--ff-only
--no-ff
--squash
これらのオプションはどのように違うのでしょうか?
これから各オプションについて、「特徴」や「使い方」、「メリット/デメリット」を解説します。
--ff(デフォルト動作)
--ff
は「Fast-Forward」の略で、デフォルトで適用されるオプションです。
マージ先のブランチ(上図の例だとdevelop
ブランチ)が変更されておらず、単純に先に進めるだけでマージが可能な場合、Fast-Forwardマージ(早送りマージ)を行います。マージ先のブランチが変更されている場合には、後ほど説明する3wayマージ(Non-Fast-Forwardマージ)が行われます。
例えば、feature
ブランチの作業をdevelop
ブランチに統合したい場合、以下を実行します。
git checkout develop
git merge --ff feature # git merge feature と同じ
上図に示しているのは、feature
ブランチに行った変更(コミットAとコミットB)をdevelop
ブランチにマージした場合の図です。左側の図の場合、develop
ブランチは変更されていないので、git merge --ff feature
を実行すると、Fast-Forwardマージ(早送りマージ)が行われます。一方、右側の図の場合、develop
ブランチに変更(コミットX)が入っているので、git merge --ff feature
を実行すると、3wayマージ(Non-Fast-Forwardマージ)が行われます。
特徴
- 新しいマージコミットを作成せず、ブランチ履歴をそのまま進める。
- マージ先のブランチが変更されている場合には、この後に説明する3wayマージ(Non-Fast-Forwardマージ)が行われる。
メリット
- 履歴がクリーンで見やすい。
- 不要なマージコミットを避けられる。
デメリット
- ブランチ統合のタイミングが履歴から分かりにくい。
--ff-only
--ff-only
は、Fast-Forwardマージ(早送りマージ)のみを許可するオプションです。Fast-Forwardマージが可能でない場合、マージは失敗します。
例えば、feature
ブランチの作業をdevelop
ブランチに統合したい場合、以下を実行します。
git checkout develop
git merge --ff-only feature
上図に示しているのは、feature
ブランチに行った変更(コミットAとコミットB)をdevelop
ブランチにマージした場合の図です。左側の図の場合、develop
ブランチは変更されていないので、git merge --ff-only feature
を実行すると、Fast-Forwardマージ(早送りマージ)が行われます。一方、右側の図の場合、develop
ブランチに変更(コミットX)が入っているので、git merge --ff-only feature
を実行してもマージをすることができません。
特徴
- Fast-Forwardが可能な場合のみマージが実行される。
- 意図しない3wayマージを防げる。
- マージ先のブランチが変更されている場合には、マージをすることができません。
メリット
--ff
で説明した内容と同じなので省略
デメリット
--ff
で説明した内容と同じなので省略
--no-ff
--no-ff
は、Fast-Forwardが可能な場合でも、新しいマージコミットを必ず作成する3wayマージ(Non-Fast-Forwardマージ)を行うオプションです。
例えば、feature
ブランチの作業をdevelop
ブランチに統合したい場合、以下を実行します。
git checkout develop
git merge --no-ff feature
上図に示しているのは、feature
ブランチに行った変更(コミットAとコミットB)をdevelop
ブランチにマージした場合の図です。develop
ブランチに変更有無にかかわらず、git merge --no-ff feature
を実行すると、必ず3wayマージ(Non-Fast-Forwardマージ)が行われます。
特徴
- 必ず新しいマージコミットを作成する。
メリット
- 履歴にブランチ統合のタイミングが明確に記録される。
- 大規模プロジェクトや複雑なブランチ管理に適している。
デメリット
- 履歴が複雑になり、読みづらくなる場合がある。
--squash
--squash
は、マージ元ブランチの全てのコミットを1つにまとめて、1回のコミットとして適用するオプションです。
例えば、feature
ブランチの作業をdevelop
ブランチに統合したい場合、以下を実行します。
git checkout develop
git merge --squash feature
git commit -m "Squashed feature branch" # マージコミットが作られないため、--squashの場合は自分でコミットする必要があります。
上図に示しているのは、feature
ブランチに行った変更(コミットAとコミットB)をdevelop
ブランチにマージした場合の図です。develop
ブランチに変更有無にかかわらず、git merge --squash feature
を実行すると、feature
ブランチに行った変更(コミットAとコミットB)を1つにまとめられます。ただし、マージコミットは作成されないので、自分でコミットする必要があります。
特徴
- マージ元のブランチの履歴は無視され、1つのコミットにまとめられます。
- マージコミットは作成されない。
メリット
- 履歴が簡潔になり、特定の機能を1つのコミットにまとめられる。
- コミットが1つにまとめられるため、「新機能の変更はこのコミット」というのがすぐに分かる。
- レビューやリリース時に便利。
- 1つのコミットにまとまっていることで、レビュー時に変更点を簡単に確認でき、リリースノートも明確になるため。
デメリット
- 元のコミット履歴が失われるため、詳細な変更履歴を追いづらい。
- チームでの作業時に注意が必要。
- チームメンバーが「feature ブランチで何をしたか」を理解しようとする場合、詳細な履歴がないため、コミット1つでは意図や経緯を把握できないことがある。
git mergeの各オプションの使い分け
git merge
のどのオプションを使用するかは、以下のように使い分けるとよいと思います。
- 履歴をシンプルにしたい
--ff
または--ff-only
を使う- 余計なマージコミットを作らず、履歴がクリーンになるため
- 履歴を明確に残したい
--no-ff
を使う- ブランチの統合タイミングが履歴から分かるため
- 変更を1つにまとめたい
--squash
を使う- 複数のコミットを1つにまとめ、リリースやレビューが簡単になるため
本記事のまとめ
この記事では『git mergeコマンドのオプション』について、以下の内容を説明しました。
--ff
--ff-only
--no-ff
--squash
git merge
の各オプションの使い分け
お読み頂きありがとうございました。