web-dev-qa-db-ja.com

'git merge'と 'git rebase'の違いは何ですか?

git mergegit rebaseの違いは何ですか?

449
Daniel Peñalba

もともと3つのコミットがあったとしましょう:Aname __、Bname __、Cname__。

A-B-C

次に開発者DanがコミットDname__を作成し、開発者EdがコミットEname__を作成しました。

A-B-C-D-E

明らかに、この衝突はどういうわけか解決されるべきです。これには、2つの方法があります。

_マージ_

A-B-C-D-E-M

両方のコミットDname__とEname__はまだここにありますが、Mname__とDname__の両方からの変更を継承するマージコミットEname__を作成します。しかし、これは diamond shapeを作成します。これは多くの人にとって非常に分かりにくいと思います。

_ rebase _

A-B-C-D-E-R

実際のファイルの内容は上記のmerge commit Rname__の内容と同じであるcommit Mname__を作成します。しかし、コミットEname__は存在しなかったので削除します(点 - 消えている線で表示)。このため、Ename__は開発者Edに対してローカルである必要があり、他のリポジトリにプッシュされたことはありません。リベースの利点は diamond の形が避けられ、歴史が変わらないことです - ほとんどの開発者はそれが大好きです!

792
mvp

gitについて嫌いな10の事柄 からの抜粋が大好きです(2番目の例では、リベースの簡単な説明を示しています)。

3.くだらないドキュメント

Manページは、万能の「f *** you」です。1。それらはユーザではなくコンピュータ科学者の観点からコマンドを記述します。適例:

git-Push – Update remote refs along with associated objects

これが人間の説明です。

git-Push – Upload changes from your local repository into a remote repository

更新、別の例:(thanks cgd)

git-rebase – Forward-port local commits to the updated upstream head

翻訳:

git-rebase – Sequentially regenerate a series of commits so they can be 
             applied directly to the head node

そして私たちは

git-merge - Join two or more development histories together

これは良い説明です。


1.原本に無修正

138
mvw

個人的には、標準的な図表作成手法はあまり役に立ちません。矢印は常に間違った方向を示しているようです。 (彼らは一般的に各コミットの「親」を指し示していますが、これは時間的に後退することになり、それは奇妙です)。

言葉で説明すると:

  • あなたが自分のブランチを自分のブランチにrebaseしたとき、あなたは自分のブランチをきれいにチェックアウトしたかのように見せ、それからそこから始まるすべての作業を行ったようにGitに伝えます。これにより、誰かがレビューできるような、クリーンで概念的に単純な変更のパッケージが作成されます。あなたは彼らのブランチに新しい変更があるときあなたは再びこのプロセスを繰り返すことができます、そしてあなたはいつも彼らのブランチの「先端に」きれいな変更のセットで終わるでしょう。
  • あなたがそれらのブランチをあなたのブランチにmergeするとき、あなたはこの時点で2つのブランチ履歴を結び付けます。あとでさらに変更を加えてこれをやり直すと、履歴のインターリーブスレッドが作成され始めます。それらの変更の一部、私の変更の一部、それらの変更の一部です。何人かの人々はこれが面倒で望ましくないと感じています。

私が理解できない理由のために、GitのためのGUIツールは、個々のマージを抽象化して、マージ履歴をよりきれいに提示するために多くの努力を払ったことがありません。それで、あなたが「きれいな歴史」を望むならば、あなたはリベースを使う必要があります。

のみリベースを使っている人や決してリベースを使っていない人からのブログ記事を読んだことを思い出します。

私はこれをちょっとした例で説明してみましょう。あなたのプロジェクトの他の人々がユーザーインターフェースに取り組んでいるとしましょう、そしてあなたはドキュメントを書いています。リベースをしないと、あなたの歴史は次のようになります。

Write tutorial
Merge remote-tracking branch 'Origin/master' into fixdocs
Bigger buttons
Drop down list
Extend README
Merge remote-tracking branch 'Origin/master' into fixdocs
Make window larger
Fix a mistake in howto.md

つまり、マージとUIはドキュメントのコミットの途中でコミットします。

コードをマージせずにmasterにリベースした場合は、次のようになります。

Write tutorial
Extend README
Fix a mistake in howto.md
Bigger buttons
Drop down list
Make window larger

すべてのコミットは一番上(最新)にあり、その後に残りのmasterブランチが続きます。

免責事項:私は別の回答で言及されている "Gitについて嫌いな10の記事"の著者です

112
Steve Bennett

受け入れられ、最も支持された答えは素晴らしいですが、言葉だけで違いを説明しようとするとさらに便利です:

マージ

  • 「わかりました。リポジトリの2つの異なる状態を取得しました。それらを一緒にマージしましょう。 2人の親、1人の子供。

リベース

  • 「メインブランチ(その名前が何であれ)の変更を機能ブランチに与えます。実際にメインブランチの現在の状態で機能作業が後で開始されたふりをすることでそうします。」
  • 「それを反映するように変更の履歴を書き直してください。」(通常、バージョン管理はすべてのnot与えられた履歴を改ざんするため、強制的にプッシュする必要があります)
  • 「同様に、私がかき集めた変更が作業とほとんど関係ない場合、実際に履歴を変更することはありません。コミットごとにdiffを見ると(「パッチ」も考えられます)。」

summary:可能な場合、リベースはほぼ常に優れています。メインブランチへの再統合を簡単にします。

なぜなら? featureあなたの機能の仕事は、oneとして提示することができます。親:少なくとも2つ、1つのマージから来ますが、複数のマージがあった場合はさらに多くの可能性があります。 マージとは異なり、複数のリベースは加算されません。(別の大きなプラス)

38
Frank Nocke

Git rebaseはマージに近いです。リベースの違いは次のとおりです。

  • ローカルコミットはブランチから一時的に削除されます。
  • git pullを実行する
  • ローカルコミットをすべてもう一度挿入します。

つまり、すべてのローカルコミットは、すべてのリモートコミットの後に最後に移動されます。マージの競合がある場合は、それも解決する必要があります。

13
Willem Franco

理解しやすいように私の姿を見ることができます。

Rebaseはコミットハッシュを変更するので、衝突を避けたい場合は、そのブランチが完了したときにrebaseを使用してください。

enter image description here

5
Nhan Cao