gitやmercurialと比べてsvnのマージに違いはありますか?


12

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

git  svn  mercurial  dvcs 

回答:


21

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

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

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

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

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

    問題ではありません 2つの分岐バージョンが作成されましたか。先祖バージョンから1000回の小さなコミットを使用することも、1回のコミットを使用することもできます。重要なのは、ファイルの最終バージョンです。(はい、これは驚くべきことです!はい、多くのDVCSガイドがこれをひどく間違っています。)

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

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

  • マージを簡単に遅らせたり、他の誰かにそれを処理させることさえできます。hg mergeたくさんの競合が発生した場合は、同僚にあなたに頼むことができます。そうすればhg pull、彼はまったく同じ状態になります。ですから、彼はhg mergeあなたよりも対立の解決に優れているかもしれません。

    これは、コミットするに更新する必要があるSubversionでは非常に困難です。サーバー上の変更を無視して、自分の匿名ブランチでコミットし続けることはできません。一般に、Subversionは、次の場合にダーティな作業コピーで遊ぶことを強制しますsvn update。変更を安全な場所に保存していないため、これは一種の危険です。GitとMercurialでは、最初にコミットしてから、必要に応じて更新およびマージできます。

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


4
いい答えです!できれば2回投票します。SOに答えはに:)私はまた、SVNの本は、あなたが参照していることを追加したいはっきり認めているという「Subversionのマージ追跡機能は、非常に複雑な内部実装を持っている...」これだけでは機能が信頼できないとかなり良い表示がある-
ブヨ

2
...そして、その非常に複雑な実装でも、単純な場合を除き、共通の祖先を正しく把握することはできません。
-Jan Hudec

遅延マージについて-取得しないでください-SVNを使用すると、同僚はトランクを更新/チェックアウトし、ブランチからマージできます。
ギル・ベイツ

@GillBates:私はあなたがあなたの仕事のためにブランチを始めていない状況について話している-あなたがtrunkSVNで作業しているとき。DVCSを使用すると、共有せずにコミットできますが、SVN svn commitでは、同じブランチで作業する他のユーザーに直接影響します。2人がSVNのブランチで作業している場合でも、すぐにあなたの作業とマージすることなく作業をコミットすることはできません。それはコミットをいくぶん恐ろしくします-これはバージョン管理システムにとって恐ろしい特性です!:
マーティンガイスラー

6

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

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

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

DVCSでのマージを容易にするもう1つのことは、コミットプッシュの概念を分離する間接的な結果です。、および同じリポジトリの任意の2つのクローン間のあらゆる種類のクロスマージをいつでも許可します。svnでは、多くの場合、関係のない変更を伴う大きな変更セットをコミットする傾向があります。これは、コミットが中央リポジトリの更新であり、他のすべてのチームメンバーに影響するためです。壊れたバージョンをコミットすると、誰もがあなたに腹を立てます。ほとんどのセットアップにはネットワーク化されたsvnサーバーが関係するため、コミットにはネットワークを介したデータのポンピングも含まれます。つまり、コミットするとワークフローにかなりの遅延が生じます(特に作業コピーが古く、最初にプルする必要がある場合)。gitとmercurialを使用すると、コミットはローカルで行われ、両方ともローカルファイルシステムの処理に非常に効率的であるため、通常は即座に終了します。その結果、人々は(慣れると)少しずつ変更をコミットし、それが機能するようになると、一度に数十件のコミットをプッシュします。その後、マージ時間になると、SCMにはさらに詳細な情報があり、競合を安全かつ自動的に解決する優れたジョブを実行できます。

そして、物事をさらに簡単にする素敵な詳細があります:

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

2
私はいくつかの修正を言及する必要がありと答えるために追加されます:1. SVNのリビジョンがされているグローバルごとのリポジトリ、改正いくつかの瞬間にレポ内のすべてのファイルを表します。2.マージ技術は、基本的には SVNとDVCSに共通-マージファイル内のファイルがあればのみ変更します同様に、マージはSVNとDVCSに対して同じ量の競合を生成します-すべてのSCMは論理ブロックではなく、文字列レベルで動作します。 -基本的なパターンを無視します。支店|マージは場合は/ dev /脳と/ dev /手の仕事、SVNで動作します
レイジーバジャー

2
パート2:DVCSのスマートマージは、Subversionとは異なり、ファイルの移動と名前の変更を追跡および処理し、SVNはそれをまったく行わないため、ほとんど発生します。第二に、失敗します。支店を持つとクローンの作成に使用する、生きるために同じ権利との分岐だけ異なる戦略をされている分岐は「...から...依存」
レイジー狸

@LazyBadger:反対です。Subversion 移動/名前変更を追跡します。これは、マージでの名前変更の処理が単にバグが多いためと、正しく処理するのが難しいまたは不可能なコーナーケースがあるため、偽の競合を引き起こします。後者は、設計上git(およびMercurialがコピー)が名前変更を追跡せ、マージ時にそれらを推測する理由です。内容がまだマージできるほど類似している場合(必要な場合)は問題なく動作し、それ以外の場合は愚かなことはしません。
Jan Hudec

@JanHudec -申し訳ありませんが、SVNのハンドルではありません移動|にリネームアトミック1アクション(DVCSの道- 「名前の変更」)、しかしとして「削除+ ...」、これ-それはDVCSでは発生しません農産物ツリーの競合、(真の名前変更)。Mercurial トラックは明示的にhg mvまたはhg addremove --similarity...名前を変更しますが、Gitはヒューリスティックを使用ますが、どちらも名前変更を処理します。マージされたファイルに1つの文字列の違いがあってもツリーの競合が発生します。Subversionのいくつかの側面を再学習する必要があります。申し訳ありません。
レイジーバジャー

5
今、私たちは非常に技術的になりました:-) SubversionとMercurialの両方のトラックコピー、名前の変更ではありません。両方のシステムは、1つのアトミックコミットrename a bとして追跡しcopy a b; remove a、両方を実行します。マージ動作の違いは、コーナーケースの異なる処理と、MercurialとGitよりも多くのマージを許可するSubversionに起因します。最後に、Git マージ時とログ時に名前の変更を検出します。これをMercurialに追加することも考えています。
マーティンガイスラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.