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


499

違いは何だgit mergeとはgit rebase


14
私の回答が削除されたため、このリンクにアクセスしてこの質問の正しい回答を入手してください:git-scm.com/book/en/Git-Branching-Rebasing#The-Basic-Rebase
HiB

6
ちなみにこのサイトを追加します。再生することでgit learnについて知っておく必要があるすべて:pcottle.github.io/learnGitBranching
Rollyng

最初にこれを読んでください:git-scm.com/book/en/v2/…次に、git-scm.com / book / en / v2 / Git-Branching-Rebasing本当に理解できます。
リベル14年

回答:


867

もともと3つのコミットがあったとしABC

ABC

次に、開発者Danがcommitを作成しD、開発者Edがcommitを作成しましたE

ABCDE

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

MERGE

ABCDEM

両方のコミットDEまだここにありますがM、両方Dとから変更を継承するマージコミットを作成しEます。しかし、これはダイヤモンド形状を作成し、多くの人々は非常に混乱します。

リベース

ABCDER

commitを作成しますR。実際のファイルの内容は、M上記のマージコミットの内容と同じです。しかし、コミットEは存在しなかったように(ドットで示されている-消失線)、commit は取り除かれます。この抹消のためにE開発者Edのローカルであり、他のリポジトリにプッシュされてはなりません。リベースの利点は、ダイヤモンドの形状が回避され、歴史が良い直線に保たれることです-ほとんどの開発者はそれを愛しています!


53
素敵なイラスト。ただし、リベースが処理される前向きなトーンには完全に同意しません。マージとリベースの両方で競合が発生し、手動で解決する必要があります。そして、いつものように、プログラマーが関与するとき、エラー、つまりバグの無視できない可能性があります。マージエラーが発生した場合、チームまたはコミュニティ全体がマージを確認し、そこにバグが導入されたかどうかを確認できます。リベースの履歴は1つの開発者のリポジトリにとどまり、reflogの有効期間は限られています。見栄えはよくなるかもしれませんが、何が問題だったかを他の人が簡単に知ることはできません。
Uwe Geuder 2013

>「しかし、これはダイヤモンド形状を作成しますが、多くの人々は非常に混乱します。」えっと...詳しく説明してもらえますか?
Greg Maletic 2014

@GregMaletic:ダイヤモンドの形状は非線形の履歴です。私はあなたのことは知りませんが、一般的に非線形のものは好きではありません。そうは言っても、本当に好きな人はダイヤモンドとマージを使用することができます-誰もあなたを強制していません。
mvp 14

1
この回答は非常に役立ちますが、ローカルで再現するために実際のgitコマンドを単純なfoo.txtファイルとともに追加した方がよいでしょう。最後のユーザーが言ったように、誰がリベースを行っているかは明らかではありません。
Vortex

1
@pferrel:l正しく理解したとは思わない。git mergeコミットをインターリーブしません(ただし、を見ると表示される場合がありますgit log)。代わりに、git mergeDanとEdの両方の開発履歴を一度にそれぞれの視点から見たようにそのまま保持します。git rebaseダンが最初に取り組んだように見え、エドは彼に続いた。どちらの場合も(マージとリベース)、実際の結果のファイルツリーは完全に同一です。
mvp

158

私はgitについて嫌いな10の事柄からのこの抜粋を本当に気に入っています(2番目の例でリベースについて簡単に説明しています):

3.不機嫌なドキュメント

manページは、万能の「f ***あなた」1です。ユーザーではなくコンピューター科学者の観点からコマンドを説明します。適例:

git-push – Update remote refs along with associated objects

これが人間の説明です:

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

更新、別の例:(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.オリジナルで無修正


問題は言語ではなく、ユーザーがコンピューターサイエンティストであるかどうかではありません。別の方法でそれを言い換えると、目的(つまり、何が起こるか)を明確にするのに役立ちますが、手段(それがどのように起こるか)を説明することはできません。Gitは、目的を理解するために手段を理解する必要があります。Gitを非常に困難にする手段を正確に理解しています。ツールとして、タスクで必要な労力を単純化または削減するために使用されるものとして、Gitはひどく失敗します。悲しいことに、あまりにも多くの開発者がそれを実現できません。
ATL_DEV

128

個人的には、標準の作図手法があまり役に立たないと思います-矢印は常に私にとって間違った方向を指しているようです。(それらは一般的に、各コミットの「親」を指しており、最終的には逆方向になり、奇妙です)。

言葉で説明すると:

  • ブランチをそのブランチにリベースするときは、ブランチをきれいにチェックアウトし、そこからすべての作業を行ったかのように見えるようにGitに指示します。これにより、誰かが確認できる変更のクリーンで概念的に単純なパッケージが作成されます。ブランチに新しい変更がある場合は、このプロセスを繰り返すことができます。ブランチの「先端」にある変更のクリーンなセットが常に得られます。
  • ブランチにブランチをマージすると、この時点で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コミットです。

コードをマージする代わりにマスターにリベースすると、次のようになります。

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

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

免責事項:私は別の回答で言及されている「Gitについて嫌いな10のこと」の投稿の著者です


42

受け入れられ、最も賛成された答えは素晴らしいですが、言葉だけで違いを説明しようとするとさらに役に立ちます。

マージ

  • 「さて、私たちはリポジトリの2つの異なる開発状態を得ました。それらをマージしましょう。両親2人、子供1人。」

リベース

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

要約:可能な場合、リベースの方がほとんど常に優れています。メインブランチへの再統合を容易にします。

なぜなら?feature機能の作業は、メインブランチに関して1つの大きな「パッチファイル」(別名diff)として提示できます。複数の親を「説明」する必要はありません。少なくとも2つ、1つのマージからのものですが、存在する場合はさらに多くの可能性があります。いくつかのマージでした。マージとは異なり、複数のリベースは加算されません。(別の大きなプラス)


18

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

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

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


7

簡単に理解するために私の図を見ることができます。

Rebaseはコミットハッシュを変更するため、多くの競合を回避したい場合は、そのブランチが完了または安定したときにrebaseを使用します。

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


0

私はgit rebase vs mergeに関する非常に興味深い記事を見つけました、ここで共有することを考えました

  • 履歴を完全に同じように表示したい場合は、マージを使用する必要があります。Mergeは履歴を保持しますが、リベースはそれを書き換えます。
  • マージすると、履歴に新しいコミットが追加されます
  • リベースは複雑な履歴を合理化する方が良いです。インタラクティブなリベースによりコミット履歴を変更できます。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.