web-dev-qa-db-ja.com

なぜそんなに多くのプロジェクトが「git merge」より「git rebase」を好むのですか?

DVCSを使用する利点の1つは、edit-commit-mergeワークフロー(edit-merge-commitよりも) CVCSによって強制されることが多い)。マージとは無関係にリポジトリに一意の変更を記録できるようにすることで、 [〜#〜] dag [〜#〜] がプロジェクトの真の家系を正確に反映します。

なぜ 非常に多くのWebサイト は、「マージコミットを回避する」ことについて話しているのですか?コミット前のマージまたはマージ後のリベースは、リグレッションの分離、過去の変更の復帰などを難しくしませんか?

明確化のポイント:マージを作成するためのDVCSのデフォルトの動作コミット。なぜそんなに多くの場所が、これらのマージコミットを隠す線形の開発履歴を見たいという欲求について話しているのですか?

71
Jace Browning

ログの見栄えがよくなるので、マージコミットは避けたいものです。真剣に。育った集中管理されたログのように見え、ローカルでは単一のブランチですべての開発を行うことができます。これらの美学以外に利点はありません。また、「中央」サーバーを経由せずに同僚から直接プルするのが競合しやすいなど、言及したものに加えていくつかの欠点があります。

66
Karl Bielefeldt

2つの言葉で:git bisect

線形履歴により、バグの実際の原因を特定できます。


def bar(arg=None):
    pass

def foo():
    bar()

ブランチ1は、argが無効になるようにリファクタリングを行います。

def bar():
    pass

def foo():
    bar()

ブランチ2には、argを使用する必要がある新機能があります。

def bar(arg=None):
    pass

def foo():
    bar(arg=1)

マージの競合はありませんが、バグが導入されています。幸いにも、この特定のものはコンパイルのステップに巻き込まれますが、私たちはいつもそれほど幸運であるとは限りません。バグがコンパイルエラーではなく予期しない動作として現れた場合、1〜2週間、バグが見つからない可能性があります。その時点で、git bisectが救い出します。

やばい。これはそれが見るものです:

(master: green)
|             \_________________________
|                \                      \
(master: green)  (branch 1: green)     (branch 2: green)
|                 |                     |
|                 |                     |
(master/merge commit: green)            |
|                         ______________/
|                        /
(master/merge commit: red)
|
...days pass...
|
(master: red)

したがって、git bisectを送信してビルドを破壊したコミットを見つけると、マージコミットが特定されます。まあ、それは少しは役に立ちますが、それは本質的に単一のコミットではなくコミットのパッケージを指しています。すべての祖先は緑色です。一方、リベースでは、線形の履歴が得られます。

(master: green)
|
(master: green)
|
(all branch 1 commits: green)
|
(some branch 2 commits: green)
|
(branch 2 commit: red)
|
(remaining branch 2 commits: red)
|
...days pass...
|
(master: still red)

ここで、git bisectは、ビルドを中断した正確な機能コミットを示します。理想的には、コミットメッセージは、別のリファクタリングを実行してすぐにバグを修正するのに十分な意図があったことを説明します。

効果は、メンテナーがすべてのコードを記述しなかった大規模なプロジェクトでのみ悪化するため、特定のコミットが行われた理由/各ブランチの目的を必ずしも覚えていない。そのため、正確なコミットを特定する(そして、その周りのコミットを調べることができる)と、非常に役立ちます。


そうは言っても、私は(現在のところ)まだマージを好みます。リリースブランチをリベースすると、git bisectで使用するための線形履歴が得られますが、日々の作業の真の履歴は保持されます。

48
Izkata

要するに、マージはしばしば何かがうまくいかない別の場所であり、人々がもう一度それに対処することを非常に恐れるようにするために一度だけ失敗する必要があるからです(あなたがそうするなら、2回噛まれたら)。

それでは、新しいアカウント管理画面に取り組んでいて、新しいアカウントのワークフローでバグが発見されたとしましょう。 OK、私たちは2つの別々の道をたどります-あなたはアカウント管理を終了し、私は新しいアカウントのバグを修正します。私たちは両方ともアカウントを扱っているので、非常によく似たコードで作業してきました。おそらく、同じコードを調整する必要さえありました。

現在、現時点では、2つの異なるバージョンのソフトウェアが完全に機能しています。私たちは両方とも、変更に対してコミットを実行し、コードを忠実にテストしました。独立して、素晴らしい仕事をしたと確信しています。それで?

さて、それはマージする時ですが、...がらくた、今何が起こりますか?ソフトウェアの2つのワーキングセットから、アカウント管理が機能せず、新しいアカウントが破損し、古いバグがまだそこにあるかどうかさえわからない、新しくバグの多いソフトウェアの1つの統一されたひどく壊れた部分に移行することはできます。 。

たぶんソフトウェアは賢くて、衝突があったと言って、私たちがそれにガイダンスを与えると主張しました。まあ、がらくた-私はそれを行うために座って、あなたが私がすぐに理解できないいくつかの複雑なコードを追加したことを確認します。私が行った変更とは矛盾していると思います...お願いします。1分たったらチェックすると、理解できない私のコードが表示されます。私たちのどちらかまたは両方が、座って適切なマージをハッシュ化し、場合によってはダン全体を再テストして、壊れていないことを確認するために時間をかける必要があります。

その間、他の8人の男たちはすべてサディストのようにコードをコミットしています。マージの競合が発生することを知る前に、いくつかの小さなバグ修正を加えて提出しました。午後に出かけるか、会議などで立ち往生しています。たぶん私は休暇を取るべきです。またはキャリアを変える。

そして、この悪夢を回避するために、一部の人々はコミットメントを非常に恐れています(他に何が新しいのですか?)。私たちは当然、このようなシナリオではリスクを嫌います-とにかく、とにかくそれを台無しにしようとしない限り、人々は無謀な放棄で行動し始めます。 ため息

さあ、行きます。はい、最新のシステムはこの痛みを和らげるように設計されており、簡単に元に戻して、リベース、デベース、フリーベース、ハングライドなどを行うことができるはずです。

しかし、それはすべてより多くの作業であり、電子レンジのボタンを押して、フォークを見つける時間がなくなる前に4コースの食事を済ませたいだけです。そして、すべてが非常に満たされていないように感じます-コードは機能し、生産的であり、その意味がありますが、マージを丁寧に処理するだけですカウントしません

プログラマーは、原則として、優れたワーキングメモリを開発する必要があり、問題が終了するとすぐに、すべてのジャンク名と変数名とスコープを忘れて、マージの競合(または、さらに悪いことに、誤って処理されたマージ)は、あなたの死亡率を思い出させるための招待です。

16
BrianH

リベースは移動する分岐点を提供し、変更をベースラインに戻すプロセスを簡素化します。これにより、長時間実行されているブランチをローカルの変更であるかのように扱うことができます。リベースしない場合、ブランチはベースラインからの変更を蓄積し、ベースラインにマージされる変更に含まれます。

マージすると、ベースラインは元の分岐点のままになります。分岐したラインから数週間分の変更をマージすると、分岐点から多くの変更があり、その多くはベースラインにあります。これにより、ブランチでの変更の識別が困難になります。変更をベースラインに戻すと、変更とは無関係の競合が発生する可能性があります。競合の場合、一貫性のない変更をプッシュすることができます。進行中のマージは管理に労力を要し、変更を失うことは比較的簡単です。

Rebaseは、ブランチポイントをベースラインの最新リビジョンに移動します。あなたが遭遇するどんな衝突もあなたの変更のためだけです。変更のプッシュははるかに簡単です。競合は、ローカルのブランチで追加のリベースを行うことによって処理されます。競合するプッシュの場合、変更をプッシュする最後のプッシュで、変更に関する問題を解決する必要があります。

5
BillThor

自動化ツールは、マージコードが確実にコンパイルおよび実行されるようにすることで改善され、構文の競合を回避していますが、導入される可能性のある論理的な競合がないことを保証できませんマージによって。したがって、「成功した」マージでは、実際には何も保証されず、すべてのテストをやり直さなければならない場合でも、誤った自信を与えてしまいます。

私が見るように、分岐とマージの本当の問題は、それがことわざを遠ざけてしまうことです。 1週間「私は自分の小さな世界で働く」と言って、後で発生する問題に対処します。しかし、バグの修正は、新しい場合は常により速く/より安価です。すべてのコードブランチがマージされ始めるときまでに、行われたことのニュアンスのいくつかをすでに忘れているかもしれません。

前述の2つの問題を一緒に考えてみると、アクティブな開発が少し遅くても、全員が同じトランクから作業して競合が発生したときに継続的に解決する方が簡単で簡単な状況に陥る可能性があります。

4
MrFox

追加の関連ポイントは次のとおりです。リベースにより、リリースブランチの機能を簡単に選択または元に戻すことができます。

0
Bruno Schäpper

いずれの回答でも、3つのことが述べられていません。

  • ブランチの内部を比較する:

    • マージコミットがある場合、ブランチ内の任意のコミットペアを比較することは非常に困難になります。
  • 一度に1つのアイテムをマージする:

    • 2つのブランチの違いを解決する場合、通常はマージが一度に行われ、マージの競合は、特定のコミットが競合の原因であるというコンテキストなしで行う必要があります。リベースする場合、リベースは競合が発生した時点で停止し、そのコンテキストでそれを解決できます。
  • プッシュ前のクリーンアップ:

    • コミットを間違えた場合、後で修正する必要があります。インタラクティブリベースをプッシュしていない場合は、コミットを結合/分割/変更/移動できます。マージした場合でもそれは可能ですが、マージ境界を越えて結合/分割/変更/移動する場合は非常に困難になります。
0
Catskul