web-dev-qa-db-ja.com

SVNマージの何がそれほど難しいのですか?

重複の可能性:
私はSubversionオタクです。なぜMercurialやGit、その他のDVCSを検討する必要があるのですか?

分散バージョン管理(Git、HG)は、SVNでのマージが困難で苦痛であるため、本質的に集中型バージョン管理(SVNなど)よりも優れていると誰かが言っているのを時々耳にします。問題は、SVNでのマージに問題がなかったことです。実際のSVNユーザーではなく、DVCSの支持者によって行われたという主張しか聞いていないので、私は これらの不快なコマーシャルを思い出しがちですテレビで 彼らはあなたがすでに持っているものをうまく動かしているものを使うのが信じられないほど難しいとごまかしの俳優にふりをさせることによってあなたが必要としない何かをあなたに売り込もうとします。

そして、常に持ち出されるユースケースは、ブランチを再マージすることであり、これは再びそれらのストローマン製品の広告を思い出させます。自分が何をしているのかわかっている場合は、最初にブランチを再マージするべきではありません(その必要もありません)。 (もちろん、根本的に間違っていてばかげていることをしているときは、難しいことです!)

では、とんでもないストローマンのユースケースを無視して、DVCSシステムでのマージよりも本質的に難しいSVNマージには何があるのでしょうか。

28
Mason Wheeler

これは、svnが2つのブランチの最新の共通祖先を正確に決定するための適切なデータ構造を欠いていたためです。これは1回だけマージされるブランチでは大した問題ではありませんが、複数のブランチが複数回マージされる状況では、多くの誤ったマージ競合を引き起こす可能性があります。

私はsvnを厳密にはフォローしていませんが、これらの特定の技術的な問題は最近のバージョンで修正されていると理解しています。しかし、それは神話を払拭するのに十分早い段階では修正されておらず、マージのためにDVCSを試した人々は他の理由でそれに固執しました。

25
Karl Bielefeldt

自分が何をしているのかわかっている場合は、最初にブランチを再マージするべきではありません(その必要もありません)。 (もちろん、根本的に間違っていてばかげていることをしているときは、難しいことです!)

そしてそこには、あなたの混乱の源と一般的な問題全体があります。

あなたはブランチをマージすることは「基本的に間違っていてばかげている」と言います。まあ、それはまさに問題です:あなたはブランチをマージすべきではないものとして考えています。どうして?あなたはブランチのマージがhardであることを知っているSVNユーザーだからです。したがって、あなたは決してそれをせず、他人にそれをしないように勧めます。マージを回避するためにトレーニングされています。 マージを回避するために使用するテクニックを開発しました

私はMercurialユーザーです。私が唯一の開発者である私自身のプロジェクトでさえ、私はブランチを常にマージします。私は修正を入れたリリースブランチを持っています。まあ、私はそれをメインラインにマージして、修正がそこに行くようにします。

SVNを使用している場合、コードベースの完全に異なる構造を採用します。どうして? SVNはマージを困難にするため、複雑なマージをavoidするイディオムとテクニックを開発するためです。

DVCSはデフォルトの状態であるため、複雑なマージを容易にします。 DVCSでは、すべてが多かれ少なかれ分岐です。そのため、それらの全体的な構造は、マージを容易にするためにゼロから構築されています。これにより、マージを決して使用しないSVNワークフローではなく、日常的にマージを使用するワークフローを開発できます。

単純な事実はこれです。SVNとは異なる方法でDVCSにアプローチする必要があります。これらの非常に異なる種類のバージョン管理システムには、適切なイディオムを使用する必要があります。 SVNでは、マージが難しいため、マージを伴わないイディオムを採用します。 DVCSでは、大したことではないのでマージを頻繁に使用するイディオムを採用します。

適切な仕事のための適切なツール。

問題は、マージに焦点を当てたワークフローは、マージしないSVNスタイルのワークフローよりもlot使いやすく、使いやすいことです。 releaseブランチから何かがdevブランチに取り込まれたときを確認するのは簡単です。ブランチ間のさまざまな相互作用を簡単に確認できます。物事のテストブランチを作成し、テストが機能しない場合は簡単に切り離すことができます。等々。

本当に、 ジョエルは私がこれよりもずっとよく説明しています 。よく読んでください。

47
Nicol Bolas

SVNマージについてそれほど難しいことは何もありません...もう...適切な哲学に従っている場合

他のほとんどの回答で私が見るのは、しばらくSVNを使用していない人からのものであるようです。誰かが正確に述べているように、「それは神話を払拭するのに十分早い時期に修正されなかった」。

最近継承したレガシープロジェクトでSVN 1.6から1.8を使用した現在の経験から、SVNはマージをはるかに簡単にするために長い道のりを歩んできました。ただし、これは絶対に確実なことではありません。また、 think は、ユーザーが意図した用途から逸脱することで簡単に苦しむことはありません。

