次の方法で共有


Team Foundation Server

Visual Studio TFS での分岐とマージのガイド

Bill Heys

コード サンプルのダウンロード

2006 年の発足以来、Visual Studio ALM Rangers チームはマイクロソフトの開発部門で活動し、Visual Studio 製品グループ、Microsoft サービス、および Microsoft Most Valuable Professional (MVP) コミュニティの間で連携を推し進めてきました。Rangers チームが指標とするビジョンは、不足している機能に対処し、導入を妨げるものを取り除きながら「機能やガイダンスの不足に外部から解決策を提供し、Visual Studio の導入を促進する」ことです。Rangers チームは、さまざまなテクノロジの専門家とビジネスの専門家が連携し、実社会の経験を共有することでコミュニティを強化します。Rangers の活動の詳細については、msdn.microsoft.com/vstudio/ee358786 (英語) を参照してください。

「Visual Studio Team Foundation Server (TFS) 分岐ガイド 2010」(tfsbranchingguideiii.codeplex.com、英語) は、ハンズオン ラボとコミュニティから得た教訓を提供し、Visual Studio TFS 2010 での分岐とマージに関する、洞察力があり実践的なガイダンスをまとめたものです。今回の記事では、次期バージョンの分岐ガイドに盛り込む予定の、高度な分岐シナリオをいくつか紹介します。

分岐ガイドのこれまでとこれから

「Rangers 分岐ガイド」は、Visual Studio 2005 と TFS 2005 のリリース後に Rangers のプロジェクトとして出発しました。最初にリリースしたガイダンスは、2007 年に CodePlex に公開しました。

2008 年、Rangers は「分岐ガイド II」プロジェクトに着手します。この 2 回目のリリースでは、ガイダンスを一連の関連ドキュメント (主文、シナリオ、Q&A、図表、ポスターなど) に再編成しました。この主文に記載したように、それぞれの二次ドキュメントは、基本ガイダンスの基盤となることを意図していました。「Rangers 分岐ガイド II」は、2008 年の終わりごろ CodePlex に公開しました。

2009 年、Rangers チームは再び、新しい分岐ガイド プロジェクトとして「分岐ガイド 2010」を立ち上げました。この 3 回目のリリースは、Visual Studio 2010 と TFS 2010 における数多くの新しい分岐機能を紹介することに重点を置いています。分岐ガイド 2010 の重要な新機能は、分岐を目に見える形にすることです。

最新バージョンのガイドのタイトルが「Rangers Visual Studio TFS 分岐ガイド 2010」となっているためか、このガイドが Visual Studio 2010 のみに当てはまるという誤解が生じています。そこで、まず、はっきりさせておかなければならないことは、このガイダンスで紹介しているベスト プラクティスとガイドは、以前のバージョンの Visual Studio と TFS にも引き続き当てはまるということです。実際、Rangers チームは、ソース管理 (SCM) に別のツールを使用しているユーザーから、肯定的なフィードバックを受け取っています。

Rangers チームは、2011 年に再び「Rangers 分岐ガイド」を更新することを計画しています。

CodePlex のサイトで、質問や、率直なフィードバック、そして関心事項をお気軽に投稿してください。

分岐の目標と方針

分岐を行う主な目標は、並列作業を複数の独立した流れに分けることです。最新の「Rangers 分岐ガイド 2010」では、どちらかと言えば、複雑な開発構想中に分離を行うことよりも、リリースの分離を行うこをに重視していました。

多くの場合、製品の次期リリースに向けてのすべての開発作業を単独の開発チームが担当することが可能です。このような単純なケースでは、継続的な安定化 (メイン分岐)、または持続的エンジニアリング (修正プログラムやサービス パックの継続的サポートを伴う製品リリースの出荷) から開発工程を分離するのに必要なのは開発分岐 1 つだけです。

ところが、開発構想が複雑になると、開発分岐 1 つだけでは、大規模製品開発作業の柔軟性を高め、十分な分離を実現することができないため、Rangers はこのような複雑な開発構想をサポートするよう何度も要請されてきました。次回リリースする「Rangers の分岐ガイド」では、機能チームによる開発といった複雑な開発シナリオに対処する方向に進めていく予定です。

