web-dev-qa-db-ja.com

TFS:マージのベストプラクティス

各チームの開発ブランチ、すべての開発ブランチが分岐する共通の統合ブランチ、および統合から分岐する本番ブランチがある標準ブランチアーキテクチャがあります。

開発フェーズでは、開発ブランチに多くのコミットを行います。フェーズの最後に、変更を統合にマージし、後で本番環境にマージします。

すべてのコミットを個別にマージし、元のコミットの説明をコピーして元のタスクにリンクすることは理にかなっていますか?もちろん、別のオプションは、単一のマージ操作ですべてのコミットを一度にマージすることです。私の質問の理由は、最初の方法は時間がかかるためです。他のブランチへのマージを元のコミットにリンクする自動化ツールはTFSにはありません。

ベストプラクティスについてのご意見をお聞かせください。

46
Captain Comic
  1. Dev *-> Integration and Integration-> Productionからのマージは、常に「コピー」マージである必要があります。これは、下流のブランチの安定性を維持するための最も安全な方法です。
    1. 最初に他の方向(例:Integration-> Dev2)でマージして、ターゲットブランチから最新の変更を取得します。
    2. 競合がある場合は、ケースバイケースで差分を処理します。 AcceptMerge(自動または手動のいずれか)が通常望ましい結果ですが、一方または他方のブランチのコピーを変更せずに取得したい場合があります。
    3. ソースブランチ(この場合はDev#2)を使用して、これらの変更を完全に組み込み、対応し、安定させます。
    4. 目的の方向にマージします(例:Dev2-> Integration)。 AcceptTheirs [別名 "ソースからコピー"]としてすべての競合を解決します。
    5. ステップ#1-4の間にターゲットブランチに変更がないことを確認します。 Devブランチがマージを早期に&頻繁に受け入れる場合は、そうであるように、このうまくいけば短いプロセスの間にターゲットブランチをロックするのは面倒ではありません。何らかの理由で死の「ビッグバン」マージが予想される場合は、ロックによって他のチームが同じことを並行して実行できない可能性がかなりあるため、準備が整うまでステップ1〜4を繰り返し繰り返す必要がある場合があります。 。
  2. 可能な場合は常に「追いつき」マージを実行します。つまり、チェックインされたのと同じ順序で物事をマージします。チェンジセット10、20、および30がA-> Bからマージする候補である場合、これらのマージ範囲はいずれも「追いつき」です:10〜10、10 〜20、10〜30。 #10をスキップする変更セットの範囲は、「チェリーピック」と呼ばれます。さくらんぼ狩りを始めると、いくつかの危険にぶつかります:
    1. 上記の merge down、copy up モデルは使用できません。それだけでも、Laura Wingerdはあなたが縁石を飛び越えていると言うでしょう。
    2. 範囲内で変更されたファイルのいずれかが以前に変更された場合は、3方向のコンテンツマージを実行して、チェリーで選択された差分のみが伝達されるようにする必要があります。完璧な差分ツールはありません。意図したよりも多くのコードを持ち込んだり、ターゲットで行われた変更を誤って上書きしたり、2つのブランチが分岐する論理バグを引き起こしたりするゼロ以外のリスクを追加しています。
    3. おそらくより安定したブランチにプロモートする一連の変更は、never以前にビルドまたはテストされた構成を表しています。ターゲットブランチの最終状態について適切な推測を行うことができます。 「モジュールFooに影響するすべての変更をマージし、DevでFooの新しいバージョンをテストしたので、Fooはインテグレーションでどのように動作しますか?」もちろん...頭の中のすべての依存関係(Devのテスト中にIntegrationで変更された可能性のあるすべてを含む)を追跡できれば。ただし、これらの推測は、SCMツールチェーンで認識または検証されることはありません。
    4. 具体的には、TFSでは、名前空間の変更が関係する場所を簡単に選択するだけで、書き込みを要求されます。バージョン範囲やパススコープが名前変更のソースを除外している場合は、代わりにブランチとして渡されます。ターゲットを除外すると、削除が保留されます。パススコープに削除取り消しのルートが含まれていない場合、不可解なエラーが発生します。範囲が削除取り消しと再削除の間にある場合、削除取り消し自体を含めなくても、ターゲットに「ファントム」ファイルが表示されます。 Movesをすべてのパスとバージョンスコープが正しい状態でマージしたが順不同である場合、候補となるすべてのチェンジセットが使い果たされた後でも、ソース名とは異なるターゲット名になる可能性があります。このコンボが今、頭に浮かばないような問題が発生する方法は他にもあると思います。ただ私を信じてください。
  3. マージする前に、常にターゲットブランチでGetを実行します。究極の安全性を実現する高度なバージョン:マージするワークスペースをヒントまたはその近くにある特定のチェンジセット番号に同期し、[キャッチアップ]マージして同じチェンジセットにマージします。そうすることで、いくつかの潜在的な問題を回避できます。
    1. 古くなったコードにマージすると、removeに表示される混乱する3方向差分が、ヒントで表示されるものから変化します。 [最終的には、チェックイン+解決時にそれらを元に戻しますが、両方を回避できる場合、2つの危険な差分を通過する理由はありません]
    2. 競合解決プロセスを2回実行する必要があります。1つはMerge、1回はCheckinです。一般的なケースではこれを回避する方法はありませんが、ほとんどの場合、マージと解決の間に同時に行われる変更の数は、ワークスペースで発生する数日または数週間の変更の数と比較してわずかです。日付。
  4. 本当に何をしているのか本当にわかっているのでなければ、ラベル(またはワークスペース)でマージしないでください。 TFSラベルによって提供される機能を確認し、それぞれが安全で一貫したマージに不適切である理由を分析してみましょう。
    1. ラベルは、複数の時点を表すことができます。ラベルがVCSの一貫したスナップショットを表す場合-そして常にそのように意図されていた場合-日付または変更セットよりも技術的の利点はありません# 。残念ながら、ラベルが実際に長期にわたって一貫しているかどうかを判断することは非常に困難です。そうでない場合、ラベルごとにマージすると、次のようになる可能性があります。
      1. 不注意によるチェリーピッキング(範囲が最初の候補よりも1時間前のアイテムを指すラベルで始まる場合)
      2. 不注意による除外(範囲が、範囲の終わりより前の時間にアイテムを指すラベルで始まる場合)
      3. 不注意による除外(範囲の開始前の時間にアイテムを指すラベルで範囲が終了する場合)
    2. ラベルversionspecsは、特定のアイテムのセットを表します。これらを使用すると、純粋な再帰クエリで他の方法で表示されるファイルとフォルダを意図的に除外できます。この機能も、マージ操作には不適切です。 (そして、もしあなたがこの能力を必要としない場合、日付とチェンジセットを介して何も得ることなく次のリスクを負います。
      1. ラベルに存在しないアイテムは、保留中の削除としてマージされるのではなく、単に無視されます。これまでに取り上げた一部のEdgeケースとは異なり、これは主流のシナリオで発生する可能性が高いが、ほとんどの人が見逃している大きな問題です。 [その結果、TFS 2010はラベル内の削除済みアイテムのサポートを追加します。]
      2. 不注意によるチェリーピッキング。しばらくの間存在していたが、前述の副作用のいずれかにより以前のマージから除外されたアイテムをラベルに追加した場合。
      3. 意図的なチェリーピッキング。この機能がMergeにもたらす全体的な利点は、ガイドラインの1つに違反することです。そのため、それがまったく正当な理由ではありません。さらに、fileレベルでチェリーピッキングを引き起こします。これは、チェンジセットによる「通常の」チェリーピッキングよりもさらに危険です。
    3. ラベルには、わかりやすいカスタマイズ可能な名前、所有者、コメントがあります。したがって、日付/チェンジセットに対して純粋なユーザビリティの違いがあります。技術的な利点はありません。しかし、ここでも見た目ほど魅力的ではありません。 TFSはUIで実際にラベルを表示することはあまりありませんが、変更セットのコメントはあちこちに表示されます。所有者によるクエリは高速(サーバー側)ですが、正確なラベル名を知らない限り、他のほとんどの検索は低速です(クライアント側)。管理機能は事実上存在しません。変更ログや監査はなく、タイムスタンプのみです。全体として、これらはチェンジセットによって提供される保証を放棄する理由にはなりません。
  5. 常にブランチ全体を一度にマージします。ファイルやサブツリーをマージするのは魅力的な場合がありますが、結局のところ、新しい装いでチェリーを選ぶだけです。
  6. 事前に計画します。残念ながら、TFSでブランチの親を変更することは困難なトピックです。難しい場合もあれば、数ステップしかない場合もありますが、明白なことはありません;組み込みコマンドはありません(2010年まで)。 2005/2008にそれを引き出すには、現在のブランチ構造、望ましい構造、およびさまざまなTFコマンドの副作用を悪用する方法についてのかなり深い知識が必要です。
  7. ブランチ内にブランチを作成しないでください。たとえば、疎結合プロジェクト間で共通のモジュールまたはバイナリを維持する方法として、分岐とマージが推奨される場合があります。私は、これが最初から非常に良いアドバイスだとは思いません-ソースコントロールシステムが実際に行うように設計されていないことを実行するよりも、ビルドシステムが適切に主要な仕事をするようにする方がはるかに優れています。とにかく、この「共有」戦術は、プロジェクト自体とひどく衝突し、SCMの目的でより広いブランチ階層内に存在します。細心の注意を払っていない場合は、TFSを使用すると、バージョン管理項目間に任意の多対多のブランチ関係を作成できます。それを整理する幸運(私はかつて顧客のためにそれをしなければならなかった、かなりではありません。)
  8. 2つのブランチに同じ相対パスを持つファイルを個別に作成しないでください。 Mergeを使用してそれらを分岐させるか、名前空間の競合を追跡するのに何時間も費やします。 (2010年は該当なし)
  9. 他のアイテムが存在していたパスの上にファイルを再度追加しないでください。古いアイテムが名前変更/移動されたか、単に削除されたかに関係なく、マージ時に興味深い課題に直面します。完全に伝播するには、少なくとも2つのチェックインが必要です。 (2010年は該当なし、エクスペリエンスはまだ多少低下していますが、チェックインは1回だけで済み、アイテムのコンテンツは保持されますが、名前の履歴はそのブランチとすべての下流ブランチにあります)
  10. 何をしているのかわからない場合は、/ forceフラグを使用しないでください。すべての/ forceマージは事実上適切な選択であり、非常に類似したリスク(解決プロセス中にコードが失われるなど)につながります。
  11. 本当に何をしているのか本当にわかっているのでなければ、/ baselessフラグを使わないでください。ラベルに似ていますが、名前の変更alwaysが不幸なEdgeのケースではなくブランチにモーフィングされることを除いて、削除を見逃します。借方/貸方の保護は一切受けません。そして最も恐ろしいのは、新しいブランチ関係を作成することです。時々。 (各ターゲットアイテムが新しいか、新しい関係で古いか、または既存の関係で古いかについてのフィードバックはユーザーに表示されません)
  12. 可能な場合は/ discard(および同等のAcceptYours解決)を避けます。一部のチェンジセットを破棄して後続のものを受け入れることは、チェリーピッキングの別の名前です:)
  13. 一般的に解像度に注意してください。それぞれのマージには、手元にあるマージへの影響とは別に、独自のダウンストリームエフェクトがあります。
    1. AcceptTheirsは、最初のガイドラインで提唱されているように、「コピー」マージを取得するための迅速で強力な方法です。他のシナリオでも使用する場合は、TFSにファイルの内容を同じにするようではないことを思い出してください。あなたは、2つのファイルがバージョン管理POVから完全に同期していることを伝えています。つまり、反対方向にマージされた可能性のあるターゲットファイルへの以前の変更は、AcceptTheirsをチェックインすると、候補とは見なされなくなります。
    2. 結果の内容がソースファイルと同一のAcceptMerge(自動または手動)は、サーバーによってAcceptTheirsと見なされます。 Checkin Webサービスプロトコルに見られる違いはありません。
    3. 名前の変更が含まれているときにAcceptYoursを使用すると、頭がねじれることがあります。 「同じ」アイテムが異なるブランチで異なる名前を持つ状況にすぐに行き着くでしょう。そもそも変更を破棄する正当な理由があるとすれば、この現象自体は危険ではありません。実際、ビルドブレークやメイクファイルへの1回限りのカスタマイズを回避する必要があるでしょう。これは人間を混乱させるだけであり、ツリー構造がブランチ間で一貫していると想定している自動化スクリプトを壊す可能性が非常に高いです。
    4. AcceptMergeは、理由によりデフォルトです。必要以上にバージョンの競合が発生する場合がありますが、真のマージが必要な場合は、これが最も安全な選択です。 (たとえば、主要なガイドライン「マージダウン、コピーアップ」のステップ#1)。他のガイドラインに従っている限り、手動による注意が必要なマージの数は大幅に減少するはずです。チェリーピッキングに重いワークフロー。
  14. バグは、修正が実際に行われた変更セットにリンクする必要があります。バグ修正がいつ、どこで(そしておそらくどのように)伝播されたかを確認するために、後で下流のブランチにドリルダウンする必要がある場合、それは純粋にソース管理機能です。追加の手荷物で作業項目を汚染する必要はなく、マージを基本的に実行する方法を大幅に変更しません。 2005/2008では、 'tf merges'コマンドまたはAttrice SideKicksのようなサードパーティのUIを使用してマージ履歴をトラバースできます。 2010年には、Visual Studioに洗練された視覚化が組み込まれています。 MSDNの説明とスクリーンショット
74
Richard Berg

私は常に、統合ブランチにコミットの範囲のみをマージし、マージしたチェンジセットの範囲のみを指定しました。

開発段階の個々の作業項目に関連する作業項目は、開発段階の作業項目です。それらを統合またはリリースに展開する必要はないと思います。

顧客からのバグ/機能リクエストを記録する場所を指定していません。これらをリリースブランチに割り当てる場合は、おそらく開発ブランチ用に他のより詳細な作業項目を作成します。マージするときは、マージするブランチでバグ修正によって解決されたすべての問題を解決済みとしてマークします。

まとめると、一括マージを行わない理由はわかりません。

5
Gergely Orosz