`git merge`と` git merge --no-ff`の違いは何ですか?


977

を使用gitk logすると、2つの違いを見つけることができませんでした。(gitコマンドまたは何らかのツールを使用して)どうすれば違いを確認できますか?




回答:


1080

この--no-ffフラグは、git merge現在のものHEADがマージしようとしているコミットの祖先であることを検出した場合、「早送り」を実行しないようにします。早送りとは、マージコミットを作成する代わりに、gitがブランチポインターを移動して、受信コミットを指すようにする場合です。これは通常git pull、ローカルで変更を加えずにを実行すると発生します。

ただし、通常、特定のブランチトポロジを維持する必要があるため(たとえば、トピックブランチにマージしていて、履歴を読み取るときにそのように見えるようにする必要があるため)、この動作の発生を防止したい場合があります。そのためには、あなたが渡すことができ--no-ffフラグとgit mergeなり、常に早送りの代わりにマージを構築します。

同様に、明示的に早送りするためにa git pullまたはuse を実行し、git merge早送りできない場合はベイルアウトする場合は、--ff-onlyフラグを使用できます。このようにして、定期的に何git pull --ff-onlyも考えずに何かを行うことができ、エラーが発生した場合は、戻ってマージするかリベースするかを決定できます。


87
より直接的OPの質問に答えるために:彼らは常に異なっていないが、彼らがしている場合、それはから明らかですgitkgit log --graph非早送り1がした一方で、マージを作成していない早送りマージコミットこと。
Cascabel 2012年

11
ffを回避する理由を拡張するといいでしょう。著者が「特定のブランチトポロジ」と述べたのは、-no-ffの場合、追加のマージコミットがマージのマーカーとして機能することを意味します。長所は、作者と合併の名前を明示的に示すマージマーカーです。短所は、一連の収束する線路のように見える非線形の履歴です。可能心理:貢献者は、より長いレビュープロセスへの関心を失うされているが、マージの副作用blog.spreedly.com/2014/06/24/...
ヴラド

6
--no-ff機能から開発へ、または開発からマスターへの移行は、プルリクエストのマージに似ていると言えるでしょうか。
merlinpatt

9
@merlinpattもちろん。GitHubでプルリクエストをマージすると、と同等になり--no-ffます。
リリーバラード

1
これは良い説明です。
確かに

1037

この質問に対する図解

以下は、使用の明確な説明と図解のあるサイトgit merge --no-ffです。

git merge --no-ffとgit mergeの違い

これを見るまでは、gitで完全に迷っていました。を使用--no-ffすると、誰かが履歴を確認して、作業のためチェックアウトたブランチを明確に見ることができます。(このリンクはgithubの「ネットワーク」視覚化ツールを指します)そして、ここにイラスト付きの別の素晴らしいリファレンスがあります。このリファレンスは、最初のリファレンスをうまく補完し、gitにあまり詳しくない人に重点を置いています。


私のような初心者のための基本情報

あなたがGit-guruではなく私のような場合、ここでの私の回答は、ローカルファイルシステムからファイルを削除せずにgitの追跡からファイルを削除する処理について説明しています。もう1つの新しい状況は、現在のコードを取得することです。


ワークフローの例

パッケージをWebサイトに更新し、ワークフローを確認するためにノートに戻る必要がありました。この回答に例を追加すると便利だと思いました。

gitコマンドの私のワークフロー:

git checkout -b contact-form
(do your work on "contact-form")
git status
git commit -am  "updated form in contact module"
git checkout master
git merge --no-ff contact-form
git branch -d contact-form
git push origin master

以下:説明を含む実際の使用法。
注:以下の出力は省略されています。gitはかなり冗長です。

$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   ecc/Desktop.php
#       modified:   ecc/Mobile.php
#       deleted:    ecc/ecc-config.php
#       modified:   ecc/readme.txt
#       modified:   ecc/test.php
#       deleted:    passthru-adapter.igs
#       deleted:    shop/mickey/index.php
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       ecc/upgrade.php
#       ecc/webgility-config.php
#       ecc/webgility-config.php.bak
#       ecc/webgility-magento.php

上記の3つのことに注意してください
。1)出力に、新しいファイルの追加を含む、ECCパッケージのアップグレードによる変更が表示されます。
2)また/ecc、この変更とは別に、私が削除した2つのファイル(フォルダーではない)があることに注意してください。これらのファイルの削除をと混同する代わりに、後でecc別のcleanupブランチを作成して、それらのファイルの削除を反映します。
3)ワークフローに従わなかった!eccを再度動作させるときに、gitのことを忘れていました。

以下:git commit -am "updated ecc package"通常のようにすべてを含めるのではなく、/eccフォルダにファイルを追加するだけで済みます。これらの削除されたファイルは特にの一部ではありませんでしたgit addが、すでにgitで追跡されているため、このブランチのコミットから削除する必要があります。

