SVNマージの難しさは何ですか?


28

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

時々、誰かが分散バージョン管理(Git、HG)は集中管理(SVNなど)よりも優れていると言うのを耳にします。SVNではマージが困難で苦痛だからです。実は、SVNでのマージに問題はなかったし、実際のSVNユーザーによるものではなく、DVCS支持者による主張だけを聞いたことがあるので、TVでの不快なコマーシャルを思い出す傾向があるあなたがすでに持っていてうまく動作するものは使用するのが信じられないほど難しいとふりをすることによって、あなたが必要のないものをあなたに売ろうとします。

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

だから、ばかげたストローマンのユースケースを割り引いて、DVCSシステムでのマージよりも本質的に難しいSVNマージには何がありますか?


6
私はまだ数ヶ月のブランチがマージされており、分散バージョン管理を使用している環境で働いていません。私が働いた唯一の場所では、そのような長寿命のブランチがTFS / Subversionを使用していました。このような長寿命のブランチは、DVCSとのマージも難しいと予想しています。
-Oded

13
@MasonWheeler困惑しています。では、VCSを何に使用しますか?(多くの)推奨されるプラクティスの1つは、機能ブランチを持つことです。その場合、トランクへのマージは必須です。または、私は何かを誤解しましたか?(はい、ツリーメタファ休憩が、それはすべてのIMOで開始する便利なことではなかった)
アンドレスF.

9
@MasonWheeler:あなたは文字通りツリーの例えを少し取っていると思います。
whatsisname


8
@MasonWheelerトランクにマージすることを聞いたことがない場合、いくつの異なる開発環境を経験していますか?一部のショップには安定したトランクと実験的なブランチがあります。その場合、チェリーピッキングで成功した機能を安定した状態に戻すことは定期的なイベントです。
-itsbruce

回答:


25

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

私はsvnにはあまり従いませんが、最近のバージョンでは特定の技術的な問題が修正されていると理解しています。しかし、それは神話を払拭するほど早く修正されておらず、マージのためにDVCSを試した人々は他の理由でそれを使い続けています。


46

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

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

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

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

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

DVCSは、デフォルトの状態であるため、複雑なマージを容易にします。DVCSでは、すべてがブランチです。したがって、それらの構造全体は、マージを容易にするために一から構築されています。これにより、マージを使用しないSVNワークフローではなく、毎日マージを使用するワークフローを開発できます。

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

適切な仕事に最適なツール。

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

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


2
それどころか、ブランチのマージを回避するように「訓練」されたことは一度もありません。それは、DVCSの人々がそれについて話すのを聞き始めるまで、最初は正直に私には決して起こらなかったものです。
メイソンウィーラー

14
@メイソン:それはどうしてトレーニングではないのですか?SVNスタイルでSVNを使用するようにトレーニングされました。また、SVNスタイルはマージを使用しないことです。したがって、あなたは物事を使用したり、マージを検討したりしないように訓練されました。それがあなたには決して起こらなかった理由です。あなたがそれを難し​​くするシステムを使用したからです。
ニコルボラス

5
「訓練されていない」と「訓練されていない」には大きな違いがあります。
メイソンウィーラー

7
@MasonWheeler:いいえ、ありません。あなたが何かをする方法を適切に教えられていないなら、あなたは暗黙のうちにそれをしないように訓練されています。問題を解決するために使用できるイディオムのレパートリーではありません。したがって、これを使用して問題を解決することはできません。効果は、マージしないように言われた場合と変わりません。「同じ疲れた古い地面」として良い議論を思い切って却下する方法は、この証拠です。マージはツールとは考えません。あなたはそれを例外または異常な何かと考えています。何かをする疑問ではなく、使用していました。
ニコルボラス

8
@MasonWheeler:「彼らは間違っている」と決めるのは誰ですか?DVCSは使用しないため、DVCSワークフローの経験はありません。あなたはそれが経験がないので、それがプログラマに役立つかどうかわからない。それでは、SVNが許可していないからといって、それが「間違っている」と言わなければならない権限は何ですか Cにはクラス、仮想関数、テンプレートがないため、間違っていると言っているようなものです。
ニコルボーラ

20

SVNのマージについて難しいことは何もありません...もう...正しい哲学に従えば

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

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

私はSVNを非常によく知っていて、その間に個人的なプロジェクトのためにMercurialを試しましたが、このプロジェクトの前にSVNで多くの分岐を行ったことはありませんでした。かなりの試行錯誤があり、私が始めたとき、私は予期しないマージの衝突をたくさん受けました。

しかし最終的に、私は1つ(または他の問題)を取得するたびに、物事を適切に実行していなかった(「SVNの方法」-おそらく、適切なバージョン管理の方法)ことに気付いた。これが難しさの原因だと思います。組織化されていない方法で何でもすることはできず、SVNが完全に動作すること、特にマージでは期待できません。マージでは、ユーザーが真の力を発揮する前に、厳格な規律が必要です。

マージをクリーンに使用するための要件ではないにしても、強力な推奨事項であることに気付きました。

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

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

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