Rangers では、分岐の方針についての議論を、次の 2 つの領域に分けることがよくあります。

  1. ソフトウェアをどのように "開発" するか。チーム構造が小規模で単純か、それとも、並列に開発作業を行う複雑なチームをサポートする必要があるか。
  2. ソフトウェアの "リリース" 先は社内か社外か。リリース バージョンを複数サポートする必要があるか。修正プログラムやサービス パックを提供する必要があるか。

シナリオによっては、リリースの方針が、開発プロセス、特に開発チームの構造に影響を及ぼすことがあります。ただし、ほとんどの場合、リリース プロセスと分岐方針の複雑さと、開発プロセスと分岐方針の複雑さとは切り離すことができます。

分岐の方針を立てるにあたっては、分岐の構造だけでなく、分岐のプロセスについても考慮します。たとえば、「Rangers 分岐ガイド 2010」で解説している基本分岐計画では、MAIN (メイン分岐)、DEVELOPMENT (開発分岐)、および RELEASE (リリース分岐) のたった 3 つしか分岐はありません。優れた分岐方針を立てる場合、分岐の関係を記述します (メイン分岐は開発分岐とリリース分岐の親であるなど)。

また、分岐方針では、分岐の構造によって暗黙のうちに決まる分岐のプロセスを表します。たとえば、メイン分岐でコードをビルドする頻度、メイン分岐から開発分岐にコードをマージする (順方向の統合) 頻度、開発分岐からメイン分岐にコードを分岐する (逆方向の統合) 条件などです。では、典型的な分岐シナリオをいくつか見てみましょう。

機能チームのシナリオ

多くの場合、複数の開発チームや機能チームが並行作業する、大規模で複雑な開発作業をサポートするために、分岐の方針が必要になります。そこで問題になるのが、開発分岐をいくつに分ける必要があるかということです。開発分岐を複数に分ければ、あるチームが開発した機能と、別のチームが開発した機能を、いつ、どのように統合すればよいかという疑問が生じます。開発分岐の方針には、このような疑問に対する答えを盛り込みます。

まず、複雑な開発構想を表現することから着手します。おそらく、リリース スケジュールは構想全体に共通ですが、複数の独立した機能チームはそれぞれ独自のマイルストーンに向けて作業を進めます。各チームが開発した機能が完成しテストが完了すると、メイン分岐に統合されます。

1 つのチームの中では、開発者個人の変更はローカル ワークスペースを使用して、別のメンバーの変更とは切り離します。ある機能チームによる変更を、同じプロジェクトで並行に作業している別の機能チームの変更から切り離すには、機能チームの分岐が優れた方法です。各機能チームによる変更を切り離しておかないと、あるチームによる変更が別のチームの機能に悪影響を与え、そのチームの開発速度が低下するおそれがあります。

機能チームを分離する分岐構造を作成することは比較的簡単ですが、構造を作成する前に、後で機能チームの分岐を統合する方法を計画しておく必要があります。たとえば、図 1 のように、MAIN 分岐と FEATURE (機能チーム) 分岐の間に "INTEGRATION (統合) 分岐" を追加した方が良いでしょうか。

image: Main and Integration Branches

図 1 MAIN 分岐と INTEGRATION 分岐

それとも、INTEGRATION 分岐をなくし、別の方法で機能チームの変更を統合する方が良いのでしょうか。推奨される、最適なベスト プラクティスは何でしょう。

ここで推奨するのは、分岐階層内のレベルの数を最少限に抑えることです。MAIN 分岐と FEATURE 分岐間に INTEGRATION 分岐を追加すると、MAIN 分岐と FEATURE 分岐間で変更を移動するのに必要なマージが、事実上 2 倍になります。分岐は変更を切り離すには有効ですが、分岐間でコードをマージしたり、常に発生するように思えるマージの競合を解決したりする必要性が生まれます。INTEGRATION 分岐を追加すると、マージが 2 倍になり、そして、マージの競合を解決する労力もおそらく 2 倍になります。

