私はよく、Hg(およびGitなど)がSVNよりもマージに優れていると読みましたが、Hg/GitがSVNが失敗する(またはSVNが手動の介入を必要とする)ものをマージできる場所の実際的な例を見たことはありません。 Hg/Gitが喜んで進んでいる間にSVNがどこで失敗するかを示すブランチ/変更/コミット/ ...操作のステップバイステップリストを投稿できますか?実用的で、例外的ではないケースをお願いします...
背景:数十人の開発者がSVNを使用してプロジェクトに取り組んでおり、各プロジェクト(または同様のプロジェクトのグループ)が独自のリポジトリにあります。リリースブランチと機能ブランチを適用する方法を知っているので、頻繁に問題に遭遇することはありません(つまり、そこにいたことがありますが、克服することを学びました Joelの問題 of "one Programmer 「チーム全体にトラウマを引き起こす」または「ブランチを再統合するために2週間で6人の開発者が必要です」)。リリースブランチは非常に安定しており、バグ修正の適用にのみ使用されます。 1週間以内にリリースを作成できるほど十分に安定したトランクが必要です。また、単一の開発者または開発者のグループが作業できる機能ブランチがあります。はい、再統合後に削除されるため、リポジトリが乱雑になりません。 ;)
だから、私はまだSVNに対するHg/Gitの利点を見つけようとしています。実際に体験したいのですが、Hg/Gitに移行できる大きなプロジェクトはまだないので、作成されたファイルがわずかしか含まれていない小さな人工プロジェクトで遊んでいます。そして、Hg/Gitの印象的な力を感じることができるいくつかのケースを探しています。
私自身はSubversionを使用していませんが、 Subversion 1.5のリリースノート:マージトラッキング(基礎) では、マージトラッキングが完全に機能する方法とは次のような違いがあるようです- [〜 #〜] dag [〜#〜] GitやMercurialなどのバージョン管理システム。
トランクからブランチへのマージは、ブランチからトランクへのマージとは異なります。何らかの理由で、トランクへのブランチのマージには、--reintegrate
オプションをsvn merge
に必要とします。
GitやMercurialのような分散バージョン管理システムでは、トランクとブランチに技術的な違いはありません:すべてのブランチは等しく作成されます(socialしかし、違い)。どちらの方向へのマージも同じ方法で行われます。
マージトラッキングを考慮するには、-g
および--use-merge-history
に新しいsvn log
(svn blame
)オプションを提供する必要があります。
GitとMercurialでは、履歴(ログ)と非表示を表示するときにマージトラッキングが自動的に考慮されます。 Gitでは、--first-parent
(Mercurialにも同様のオプションが存在すると思います)のみで最初の親をフォローし、git log
の追跡情報を「破棄」するように要求できます。
私が理解していることからsvn:mergeinfo
プロパティは競合に関するパスごとの情報を保存します(Subversionはチェンジセットベースです)が、GitとMercurialでは、複数の親を持つことができるオブジェクトをコミットするだけです。
「既知の問題」Subversionのマージトラッキングのサブセクションでは、繰り返し/循環/リフレクティブマージが適切に機能しない可能性があります。次の履歴では、2番目のマージが正しいことをしない可能性があることを意味します(「A」はそれぞれトランクまたはブランチ、「B」はブランチまたはトランクになります)。
* --- * --- x --- * --- y --- * --- * --- * --- M2 <-A \\/ -* ---- M1 --- * --- * ---/<-B
上記のASCII-artが壊れた場合:ブランチ 'B'はリビジョン 'x'のブランチ 'A'から作成(分岐)され、その後、ブランチ 'A'はリビジョン 'y'でブランチ 'B'にマージされます「M1」をマージし、最後にブランチ「B」をブランチ「A」にマージ「M2」としてマージします。
* --- * --- x --- * ----- M1-* --- * --- M2 <-A \// \-* --- y --- * --- * ---/<-B
上記のASCIIアートが壊れた場合:リビジョン 'x'のブランチ 'A'からブランチ 'B'が作成(フォーク)され、 'y'のブランチ 'A'に 'M1'以降としてマージされます。 「M2」としてブランチ「A」に再びマージされました。
Subversionは criss-cross merge の高度なケースをサポートしていない場合があります。
* --- b ----- B1--M1-* --- M3 \\// \X / \/\ / \-B2--M2-*
Gitは、実際には「再帰的」マージ戦略を使用してこの状況をうまく処理します。 Mercurialについてはわかりません。
「既知の問題」には、ファイル名の変更ではマージ追跡が機能しないという警告があります。一方がファイルの名前を変更し(おそらく変更する)、もう一方が(古い名前で)名前を変更せずにファイルを変更する場合。
GitとMercurialの両方は、実際にはこのようなケースをうまく処理します:Gitを使用したrename detection、Mercurialを使用したrename tracking。
HTH
私も、Subversionがブランチのマージに失敗し、Mercurial(およびGit、Bazaarなど)が正しいことを行うケースを探していました。
SVNブック 名前を変更したファイルが誤ってマージされる方法を説明します 。これは、Subversion 1.5 、 1.6 、 1.7 、および 1.8 !私は以下の状況を再現しようとしました:
cd /tmp rm -rf svn-repo svn-checkout svnadmin create svn-repo svn checkout file:/// tmp/svn-repo svn -checkout cd svn-checkout mkdirトランクブランチ echo 'Goodbye、World!' > trunk/hello.txt svnトランクブランチの追加 svn commit -m 'Initial import。' svn copy '^/trunk' '^/branches/rename' -m 'ブランチの作成' svn switch '^/trunk'。 echo 'Hello、World!' > hello.txt svn commit -m 'トランクの更新' svn switch '^/branches/rename'。 svn rename hello.txt hello.en.txt svn commit -m 'ブランチの名前を変更します。' svn switch '^/trunk'。 svn merge --reintegrate '^/branches/rename'
本によると、マージはきれいに終了するはずですが、trunk
の更新が忘れられているため、名前が変更されたファイルに間違ったデータが含まれています。代わりに、ツリーの競合が発生します(これは、執筆時点でDebianの最新バージョンであるSubversion 1.6.17で発生しています)。
---リポジトリURLの違いを '。'にマージ: A hello.en.txt C hello.txt 競合の概要: ツリーの競合:1
競合はまったくありません。更新をファイルの新しい名前にマージする必要があります。 Subversionが失敗しても、Mercurialはこれを正しく処理します。
rm -rf /tmp/hg-repo
hg init /tmp/hg-repo
cd /tmp/hg-repo
echo 'Goodbye, World!' > hello.txt
hg add hello.txt
hg commit -m 'Initial import.'
echo 'Hello, World!' > hello.txt
hg commit -m 'Update.'
hg update 0
hg rename hello.txt hello.en.txt
hg commit -m 'Rename.'
hg merge
マージ前は、リポジトリは次のようになります(hg glog
):
@ changeset:2:6502899164cc |タグ:tip |親:0:d08bcebadd9e |ユーザー:Martin Geisler | date:Thu Apr 01 12:29:19 2010 +0200 |概要:名前を変更します。 | | o変更セット:1:9d06fa155634 | /ユーザー:Martin Geisler | date:Thu Apr 01 12:29:18 2010 +0200 |概要:更新。 | o変更セット:0:d08bcebadd9e ユーザー:Martin Geisler date:Thu Apr 01 12:29:18 2010 +0200 要約:初期インポート。
マージの出力は次のとおりです。
hello.en.txtとhello.txtのhello.en.txtへのマージ 0ファイルの更新、1ファイルのマージ、0ファイルの削除、0ファイルの未解決 (ブランチマージ、コミットすることを忘れないでください)
つまり、Mercurialはリビジョン1からの変更を取得し、リビジョン2からの新しいファイル名にマージしました(hello.en.txt
)。もちろん、リファクタリングをサポートするためにこのケースを処理することは必須であり、リファクタリングはexactlyブランチで行うことです。
通常の利点(オフラインコミット、 の公開プロセス 、...)について話すことなく、ここに「マージ」の例を示します。のような:
私が見続ける主なシナリオは、...two無関係なタスクが実際に開発されるブランチです
(1つの機能から始まりましたが、この別の機能の開発につながりました。
またはパッチから始まったが、別の機能の開発につながる)。
Mainブランチの2つの機能のうち1つだけをマージする方法は?
または2つの機能をそれぞれのブランチに分離するにはどうしますか?
何らかの種類のパッチを生成しようとする可能性がありますが、問題は機能依存性次の間に存在する可能性があります。
Git(およびMercurialもそうです)は、rebase --ontoオプションを提案して、ブランチの一部をリベース(ブランチのルートをリセット)します。
から ジェフロミの投稿
- x - x - x (v2) - x - x - x (v2.1)
\
x - x - x (v2-only) - x - x - x (wss)
v2用のパッチと次の新しいwss機能があるこの状況を解決できます。
- x - x - x (v2) - x - x - x (v2.1)
|\
| x - x - x (v2-only)
\
x - x - x (wss)
、次のことができます。
私が気に入っている(マージに影響する)他の機能は、 squash commits (まだ別のブランチにプッシュされていないブランチで)レポ)を提示するために:
これにより、競合が少なく、はるかに簡単なマージが保証されます。
最近、SVNからGITに移行しましたが、これと同じ不確実性に直面しました。 GITの方が優れているという逸話的な証拠がたくさんありましたが、例を見つけるのは困難でした。
ただし、GITは、SVNよりもマージのほうがはるかに優れています。これは明らかに逸話ですが、従うべき表があります。
見つけたもののいくつかを以下に示します。
GITを評価していたときに、次のテストを実行しました。これらは、マージに関してはGITが勝者であることを示していますが、それほどではありません。実際には、その差ははるかに大きくなりますが、SVNが不適切に処理する状況を再現することができなかったと思います。
他の人はこれのより理論的な側面をカバーしています。もっと実用的な視点を貸してもいいでしょう。
現在、「機能ブランチ」開発モデルでSVNを使用している会社で働いています。あれは:
一般に、それは動作します。 SVNはこのようなフローに使用できますが、完全ではありません。 SVNには、邪魔をして人間の行動を形作るいくつかの側面があります。それはいくつかの否定的な側面を与えます。
^/trunk
よりも低い地点から分岐する人々には、かなりの数の問題がありました。このゴミはツリー全体の情報レコードをマージし、最終的にマージトラッキングを中断します。偽の競合が現れ始め、混乱が支配します。svn merge
はあなたが望むことをします。変更を元に戻すには、マージコマンドに--reintegrate
が必要であると言われています。このスイッチを本当に理解したことは一度もありませんが、これはブランチを再びトランクにマージできないことを意味します。これは、それがデッドブランチであり、作業を続行するには新しいブランチを作成する必要があることを意味します。 (ノートを参照してください)起こりやすいのは、エンジニアが1日目にブランチを作成することです。彼は作業を開始し、それを忘れます。しばらくして上司がやって来て、仕事をトランクにリリースできるかどうかを尋ねます。再統合とは次のことを意味するため、エンジニアはこの日を恐れています。
...そして、エンジニアはこれをできる限り少なくしているため、各ステップを実行するための「魔法の呪文」を思い出せません。間違ったスイッチとURLが発生し、突然混乱し、「エキスパート」を取得します。
最終的にはすべて落ち着き、人々は欠点に対処する方法を学びますが、新しいスターターはそれぞれ同じ問題を経験します。最終的な現実(彼が始めたときに述べたものとは対照的に)は次のとおりです。
...しかし...
ありがたいことに、チームは対処するのに十分なほど小さいですが、スケールしません。つまり、これはCVCSの問題ではありませんが、DVCSほどマージが重要ではないため、それほど滑らかではありません。その「摩擦の結合」は、「機能分岐」モデルが故障し始めることを意味する動作を引き起こします。適切なマージは、DVCSだけでなく、すべてのVCSの機能である必要があります。
this によれば、--record-only
問題の解決に使用できる--reintegrate
スイッチがあり、 明らかに v1.8はいつ実行するかを選択します自動的に再統合し、その後ブランチが停止することはありません
Subversion 1.5より前(私が間違っていなかった場合)、Subversionにはマージ履歴が記憶されないという重大な欠点がありました。
VonCで概説されているケースを見てみましょう。
- x - x - x (v2) - x - x - x (v2.1)
|\
| x - A - x (v2-only)
\
x - B - x (wss)
リビジョンAとBに注意してください。「wss」ブランチのリビジョンAからリビジョンBの「v2専用」ブランチに(何らかの理由で)変更をマージし、両方のブランチを引き続き使用するとします。 Mercurialを使用して2つのブランチを再度マージしようとすると、リビジョンAとBの後にのみ変更がマージされます。Subversionでは、以前にマージを行わなかったかのように、すべてをマージする必要があります。
これは私自身の経験からの例であり、BからAへのマージはコードの量が原因で数時間かかっていました。これはagain、これはSubversion 1.5より前の場合に当てはまります。
Hginit:Subversion Re-education :からのマージ動作における、おそらくより関連性の高い別の違い
あなたと私がいくつかのコードに取り組んでおり、そのコードを分岐し、それぞれ別のワークスペースに移動して、そのコードに個別に多くの変更を加えると想像してください。
マージする必要があるとき、Subversionは両方のリビジョン(変更されたコードと変更されたコード)を調べようとし、それらを1つの大きな不浄な混乱の中で破壊する方法を推測しようとします。通常は失敗し、ページと実際には競合ではない「マージ競合」のページが生成されます。Subversionが実行した内容を把握できなかった場所です。
対照的に、Mercurialで個別に作業している間、Mercurialは一連の変更セットの保持に忙しかった。したがって、コードをマージしたい場合、Mercurialには実際にさらに多くの情報があります。最終製品を見てそれをどのように配置するかを推測するのではなく、各自が何を変更したかを把握し、それらの変更を再適用できます一緒に。
つまり、違いを分析するMercurialの方法は、Subversionの方法よりも優れていました(だった?)。