web-dev-qa-db-ja.com

gitまたはmercurialと比較したsvnのマージには違いがありますか?

私の理解から、SVNは「分岐が簡単です。マージするのが難しい」。何故ですか?それらがマージする方法に違いはありますか?

12
user2528

Mercurial(およびGit)が問題なくマージされ、Subversionが偽の競合を提示する非常に具体的な状況については、 my Stack Overflow answer を参照してください。状況は、一部のファイルの名前を変更するブランチで行われる単純なリファクタリングです。

Tdammersの回答に関しては、そこには多くの誤解があります。

  • Subversion、Mercurial、およびGitはすべて、プロジェクトのリポジトリ全体のスナップショットを追跡します。それらをversionsrevisions、またはchangesetsと呼んでも違いはありません。これらはすべて、一連のファイルの論理的にアトミックなスナップショットです。

  • マージのサイズに関しては、コミットのサイズ違いはありませんです。 3つのシステムすべてが標準の3者間マージアルゴリズムとマージし、そのアルゴリズムへの入力は次のとおりです。

    • 最大の共通祖先バージョン
    • 1つのブランチのバージョン
    • 他のブランチのバージョン

    重要ではない 2つのブランチバージョンがどのように作成されたか。祖先バージョン以降、1000個の小さなコミットを使用できます。または、1つのコミットを使用できます。重要なのは、ファイルの最終バージョンです。 (はい、これは驚くべきことです!はい、多くのDVCSガイドがこれをひどく間違っています。)

また、違いについていくつかの良い点を挙げています。

  • Subversionには「voodoo」があり、/trunkから/branches/fooなどにマージできます。 MercurialとGitはこのモデルを使用しません。代わりにブランチが履歴で直接モデル化されます。したがって、履歴は線形ではなく、有向非循環グラフになります。これはSubversionで使用されているモデルよりもはるかに単純なモデルであり、これにより多くのコーナーケースが削減されます。

  • 簡単にマージを遅延したり、他の人に処理させたりすることもできます。 hg mergeによって大量の競合が発生した場合は、同僚にhg pullを依頼して、まったく同じ状態にすることができます。したがって、彼はhg mergeを行うことができ、おそらくあなたよりも競合を解決するのが得意です。

    これは、更新が必要なSubversionでは非常に困難ですbeforeコミットできます。サーバー上の変更を単に無視して、独自の匿名ブランチでコミットし続けることはできません。一般に、Subversionはsvn updateを実行するときにdirty working copyをいじることを強制します。安全な場所に変更を保存していないので、これは一種の危険です。 GitとMercurialでは、最初にコミットしてから、必要に応じて更新およびマージできます。

GitとMercurialがSubversionよりもマージが優れている本当の理由は、実装の問題です。正しい答えが何であるかが明らかであっても、Subversionが処理できない名前の競合があります。 MercurialとGitはそれらを簡単に処理します。しかし、Subversionがこれらも処理できなかった理由はありません。一元化されていることは確かに理由ではありません。

21
Martin Geisler

中心的な問題は、これらのシステムがバージョン管理されたディレクトリ構造を表す方法にあります。

システム全体が展開するSubversionの基本的な概念は、version(または、svnの用語では「リビジョン」)の概念です。ある時点でのファイルのスナップショットです。履歴が完全に線形である限り、問題はありませんが、2つの独立した開発ラインからの変更をマージする必要がある場合、svnは両方の現在のバージョンを比較し、最後に共有されたバージョン間で3者間比較を行う必要がありますそして2つのヘッドバージョン。一方のヘッドで変更されているように見えても、もう一方のヘッドでは変更されない行は、簡単に解決できます。両方のヘッドでまったく同じように逸脱するラインはより困難ですが、通常は実行可能です。異なる方法で逸脱している行は、svnに「これを理解できない、人間、これを解決してください」と言わせます。

対照的に、gitとMercurialはバージョンではなくchangesetsを追跡します。リポジトリ全体はチェンジセットのツリーであり、それぞれが親に依存します。親のチェンジセットは任意の数の子を持つことができ、ツリーのルートは空のディレクトリを表します。言い換えると、git/hgは「最初は何もなかった、次にこのパッチが適用され、次にそのパッチなど」と言っています。 2行の開発をマージする必要がある場合、git/hgは各ヘッドが現在どのように見えるか、そして最後の一般的なバージョンがどのように見えるかを知るだけでなく、移行がどのように行われたかを知っているので、よりスマートなマージが可能になります。

DVCSでのマージを容易にするもう1つのことは、commitPushの概念を分離し、任意の2つのクローン間であらゆる種類のクロスマージを許可する間接的な結果ですいつでも同じリポジトリ。コミットは他のすべてのチームメンバーに影響を与える中央リポジトリの更新でもあるため、svnでは、多くの場合、無関係な変更を伴う大きなチェンジセットをコミットする傾向があります。壊れたバージョンをコミットすると、誰もがあなたに腹を立てるでしょう。ほとんどの設定にはネットワーク化されたsvnサーバーが含まれるため、コミットにはネットワーク経由のデータのポンプも含まれます。つまり、コミットするとワークフローにかなりの遅延が生じます(特に作業コピーが古く、最初にプルする必要がある場合)。 gitとMercurialでは、コミットはローカルで行われ、どちらもローカルファイルシステムの処理に非常に効率的であるため、通常は即座に完了します。その結果、人々は(慣れれば)小さな増分変更をコミットし、それが機能するようになると、1ダース程度のプッシュを1回でコミットします。その後、マージ時間になると、SCMはより詳細な情報を入手できるため、競合を安全かつ自動的に解決するためのより適切な作業を実行できます。

そして、物事をさらに簡単にするニースの詳細があります:

  • あなたは複数のヘッドを持つことができ、それでもどちらかにコミットできます。 Subversionとは異なり、再度コミットする前にプル、更新、マージを組み合わせる必要はありません。マージすることを選択するまで、複数のヘッドはそのままです。
  • ディレクトリは特別に扱われません。代わりに、パスは1つの大きなファイル名と見なされ、すべてのディレクトリは常に同じリビジョンである必要があります。これは、プロジェクトのサブフォルダーが異なるリビジョンにある場合、Subversionブードゥーを実行できないことを意味しますが、作業コピーが管理不能な巨大な混乱状態になる可能性が低くなることを意味し、さらに興味深いことに、移動は削除として表されません-and-add(retrofitメタデータがなければ、svnで完全に機能しなくなります)が、単に名前の変更として。ファイルを移動すると、その履歴全体が保持されます。マージは、同じファイルの移動されていないバージョンに対して行われた移動されたファイルに変更を適用することもできますafter別のブランチの移動
  • ほとんどの場合、実際にはneedでさえブランチを作成しません。代わりに、リポジトリ全体のクローンを作成します。特に同じファイルシステムで行われ、クローンを削除したい場合は、クローンが存在するディレクトリを削除するだけです。そのためにhgやgitを使用する必要さえありません。
  • マージできるものには(もしあれば)いくつかの制限があります。同じリポジトリの6つのクローンを作成し、AからB、CからB、BからD、CからD、Bからマージ(または、プッシュまたはプル、明示的なマージは通常は不要)できます。いつでも、好きなだけ、Aに、DにEに。
  • マージするリポジトリの1つを複製して、もう1つのリポジトリからプルすることで、マージをテストできます。それがあなたの望むことをするなら、あなたは本当のターゲットにプッシュバックすることができます、そうでなければ、あなたはクローンを捨てて、新たに始めます。
6
tdammers