INTEGRATION 分岐をなくせば、分岐階層内の層の数が減ります。しかし、FEATURE-1 分岐と FEATURE-2 分岐をどこで統合し、その統合はどこでテストすべきでしょうか。MAIN 分岐をできるだけ安定した状態に保つには、テストしていない変更を MAIN 分岐に統合しないようにします。INTEGRATION 分岐をなくしたので、機能のマージと統合のテストは、機能チームの分岐自体で管理された手法で完了しなければなりません。

(安定状態の) MAIN 分岐で日々のビルドを行い、ビルドが成功した後に、MAIN 分岐から開発 (FEATURE) 分岐に分岐を行うことをお勧めします。FEATURE 分岐のコードが比較的安定するまでは、FEATURE 分岐からコードを MAIN 分岐にマージしないようにします。つまり、FEATURE 分岐は、品質を保証してから MAIN 分岐にマージすべきです。

FEATURE 分岐のコードが "リリース可能" または "他のチームと共有可能" であると思われる場合にのみ、この FEATURE 分岐と MAIN 分岐または別の FEATURE 分岐を統合することを検討します。図 2 は、このプロセスを、"リリース可能な" 各マイルストーンの後に表しています。

image: Feature Branching

図 2 機能の分岐

以下にプロセスの手順を示します。

  • FEATURE-1 分岐を MAIN 分岐にマージする前に、MAIN 分岐から FEATURE-1 分岐への最終分岐 (順方向の統合、FI) を行います。
  • その MAIN のコードと FEATURE-1 分岐のコードの統合に対する最終テストを完了します。
  • FEATURE-1 分岐のコードが安定したら、このコードを MAIN にマージ (逆方向の統合、RI) します。
  • この時点で、MAIN のコードに FEATURE-1 のコードが組み込まれます。
  • MAIN では、日常のビルドに相当するビルドとテストを行います。MAIN での次回のビルドに成功したら、MAIN を各 FEATURE 分岐に分岐します。初回は、この分岐により、FEATURE-1 のコードが FEATURE-2 のコードに分岐されます。
  • FEATURE-2 分岐では、FEATURE-1 のコードと FEATURE-2 のコードの統合をテストします。
  • FEATURE-2 のコードが、リリース可能または他のチームと共有可能になったら、FEATURE-2 のコードを MAIN にマージします。ただし、まずは MAIN から FEATURE-2 への最後の分岐を行って、最後の統合をテストします。

注: 独立した INTEGRATION 分岐を取り除くにあたっては、統合に自動テストを使用できることが主な要件となります。自動テストを使用することで、多くの変更を分岐にマージすることによって発生するバグをチームが特定および解決できるため、コードの速度 (つまり、機能チームの生産性) への影響が少なくなります。

自動テストを変更の統合テストに利用できなければ、機能チームがバグを特定して解決するために手動でテストを実行することになり、機能チームの生産性に悪影響が及ぶおそれがあります。このようなシナリオでは、MAIN 分岐と FEATURE 分岐の間に INTEGRATION 分岐を追加することを検討します。先ほど説明したように、INTEGRATION 分岐によって、マージやマージ競合の解決の作業が増えることがありますが、この分岐を追加することで、統合が機能チームの生産性に及ぼす影響が少なくなります。

優れた分岐方針を立てるには、正常な分岐プロセスを備えた正常な分岐構造を作成する必要があります。これにより、機能チームの生産性が最大限に引き上げられ、同時にメイン分岐の安定性も維持されます。

共通コードを共有するシナリオ

プロジェクト間で共通コードを共有することは、多くの組織にとっての課題です。Visual Studioでは、プロジェクトまたはソリューション間でコードを共有する主な手法が 3 つあります。

  • ファイルのリンク
  • バイナリ (アセンブリ) の共有
  • ソース コードの共有

また、コードの分離にもいくつかの手法があります (本記事の別の箇所で扱っています)。

  • チーム プロジェクトの分離
  • 分岐による分離
  • ワークスペースの分離

適切なコード共有方針を選択するためには、コード共有の手法と分離の手法を組み合わせる必要があります。

ファイルのリンク: 複数のプロジェクトから単一のソース ファイルへの参照を共有できる Visual Studio の機能 ([既存項目の追加])。ファイルのリンクは、共有するファイル数が限られる、小規模プロジェクトに適しています (これは、Visual Source Safe のファイル共有と似ています)。