それで、結局のところ、SVNマージは簡単ですか?そうではないと思います。決して気楽な方法ではありません。それは悪いですか?そうは思いません。間違った使い方をして、何をしているのか十分に考えていない場合にのみ顔に吐き出します。

これに基づいて、私の経験からこれらのことについて少し寛大であり、すべてが最初から自動化されていたので、人々がMercurialを好む理由を見ることができます(例えば)ただし、SVNはかなり追いついているので、これ以上バッシングする価値はありません。


ツリーの競合-はい、SVNはこれらに問題を抱えていますが、TBHは他のすべてのSCMも同様です。Gitには、名前を変更または移動したファイルが同じかどうかを判断するためのヒューリスティックがありますが、常に正しいとは限りません(できません!)。SVNは、これらの競合の解決をより簡単に理解できるように努力する必要があると思います。
gbjbaanb 14

@gbjbaanb:ヒューリスティックは提供しませんが、Mercurialと同様に「修復移動」を提供します。実際に、どの削除済みファイルと追加済みファイルが同じであるかを伝える必要があります。間違いなく改善の余地があります。
leokhorn 14

あなたがプロジェクトに取り組んでいる唯一の人であるとき、これはすべて素晴らしいことです...しかし、あなたが十分な規模のチームを持ち、彼らがすべて「SVNの方法」(誰がそれについて正確に同意するように思われない)を使用している場合まだPITAです。事実、svnは分岐ワークフローをそれほどうまくサポートしていません。「SVNの方法」は、ブランチを作成せず、ウォーターフォールSDLCを使用することです。そうは言っても、私は過去にGitのマージで、数人の人々が取り組んでいる大規模プロジェクトで問題を抱えてきました。しかし、彼らはまだずっと痛みが少ないように見えました。
ryoung

私の経験では、バージョン管理システムがどのように機能するかを気にかけない人と作業している場合、SVNは日常的に使用する方が簡単です。私はいくつかのDVCSチームでしか働いていませんが、常にかなりの数のチームが適切なリビジョン管理動作を行わず、すべての人のリポジトリを汚染します。Subversionでは、一般に、訓練を受けていない人はブランチに近づかないため、ブランチを「エキスパート」に任せて適切に管理します。確かに、...この経験は私だけではあると私は彼らのツールが働いていた方法を知っていたプログラマでのみ動作することを好むだろう
ダッシュ-トム・バン

5

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

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

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

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

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

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

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

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

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

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

したがって、gitで1つのコミットの履歴を調べると、すべての履歴、ブランチがいつ、マージされたか、ブランチとマージの間の両方のブランチの履歴を見ることができます。

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

Mercurialの経験はありませんが、内部の動作はgitに似ていると思われます。

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

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


1

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


接続が遅いことを外挿し、オフサイトのリモートサーバーで作業すると、大きな更新を行うときに接続エラーがドロップされます。
jxramos

-1

はい、私もそうします。現在、作業中のプロジェクトのさまざまなバージョン(ブランチ)用に12個のVMがあります。古いバージョンのバグを修正する必要がある場合、バグを修正し、そのコミットを新しいバージョンのブランチにマージします。しかし、それはブランチ全体を再マージすることです。ここで私が話していることです。

ここに、gitの非常に素晴らしい点の1つがあります。DVCSを継承するのではなく、gitが得意とするものです。任意のブランチの特定のリビジョンを別のブランチにマージできます。基本的には差分を取得して他のブランチに適用しますが、追跡を行い、はるかに自動です。

したがって、ブランチ2.0とブランチ3.0があり、2.0のバグを発見した場合、2.0で修正し、それを解決するリビジョンのセットを取得して、それらのリビジョンのみを 3.0ブランチにマージできます。SVNには、各リビジョンの差分を手動で取得して適用する以外に、これを行う方法はないと思います

もちろん、自動マージアルゴリズムも非常にスムーズに動作するように見え、gitは「すべてのもののブランチを作成する」モデルでゼロから構築されているため、ブランチは本当にスムーズで簡単です。ブランチの軽量さで頻繁にブランチするのは自然なことのようです


また、mercurialにも同様の機能があると思います
-Earlz

2
実際、SVNでもまったく同じことができます。私はいつもそれをします。SVN Mergeコマンドは、別のブランチからリビジョン(またはリビジョンの範囲)を取得し、作業コピーに適用してからコミットできます。
メイソンウィーラー

2
@MasonWheeler多くの反SVN感情が1.5より前のバージョン(svnがマージ追跡を取得したとき)に向けられていたことに留意してください。そしてもちろん、それの多くは無意味なファンボイズムです
...-ヤンニス

3
@MasonWheelerも参照してくださいstackoverflow.com/a/4215199/69742その投稿はDVCSに要約され、バージョンでなく変更セットを追跡します。変更セットは、本質的に簡単に取得してマージできます...コンテキストが必要なため、バージョンはそれほど多くありません
-Earlz

@MasonWheelerああ、これ:stackoverflow.com/questions/2471606/…–
アールズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.