私はSVNをよく知っていて、それまでの間、Mercurialを個人的なプロジェクトで試しましたが、このプロジェクトの前にSVNで多くのブランチを作成したことはありませんでした。かなりの試行錯誤があり、開始時に予期しないマージ競合が lot 発生しました。

しかし、結局のところ、1つ(またはその他の問題)が発生するたびに、適切にを実行しなかったことが原因であることに気付きました(別名 "SVNの方法"-間違いなく、適切なバージョン管理方法)。私はこれが難しいところだと思います:組織化されていない方法でやりたいことは何もできず、SVNが完全に機能することを期待します。マージは、ユーザーが真の力を発揮する前に、ユーザーからの厳しい規律を必要とします。

マージをクリーンに使用するための要件ではないにせよ、私が気づいたのは次の点です。

  • SVNの最新バージョン(私の意見では1.6以上)を使用してください。より多くの自動化とチェックが行われます。
  • デフォルトの「トランク、ブランチ、タグ」構造を使用し、その哲学を適用します(タグにコミットしないでください)。 SVNは何もチェックしません。タグをブランチとして使用する場合(そのプロジェクトリポジトリを見つけた状態です)、それでも機能しますが、一貫性を保つ必要があります。
  • ブランチとは何か、いつブランチを作成するかを把握します。タグについても同じです。
  • サイドブランチをソースブランチで最新の状態に保ちます(通常はトランクですが、技術的にはどのブランチからでもブランチできます)。これは必須 SVNに自動マージを実行させる場合です。 SVN 1.8は、最新のものではない場合、および作業コピーに保留中の変更がある場合、実際には自動マージを防ぎます(この動作は1.8.5で再び消えたようです)。
  • 「適切な」コミットを行います。非常に具体的なコンセプトの変更のみを含める必要があります。可能な限り、それらには少量の変更を含める必要があります。たとえば、しない 1つのコミットに2つの独立したバグに関する変更が含まれるようにしたいとします。すでに両方を修正していて、それらが同じファイルにある場合は、一方のバグの変更を保存して、最初に just もう一方の変更をコミットできるようにする必要があります then 2番目の変更セットをコミットします。 TortoiseSVNでは、「コミット後に復元」を使用してこれを簡単に行うことができます。
    • そうすることで、特定の独立した一連の変更を元に戻すことができ、そのようなセットを別のブランチにマージすることだけが可能になります。はい、SVNでは、厳選されたリビジョンをマージできます。
  • サブブランチ(トランクから分岐し、その新しいブランチから分岐する)を使用する場合は、階層を尊重してください。サブブランチをトランクで更新する場合、またはその逆の場合、多少の苦労が伴います。マージは、階層を下または上にカスケードする必要があります。
    • 数か月の実験の後、これが最も重要な部分である可能性があることを保証できます。同じトランクから2つのサブブランチを作成し、サブブランチ間、または場合によっては両側のサブサブブランチ間でビットをマージしようとしました。これにより、SVN(またはユーザー)がトリップする可能性があります。特定のリビジョンをマージする場合は問題なく動作します。自動マージで問題が発生する可能性があります。
    • サブブランチAをトランクと同期し、サブブランチAからサブブランチBに何かをマージしようとすると、特に問題が発生しました。SVNは、「トランクから同期」リビジョンをサブブランチに合法的にマージする必要があると考えているようですBそしてこれは大量の紛争につながります。
  • 可能な限り、ブランチのルートからマージします。そうしないと、SVNはサブフォルダーに対して行われたマージのみを追跡し、ルートから do を自動マージしようとすると、マージされていないリビジョンが見つからないという警告が表示される場合があります。これらをルートからマージするだけで修正できますが、混乱を避けるのが最善です。
  • コミットするブランチに注意してください。 Switchを使用して、作業コピーがさまざまなブランチを指すようにする場合は、どこにコミットするかを確認してください。
    • that ブランチの変更を本当に望まないのは特に悪いことです。私はまだそれについてはっきりしていませんが、それを取り除く方法/正しいブランチに転送する方法(リバート、マージ)に応じて、何か厄介なことができます。それは修正可能ですが、潜在的な競合を回避または即座に解決するためにリビジョンごとにリビジョンをマージするか、自動マージ後におそらくより複雑な競合を修正する必要があります。
  • ブランチをあまり長く触れないでください。実際、それは時間の問題ではなく、ブランチとトランクにコミットされたリビジョンの数と、これらの変更の量です。 2つのブランチ間のマージ、3ウェイマージは常に、ブランチ間の最新の一般的なリビジョンと比較されます。その間の変更が多いほど、自動マージが失敗する変更が多くなります。もちろん、その間にコードの構造を変更した場合(ファイルを移動または名前を変更した場合)は、はるかに悪くなります。