ファイルのリンクでは、リンクされるソース ファイルのバージョンを 1 つだけ管理します。リンクされるファイルに変更を加えると、そのファイルをリンクしているすべてのプロジェクトに即座に反映されます。ただし、ファイルのリンクにはデメリットもあり、リンクされるファイルに変更を加える場合は、依存関係にあるすべてのプロジェクト チームと調整することになります。たとえ注意深く調整したとしても、加えた変更が依存関係にあるプロジェクトに悪影響を及ぼす可能性があります。

バイナリの共有 (アセンブリ参照): Visual Studio ソリューションからアセンブリ参照を使用して共通の共有コードを参照します。この場合、依存関係にあるソリューションをビルドまたはコンパイルしても、共通の共有ソース コードがコンパイルされることはありません。依存関係にあるプロジェクトのコンパイルは、プロジェクト参照よりもアセンブリ参照を使用する方が高速に実行されます。

共通コードを担当するチームには、そのコードの完全な所有権があり、十分な管理を行うことが可能なため、理論上は、製品管理、バージョン管理、および品質がおそらく強化され、分岐とマージが複雑ではなくなります。

共通コードを再利用するチームは共通ソース コードにアクセスできないため、新機能を追加する場合は、共通コードの担当チームに、共通の共有ソース コードへの新機能の追加やバグの解決を依頼することになります。

共通コードのアセンブリは、依存関係にあるプロジェクトから参照できる既知のファイル共有にコピーすることで、共有できます。署名済みのアセンブリは、グローバル アセンブリ キャッシュに追加しなくてはならない場合があります。または、アセンブリは、共通コードのチーム プロジェクトから、依存関係にあるプロジェクトのメイン分岐にある bin フォルダーにコピーすることができます。

ソース コードの共有: Visual Studio でのソース コードの共有では、依存関係にあるプロジェクトから、共通の共有コードへのプロジェクト参照を使用します。ソリューションをビルドするときに、共通の共有コード プロジェクトなど、すべてのプロジェクトがビルドされます。複雑なプロジェクトでは、共有コードへのプロジェクト参照を多く含めることにより、ビルド時間が大幅に増加する場合があります。

これは、チームがチーム独自の TFS チーム プロジェクトで共通の共有コードを所有および管理している場合に起こります。この共通コードを共有するには、まず、コードを使用している (依存関係にある) プロジェクトのチーム プロジェクトが含まれるフォルダーに、コードを分岐します。以下にその手順を示します。

  • 依存関係にあるプロジェクトのチーム プロジェクト内に "Share" というフォルダーを作成します (例: $\Product1\Share)。
  • 共通ライブラリ (たとえば EnterpriseLibrary) の MAIN 分岐を、依存関係にあるプロジェクトの Share フォルダーに分岐します。たとえば、$\Enterprise Library\Main を $\Product1\Share\EnterpriseLibrary に分岐します。
  • 適切な共通コードプロジェクトを、依存関係にあるプロジェクトのソリューションに追加します。
  • 依存関係にあるプロジェクトからソリューション内の既存の共通コード プロジェクトへのプロジェクト参照を作成します。

注: 入れ子になった分岐は TFS 2010 ではサポートされません。入れ子の分岐によるエラーは、新しい分岐を、フォルダー構造における既存の分岐の上下に作成しようとすると発生します (図 3 参照)。

図 3 Team Foundation Server 2010 で、入れ子になった分岐によってエラーが発生している例

組織は、依存関係にある各プロジェクトで共通の共有ソース コードへの変更を許可するかどうかを判断する必要があります。変更を防ぐには、共通ライブラリから分岐した後、新しい分岐を読み取り専用にします。その後、共通のコード ソースへのすべての変更は、共通ライブラリのチーム プロジェクトで行い、依存関係にあるプロジェクトのチーム プロジェクトにマージする必要があります。

または、依存関係にあるチーム プロジェクト内で、共有コード ソースの変更を行うことを可能にします。このような変更は、共通ライブラリのチーム プロジェクトに (RI によって) マージすることが可能です。組織は、このような変更を慎重に管理して、変更を共通ライブラリにマージすることを困難または不可能にする非互換性の問題を回避し、共有コードの複数コピーが生成されないようにする必要があります。

