web-dev-qa-db-ja.com

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

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

781
user1162226

現在のHEADがマージしようとしているコミットの先祖であることが検出された場合、--no-ffフラグはgit mergeが "早送り"を実行するのを防ぎます。早送りは、マージコミットを構築する代わりに、gitがブランチポインタを入ってくるコミットを指すように移動するだけです。これは一般的にローカルな変更なしでgit pullをするときに起こります。

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

同様に、明示的に早送りするためにgit pullを実行するかgit mergeを使用したい場合、および早送りできない場合は回避する場合は、--ff-onlyフラグを使用できます。こうすることで、考えなくてもgit pull --ff-onlyのようなことを定期的に行うことができます。それからエラーが発生した場合は、戻ってマージするかリベースするかを決めることができます。

878
Lily Ballard

この質問に対するグラフィックの答え

これはサイトです はっきりした説明と使い方の図解を添えて git merge --no-ff

difference between git merge --no-ff and git merge

私がこれを見るまで、私はgitで完全に迷っていました。を使う --no-ff 誰かが履歴を見直すことを明確にすることを許可します あなたがチェックアウトしたブランチを見る に取り組むこと。 (そのリンクはgithubの「ネットワーク」視覚化ツールを指しています)そしてここに もう一つの素晴らしい参考文献 イラスト付きです。このリファレンスは、gitについてあまり知らない人々に焦点を当てることで、最初のものをうまく補完します。


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

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


ワークフロー例

私は自分のウェブサイトにパッケージを更新し、自分のワークフローを見るために自分のノートに戻る必要がありました。この答えに例を追加すると便利だと思いました。

私の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)2つのファイルがあることにも注意してください(/eccフォルダーにはありません)私はこの変更とは無関係に削除しました。これらのファイルの削除を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 [email protected]:me/mywebsite.git
   8a0d9ec..333eff5  master -> master



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

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

git commit -amの代わりに、私はgit statusによって作成された "変更された"リストからファイルを選択し、そしてそれをこのスクリプトに貼り付けています。これは、私が何十もの編集を行ったが、変更をグループ化するのを助けるために様々なブランチ名を欲したために起こりました。

862
Chris K

--no-ffオプションは早送りマージが起こらないことを保証します、そして 新しいコミットオブジェクトは常に作成されます 。 gitに機能ブランチの履歴を管理させたい場合、これは望ましいことです。git merge --no-ff vs git merge 上の図では、左側がgit merge --no-ffを使用した後のgit履歴の例であり、右側がffマージが可能な場所でのgit mergeの使用例です。

_ edit _ :このイメージの以前のバージョンでは、マージコミットの親は1人だけでした。 マージコミットには複数の親コミットがあります "gitは"機能ブランチ "と元のブランチの履歴を管理するために使用します。複数の親リンクは緑色で強調表示されています。

183
Daniel Smith

マージ戦略

  • 明示的な、早送りではないマージ
  • リベースまたは早送りマージによる暗黙的
  • マージ時にスカッシュ

enter image description here

enter image description here
rebase :新しい基本レベルを確立

enter image description here
早送り: 早送り

enter image description here スカッシュ: 平らになるように力で(何か)押しつぶすか絞る

77
Premraj

これは古い質問です、そしてこれは他の投稿でやや微妙に言及されています、しかし私にとってこのクリックをした説明は 早送りでないマージは別のコミットを必要とするでしょう です。

34
Parris Varney

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

1
jsina