上記に従わない場合、競合が発生する可能性が非常に高くなります。それらは常に解決可能ですが、時間を費やすのはそれほど楽しいものではありません。

ああ、マージについてもう1つあります。私が読んで試したすべてのことから、SVNは本当にやっかいです:削除/移動/名前を変更したファイル/フォルダー。 どうやら、SVNはまだ1つのブランチで名前変更、削除、または移動されているファイルを処理できず、元のバージョンが別のブランチで変更されてから、それらをマージします。ファイルがどこに移動したのかわからないだけで、反対に変更を「忘れて」しまいます。 1つの変更は明らかに解決できません(ファイルを削除または変更しますが、両方を行うことはできません)が、移動/名前変更されたファイルに変更を適用すると、 should は機能しますが、機能しません。うまくいけば、これはすぐに修正されます。

それで、全体として、SVNマージは簡単ですか?私はそうは思いません。もちろん、のんきなやり方ではありません。 bad ?私はそうは思いません。それはあなたがそれを間違った方法で使用し、あなたが何をしているかについて十分に考えていないときにのみ、あなたの顔に吐き出されます。

これに基づいて、私の経験からこれらのことについて少し寛容であり、すべてが最初から自動化されていた(少なくとも最初のバージョンから)ため、人々がMercurialを好む理由がわかります(たとえば)。しかし、SVNはかなり追いついてきたので、もうそれほどバッシングする価値はありません。

21
leokhorn

内部データモデルは根本的に異なります。

基本的に、SVNでは、ブランチの履歴を見ると、そのブランチで何が起こったかしかわかりません。したがって、ブランチBからブランチAにマージすると、ブランチAの履歴には、Bに対して明示的に行われたすべての変更を含む1つの大きなコミットが含まれます。分岐しました。

SVNの最初のバージョンでは、ブランチBをブランチAにもう一度マージする必要がある場合、マージするブランチBのリビジョン範囲を手動で指定する必要がありました同じリビジョンを2回マージすることを避けるため。賢い開発者はもちろん、「M:1でマージされたB:1234」のようなコミットメッセージを使用します。

SVN 1.5はこれを「修正」しました。しかし、マージが基本的に適用される方法は変わりませんでした。ブランチAに追加のメタデータを追加するだけで、リビジョン1234がマージされたことをSVNに知らせ、SVNが正しいリビジョン範囲を自動的に選択できるようにしました。

ただし、このソリューションは基本的に、マージされたものの追跡を基本的にサポートしないデータモデルの回避策です。

2つのブランチをマージすることは、比較的単純な例です。しかし、このより複雑なシナリオをイメージ化する

  1. Aからブランチtrunkを作成し、ここでいくつかのコミットを行います
  2. BからブランチAを作成し、ここでいくつかのコミットを行います
  3. trunkAでいくつかのコミットを行います
  4. Btrunkにマージ
  5. ABにマージ
  6. Atrunkにマージ
  7. Btrunkにマージします(これは実際には何もしません)

メタデータモデルを使用してこれを正しく処理することは非常に複雑になります(SVNが実際にこのシナリオを正しく処理するかどうかはわかりません。また、テストする傾向もありません)。

Gitでこのシナリオを処理するのは非常に簡単です。

Gitでは、コミットするたびに、そのコミットを表す内部オブジェクトに前のヘッドへの参照が含まれます。ブランチをマージすると、コミットにはマージされるすべてのブランチの前のヘッドへの参照が含まれます(gitでは一度に複数のブランチをマージできます)

したがって、gitで1つのコミットの履歴を調べると、すべての履歴を確認でき、いつ分岐されたか、いつマージされたか、そして分岐とマージの間の両方の分岐の履歴を確認できます。

したがって、部分的にマージされたブランチをマージする場合、すでにマージされているものとマージされていないものを判別することは非常に簡単です。

Mercurialの経験はありませんが、内部の仕組みはgitに似ていると思います。

基本的に、SVNにとって、ブランチを安価にすることが設計目標でした。しかしgitでは、マージを安くすることが設計目標でした。

最後に、前回SVNを使用したとき、あるブランチでファイルの名前が変更され、別のブランチで変更されたマージを処理できませんでした。

5
Pete

私はSVNマージのかなりの部分を実行しました-長期にわたる開発ブランチとリリースブランチを含む。概して、私は生き残った。マージは常にトリッキーですが、DCVSの場合、マイナス面はひどく悪いことではありません。すべてローカルであるため、既知の適切なリビジョンに更新して続行してください。一方、SVNではサーバー側で多くのことが発生したため、リカバリは醜いものでした。通常、ローカルコピーを消去してから、新しいクリーンブランチをチェックアウトして再試行しました。私の場合は悪くありませんでした-SVNボックスへのギガビット接続が役立ちます。しかし、低速の接続を使用しているため、マージを含めてすべてが永遠にかかるため、これに多くの問題を抱えている請負業者がいました。

1
Wyatt Barnett