アーキテクチャのツール化とモデル化のシナリオ

Visual Studio Ultimate では、UML モデルと Layer モデルを作成できます。これらのモデルは、各 Visual Studio プロジェクトに個別に存在し、多くのパッケージを含むことができ、ソリューションのさまざまな部分に対処することができます。詳細については、アーキテクチャ ツール ガイドを vsarchitectureguide.codeplex.com (英語) で、「アプリケーションのモデル化」を msdn.microsoft.com/library/57b85fsc.aspx で参照してください。

モデルによる分岐とマージが可能かどうかを調べるには、図 4 のような、3 つのシナリオから成る簡単なテスト環境を作成します。

image: Evaluation Scenarios in a Test Environment to Test Possibility of Branching and Merging

図 4 分岐とマージが可能かどうかをテストするための、テスト環境における評価シナリオ

モデル プロジェクトを含むソリューションを 1 つ備えた Main 分岐を作成します。このモデル プロジェクトには、架空の安定したプロジェクトとして空の UML クラス ダイアグラムを含みます。この Main 分岐を、各シナリオを表す Scenario1、Scenario2、および Scenario3 に分岐し、さらに各 Scenario 分岐を、開発チームを表す Dev1 および Dev2 に分岐します (図 5 参照)。

image: BranchingDemo Team Project, as Viewed in the Source Explorer

図 5 ソース管理エクスプローラーで表示した BranchingDemo チーム プロジェクト

この分岐には何も問題がないことは明らかです。しかし、モデルへの変更を逆方向に統合 (マージ) することは可能でしょうか。

Scenario1 では、どのチームもモデルを変更していません。Scenario2 では、2 チームのうち 1 チームだけがモデルを拡張しています。Development 分岐から関連する Scenario 分岐への RI は、変更のない Scenario1 モデルと、更新した Scenario2 モデルでは問題なく行われます。

Scenario3 ではより現実的に、両方のチームがモデルを更新します。Dev1 チームが 2 つのクラスを作成し、Dev2 チームが 1 つのクラスを作成したとします。

賢明な読者はお気付きでしょうが、どちらのチームもそれぞれの操作で Class1 クラスを作成することになります。

2 つの Development 分岐のうち最初の Development 分岐を Scenario3 分岐に逆統合する場合、このマージは簡単に行えるという誤った感覚を生み出しがちです。しかし、2 番目のチームが Scenario3 分岐に変更をマージするときに、3 つのファイル (.classdiagram、.layout、および .uml) で競合が発生し、チェックインできません (図 6 参照)。

image: A Merge Causes Conflicts Due to the Changes Made by Two Teams of the Class1 Class

図 6 2 つのチームが Class1 クラスに変更を加えたために生じるマージの競合

この場合、[ターゲット分岐バージョンを保持する] か [ソース分岐バージョンを取得する] のどちらかのオプションを選択して、マージが可能かどうかの質問に [はい] で答えます。ところがこれは、変更が失われるという、いずれのチームにとってもまったく好ましくない結果になります。別の方法として、手動でマージを行う [マージ ツールで変更をマージする] というオプションもありますが、大半の利用者にとって、実用的ではないうえわかりにくく、間違いを起こしやすい選択肢です。

このため、アーキテクチャ モデルの分岐とマージは可能ですが、果たして推奨されるのでしょうか。UML モデルでの問題は、構造を目に見える形にしたクラス ダイアグラムなどが、3 つの主要なファイル (.layout、.classdiagram、および .uml) にまたがって行われている点です (図 7 参照)。

image: Visualizations Spread Across Three Main Files

図 7 3 つの主要なファイルまたがって行われる視覚化

.layout ファイルは、モデル内の図形のサイズと位置を定義します。.uml ファイルは "マスター" モデルで、.classdiagram ファイルは、ダイアグラムに存在している .uml ファイルのコンテンツのキャッシュを保持します。

モデル化ツールで普通に編集しても、モデルが不適切な状態にならないように、ツールによってモデルが補強されることがあるため、これがマージを困難にする一因となっています。純粋な XML のマージでは、開くこともできない無効なモデルを作成してしまう危険性をもたらす結果となっても、このような検証は行われません。

