図で分かるgit-mergeの--ff, --no-ff, --squashの違い
git-merge の--ff, --no-ff, --squashの違いをまとめてみた。
git helpから引用
まずは、git helpを読みましょう
- git merge --helpから引用(抜粋)
NAME git-merge - Join two or more development histories together SYNOPSIS git merge [-n] [--stat] [--no-commit] [--squash] [-s <strategy>] [-X <strategy-option>] [--[no-]rerere-autoupdate] [-m <msg>] <commit>... git merge <msg> HEAD <commit>... git merge --abort OPTIONS --ff, --no-ff Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer. This is the default behavior of git-merge. With --no-ff Generate a merge commit even if the merge resolved as a fast-forward. --squash, --no-squash Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit or move the HEAD, nor record $GIT_DIR/MERGE_HEAD to cause the next git commit command to create a merge commit. This allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus). With --no-squash perform the merge and commit the result. This option can be used to override --squash. --ff-only Refuse to merge and exit with a non-zero status unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward.
fast-forward(ファーストフォワード)って何?
マージの説明の前に、まずはGitのfast-forwardについて。
- 入門Git p.230 から引用
2つのコミットAとBとがあるときに、コミットAにいたる歴史がコミットBにいたる歴 史にすべて含まれている場合、2つのコミットはファーストフォワードの関係にある、と か、コミットAはコミットBにファーストフォワードする、といいます。
少し分かりにくいので、絵にしてみた。
各マージの解説
本題の各マージについて。
1. --ff
デフォルトの設定です。
もしマージ対象のブランチとfast-forwardの関係にある場合、マージコミットは作られず、ブランチの参照先の更新だけを行います。
(fast-forwardの関係でない場合、マージコミットが作られます)
$ git merge topic
各オプションの使い分けの前に
まずはプロジェクトのリポジトリの運用について決める必要があります。
- コミットの粒度
- rebase は必須であるか?
- トピックブランチのマージの時にマージコミットを作るか?
などを決め、プロジェクトのポリシーに沿ったコミットログを作るのが良いと思います。
オプションの使い分け
私はこうやって使っている・・・という例を紹介します。
他の便利な例や突っ込みがあれば、コメントで。
--ff
ログが一本になり、トピックブランチがあったという情報がなくなる。
トピックブランチの存在をログに残す必要がなく、そのままマージしてもコミット粒度が問題無い場合に使う。
--no-ff
--ffと異なり、トピックブランチがあったという情報が残る。
基本的には「A successful Git branching model」を参考に--no-ffを使うのが良い。
--squash
トピックブランチがあった情報も、コミットログも全て残らない。
トピックブランチで行った作業が少なく、1コミットにまとめてしまっても問題ない場合に使う。
git mergeで常に--no-ffにする
ついでに、常に--no-ffにする設定を紹介します。
この方法は2つあります。
方法1. エイリアスを使う
エイリアスを設定し、--no-ffのマージを行う時はgit nffmerge を使うようにする。
$ git config --global alias.nffmerge "merge --no-ff"
方法2. mergeoptions
マージオプションを設定すると、指定したブランチのマージでは設定値がデフォルトとして使用されます。
git config branch.<name>.mergeoptions "--no-ff"
ただし、この設定を行うとgit pull の実行時にもマージコミットが出来てしまい、マージコミットが大量に出来てしまうため、リモートの変更を取得したい時はgit pull --rebase を使う必要があります。
特定のブランチで必ずpull --rebase を有効にする
次のコマンドで設定できる。
$ git config branch.<name>.rebase true
全てのブランチでpull --rebase を有効にする
もし全てのブランチで設定したい場合、次のコマンドで設定する。
$ git config branch.autosetuprebase always