$ git checkout -b ecc
$ git add ecc/*
$ git reset HEAD passthru-adapter.igs
$ git reset HEAD shop/mickey/index.php
Unstaged changes after reset:
M       passthru-adapter.igs
M       shop/mickey/index.php

$ git commit -m "Webgility ecc desktop connector files; integrates with Quickbooks"

$ git checkout master
D       passthru-adapter.igs
D       shop/mickey/index.php
Switched to branch 'master'
$ git merge --no-ff ecc
$ git branch -d ecc
Deleted branch ecc (was 98269a2).
$ git push origin master
Counting objects: 22, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (14/14), 59.00 KiB, done.
Total 14 (delta 10), reused 0 (delta 0)
To git@github.com:me/mywebsite.git
   8a0d9ec..333eff5  master -> master



上記を自動化するためのスクリプト

このプロセスを1日に10回以上使用して、コマンドを実行するバッチスクリプトを作成することにしたのでgit_update.sh <branch> <"commit message">、上記の手順を実行するためのほぼ適切なスクリプトを作成しました。これがそのスクリプトのGistソースです。

git commit -am経由で作成された「変更済み」リストからファイルを選択しgit statusて、このスクリプトに貼り付ける代わりに。これは、私が何十もの編集を行ったが、変更をグループ化するのに役立つようにさまざまなブランチ名が必要だったために起こりました。


11
--no-ffオプションとマージした後でも、ブランチを安全に削除できますか?
アンディフレミング

17
@DesignerGuyはい、古いブランチを安全に削除できます。ブランチesは、特定のコミットへの単なるポインタと考えてください。
Zyphrax 2014

2
リンクされたページからこのテキストが役に立ったとわかりました:--no-ffなし「Gitの履歴から、どのコミットオブジェクトが機能を実装しているかを確認することは不可能です。すべてのログメッセージを手動で読み取る必要があります。」
Lorne Laliberte 2014

1つの画像は常に1000語よりも優れています。
18

1
2番目の画像では、グラフィックは機能ブランチを示していませんが、なぜですか?それはまだ存在しませんか?
ADJenks

269

マージ戦略

明示的なマージ:新しいマージコミットを作成します。(これは、を使用し--no-ffた場合に得られるものです。)

ここに画像の説明を入力してください

Fast Forward Merge:新しいコミットを作成することなく、すばやく転送します。

ここに画像の説明を入力してください

リベース:新しいベースレベルを確立します。

ここに画像の説明を入力してください

スカッシュ:(何か)を力で押しつぶすか押して、平らになるようにします。

ここに画像の説明を入力してください


11
興味深いグラフィックですが、実際には--no-ffのケースを示していないため、ここの質問には完全に答えていません
Vib

22
最初の「明示的なマージ」は、ここでは「マージ」と題されており、ff以外のマージです。
bkribbs 2018

3
そのグラフィックは本当に私を助けてくれました
exexzian

2
言うごとの質問には答えませんが、このグラフィックはすばらしいです。
SovietFrontier

3
では、リベースと早送りマージの違いは何でしょうか?
ThanosFisherman

217

この--no-ffオプションにより、早送りマージが発生せず、新しいコミットオブジェクトが常に作成されます。gitに機能ブランチの履歴を保持させたい場合、これは望ましいことです。             git merge --no-ff vs git merge 上の画像では、左側が使用後のgit履歴の例でgit merge --no-ff、右側がgit mergeffマージが可能な場所での使用例です。

編集:このイメージの以前のバージョンは、マージコミットの単一の親のみを示していました。マージコミットには、 gitが「機能ブランチ」と元のブランチの履歴を維持するために使用する複数の親コミットがあります。複数の親リンクは緑色で強調表示されます。


3
緑の矢印は黒い矢印に対して何を示していますか?
rtconner 2015年

11
緑の矢印は、コミットと親の間のリンクを示し、コミットには複数の親があります。通常のコミット(黒)の親は1つだけです。
Daniel Smith

9
@DanielSmithこのエレガントなグラフをどのように描くのですか?
chancyWu 2016年

4
@chancyWu with Adob​​e Illustrator
Daniel Smith

私の会社では、すべてのプルリクエストが--no-ffオプションとマージされているようです。そのような状況下で、プルリクエストを作成する前にリベースすることはまだ意味がありますか?
Nickpick

37

これは古い質問であり、他の投稿で少し微妙に言及されていますが、このクリックを私にさせた説明は、高速ないマージでは別のコミットが必要になるということです。


上記の私の回答でワークフローを確認していただけますか?これは、私が今持っているものを超えて追加のコミットが必要であることを意味しますか?ありがとう。
クリスK

3
@ChrisKのgit merge --no-ff ecc場合、git logforブランチマスターで追加のマージコミットを行うだけです。マスターがコミットの直接の祖先を指している場合、技術的には必要ありませんeccがオンになっていますが、--no-ffオプションを指定することにより、そのマージコミットの作成を強制します。:それはタイトルがありますMerge branch 'ecc'
はAnkur Agarwalさん

素晴らしい要約!:)
エデュアルド

4

--no-ffフラグを使用すると、早送りでマージを実行できたとしても、マージは常に新しいコミットオブジェクトを作成します。これにより、機能ブランチの履歴の存在に関する情報が失われるのを防ぎ、機能を一緒に追加したすべてのコミットをグループ化します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.