各チームが、自身のダイアグラムにのみ変更を行い、その変更が独立したパッケージ内のクラスにしか影響しなければ、この問題を軽減することができます。これは、ほとんどの変更が独立したファイル内で行われるためです。それでも、複数のパッケージにまたがる関係に変更を加えるというケースは必ず存在します。

現実的には、新製品を繰り返し作成するときに、分岐を考えるチームもあるでしょう。この場合、ソース コード、ドキュメント、およびモデルを分岐することになります。アクティビティ、シーケンス、レイヤー、クラス ダイアグラムなどのモデルは、リリース チームが主流の開発とメンテナンスを続ける一方で、新製品を繰り返し作成する中で進化していくモデルの好例です。つまり、このモデルでは 2 つ以上の分岐の中でそれぞれ進化していく可能性が高くなります。したがって、どこかの時点で、分岐シナリオと、非常に困難なマージ シナリオとが遭遇することになります。

現在のモデルはすべて、分岐には適していますが、マージには適していません。難しく、間違いを起こしやすいことを踏まえたうえで、マージを行う場合は、以下の 2 つの推奨事項について考慮します。

  • 1 つソリューションと、各クラスを表すモデル ビューを独立したパッケージで定義することにより、マージを避けます。アーキテクチャ ツール ガイドでは、パッケージ単位に 1 つのソリューション ビュー (図 8) と、モデル ビュー (図 9) を使用するよう提案しています。ダイアグラムに、複数のパッケージからのコンテンツが含まれているときは、ある程度注意を払わなければなりません。これは、クラス、コンポーネント、およびユース ケースによく見受けられます。このような場合の競合を完全に避けるには、ユーザーは "外部の" パッケージに含まれる要素のメタデータを決して編集してはいけません。

    図 8 使用を提案しているパッケージに基づく構造のソリューション ビューでの表示

    image: The Proposed Package-Based Structure as Seen in UML Model Explorer

    図 9 使用を提案しているパッケージに基づく構造の UML モデル エクスプローラーでの表示

  • 共有コンポーネントと同様、モデルを枝分かれしない分岐にします。

フォールバックとは、[ターゲット分岐バージョンを保持する] オプションか [ソース分岐バージョンを取得する] オプションを使用して、1 つの分岐の中でモデルを表示しながら手動で編集することです (図 10 参照)。

image: A Manual Model Edit Merge

図 10 手動でモデルを編集するマージ

たとえば、モデルを目で見て比較し、最上部の分岐内のモデルを手動で更新することで、モデルを表示上 2 つの分岐に分け、手動でマージ (手順 3.) します。統合したモデルを含む分岐を、MAIN に逆方向に統合 (手順 4.) し、変更前のモデルを含む他の分岐は、モデルの競合を解決する際、[ターゲット分岐バージョンを保持する] を使って逆方向に統合します (手順 5.)。

総括すると、モデルを自動的にマージすることは、現時点ではあまりお勧めしません。モデルでは分岐とマージのシナリオは避けるか、マージを行う前に、モデルの編集を目で見て手動で行うことをお勧めします。

実社会の複雑な環境で読者が遭遇すると考えられる、新しい分岐シナリオをいくつか紹介しました。このシリーズの次回の記事では、チーム プロジェクトと、チーム プロジェクト コレクションについて解説します。

Bill Heys は、Microsoft Consulting Services (ニュー イングランド) のシニア コンサルタントです。Heys の Visual Studio ALM Ranger としての活動を、Visual Studio を使用したカスタムのアプリケーション開発とアプリケーション ライフサイクル管理に特化しています。彼のブログは、blogs.msdn.com/b/billheys (英語) で公開されています。

Willy-Peter Schaub は、Microsoft Canada Development Center で、Visual Studio ALM Rangers のソリューション アーキテクトを務めています。80 年代中ごろから、ソフトウェア エンジニアリングにおける簡潔さと保守性を追求し続けています。彼のブログは、blogs.msdn.com/b/willy-peter_schaub (英語) で公開されています。

この記事のレビューに協力してくれた技術スタッフの Marcel de VriesJens JacobsenBijan Javidi、および Alan Wills に心より感謝いたします。