私の理解から、SVNは「簡単に分岐できます。マージが難しい」。何故ですか?マージ方法に違いはありますか?
私の理解から、SVNは「簡単に分岐できます。マージが難しい」。何故ですか?マージ方法に違いはありますか?
回答:
Mercurial(およびGit)が問題なくマージされ、Subversionが偽の競合を提示する非常に具体的な状況については、Stack Overflowの回答を参照してください。この状況は、いくつかのファイルの名前を変更するブランチで行われる単純なリファクタリングです。
tdammersの回答に関して、そこには多くの誤解があります。
Subversion、Mercurial、およびGitはすべて、プロジェクトのリポジトリ全体のスナップショットを追跡します。それらをバージョン、リビジョン、またはチェンジセットと呼んでも違いはありません。これらはすべて、一連のファイルの論理的にアトミックなスナップショットです。
マージのサイズに関しては、コミットのサイズに違いはありません。3つのシステムはすべて、標準のスリーウェイマージアルゴリズムとマージされ、そのアルゴリズムへの入力は次のとおりです。
問題ではありません 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がそれらを同様に処理できなかった理由はありません。集中化されていることは確かに理由ではありません。
trunk
SVNで作業しているとき。DVCSを使用すると、共有せずにコミットできますが、SVN svn commit
では、同じブランチで作業する他のユーザーに直接影響します。2人がSVNのブランチで作業している場合でも、すぐにあなたの作業とマージすることなく作業をコミットすることはできません。それはコミットをいくぶん恐ろしくします-これはバージョン管理システムにとって恐ろしい特性です!:
中心的な問題は、これらのシステムがバージョン管理されたディレクトリ構造を表す方法にあります。
システム全体が展開するSubversionの基本概念は、バージョン(またはsvn lingoでは「リビジョン」)の概念です:特定の時点でのファイルのスナップショットです。履歴が完全に線形である限り、すべては問題ありませんが、2つの独立した開発ラインからの変更をマージする必要がある場合、svnは両方の現在のバージョンを比較し、最後の共有バージョン間で3者間比較を行う必要がありますそして2つのヘッドバージョン。一方のヘッドで変更されているように見えるが、もう一方のヘッドでは変更されていない行は、簡単に解決できます。両方のヘッドでまったく同じように逸脱するラインはより困難ですが、通常は実行可能です。異なる方法で逸脱する行は、svnに「これを理解できません、人間、これを解決してください」と言っているのです。
対照的に、gitとmercurial は、バージョンではなくチェンジセットを追跡します。リポジトリ全体はチェンジセットのツリーであり、各チェンジセットは親に依存します。親チェンジセットには任意の数の子を含めることができ、ツリールートは空のディレクトリを表します。言い換えると、git / hgは「最初に何もなかった、このパッチが適用され、次にそのパッチなど」と言います。2つの開発ラインをマージする必要がある場合、git / hgは各ヘッドが現在どのように見えるか、最後の共通バージョンがどのように見えるかだけでなく、移行がどのように行われたかを認識し、よりスマートなマージを可能にします。
DVCSでのマージを容易にするもう1つのことは、コミットとプッシュの概念を分離する間接的な結果です。、および同じリポジトリの任意の2つのクローン間のあらゆる種類のクロスマージをいつでも許可します。svnでは、多くの場合、関係のない変更を伴う大きな変更セットをコミットする傾向があります。これは、コミットが中央リポジトリの更新であり、他のすべてのチームメンバーに影響するためです。壊れたバージョンをコミットすると、誰もがあなたに腹を立てます。ほとんどのセットアップにはネットワーク化されたsvnサーバーが関係するため、コミットにはネットワークを介したデータのポンピングも含まれます。つまり、コミットするとワークフローにかなりの遅延が生じます(特に作業コピーが古く、最初にプルする必要がある場合)。gitとmercurialを使用すると、コミットはローカルで行われ、両方ともローカルファイルシステムの処理に非常に効率的であるため、通常は即座に終了します。その結果、人々は(慣れると)少しずつ変更をコミットし、それが機能するようになると、一度に数十件のコミットをプッシュします。その後、マージ時間になると、SCMにはさらに詳細な情報があり、競合を安全かつ自動的に解決する優れたジョブを実行できます。
そして、物事をさらに簡単にする素敵な詳細があります:
hg mv
またはhg addremove --similarity...
)名前を変更しますが、Gitはヒューリスティックを使用しますが、どちらも名前変更を処理します。マージされたファイルに1つの文字列の違いがあっても、ツリーの競合が発生します。Subversionのいくつかの側面を再学習する必要があります。申し訳ありません。
rename a b
として追跡しcopy a b; remove a
、両方を実行します。マージ動作の違いは、コーナーケースの異なる処理と、MercurialとGitよりも多くのマージを許可するSubversionに起因します。最後に、Git はマージ時とログ時に名前の変更を検出します。これをMercurialに追加することも考えています。