外部リポジトリコピー

この記事は、元の場所http://blogs.collab.net/subversion/foreign-repository-copiesからの許可を得てミラーリングされています。無効なリンクは削除または更新されています。

著者:C. Michael Pilato

投稿日時 2013-06-28

しばらく前に、私はこのスペースで書きました。Subversionに実装した新しい機能、つまりいわゆる「外部リポジトリ」(つまり、ワーキングコピーに反映されているリポジトリとは異なるリポジトリ)からワーキングコピーに変更をマージする機能についてです。この機能は、ベンダーブランチを管理するための優れた代替方法として宣伝しました。その投稿では詳細を少し曖昧にしたことを認めますが、考え方は非常にシンプルでした。サードパーティのコードベースのベースラインコピーをリポジトリにインポートし、その後、サードパーティによって行われた変更を、そのリポジトリから直接ローカルのベースラインコピーにマージします。 voilà!ベンダーブランチ。

外部リポジトリのマージ機能の可能性を認識して以来、私もこのアプローチを使用し始めました。サードパーティのコードを使用するCollabNet関連および個人的なプロジェクトがいくつかあります。たとえば、CollabNetのTeamForgeとSubversion Edge製品はどちらもViewVCを使用しています。これらの状況の多くでは、サードパーティのコードベースに小さなカスタマイズを行う必要があります。ベンダーブランチは、これらの変更を管理するための自然な方法です。

しかし、理論を実践し始めると、最初のブランチ初期化ステップで予期せぬ問題に遭遇しました。それはプロパティです。svn importは、インポートソースに記録されているSubversionファイルまたはディレクトリプロパティを認識または複製しません。そのため、svn importを使用してサードパーティのコードのベースラインバージョンでベンダーブランチを作成すると、情報の混合物が生成されます。確かに、ベンダーのファイルの内容とディレクトリ構造はワーキングコピーに完全に複製されていました。しかし、メタデータsvn:ignoresvn:eol-stylesvn:keywordsなどノードプロパティ)は、ベンダーの元のデータソースからではありませんでした。代わりに、独自のローカル自動プロパティ設定から来ていました。

次の(ややこしらえた)例では、svn importがサードパーティライブラリに存在していたsvn:ignoreプロパティを効果的に失うことに注意してください。

$ svn co http://otherfolks.com/svn/trunk third-party-wc
A    third-party-wc/src
A    third-party-wc/src/source_file.c
A    third-party-wc/src/source_file.h
A    third-party-wc/notes
A    third-party-wc/notes/how_to_do_stuff.txt
A    third-party-wc/README
Checked out revision 61.
$ svn plist -vR third-party-wc/
Properties on 'third-party-wc/src':
  svn:ignore
    a.out
$ svn import -m "Initialize vendor branch." \
      third-party-wc http://localhost/svn/my-project/vendor
Skipped 'third-party-wc/.svn'
Adding         third-party-wc/src
Adding         third-party-wc/src/source_file.c
Adding         third-party-wc/src/source_file.h
Adding         third-party-wc/notes
Adding         third-party-wc/notes/how_to_do_stuff.txt
Adding         third-party-wc/README

Committed revision 13.
$ svn co http://localhost/svn/my-project/vendor vendor-wc
A    vendor-wc/src
A    vendor-wc/src/source_file.c
A    vendor-wc/src/source_file.h
A    vendor-wc/notes
A    vendor-wc/notes/how_to_do_stuff.txt
A    vendor-wc/Makefile
A    vendor-wc/README
Checked out revision 13.
$ svn plist -vR vendor-wc
$

しまった!ベンダーからsvn:ignoreプロパティが欠けています!

その結果、ベンダーデータの最初のインポートは問題なく実行されましたが、後で(プロパティの変更が含まれる外部リポジトリのマージを実行している間)プロパティの競合が発生するようになりました。マージは、「プロパティ *NAME* の値を *OLD_VALUE* から *NEW_VALUE* に変更します」と表示されます。私のワーキングコピーは眉をひそめて、「しかし、*NAME* の値は *OLD_VALUE* ではありません。*SOMETHING_ELSE* です」と返答します。ブーン。競合。

$ svn merge -r61:62 http://otherfolks.com/svn/trunk vendor-wc
Conflict for property 'svn:ignore' discovered on '/home/cmpilato/vendor-wc/src'.
They want to change the property value to 'program', you want to delete the property.
Select: (p) postpone,
        (mf) mine-full, (tf) theirs-full,
        (s) show all options: p
--- Merging (from foreign repository) r62 into 'vendor-wc':
 C   vendor-wc/src
A    vendor-wc/Makefile
Summary of conflicts:
  Property conflicts: 1
$

うっ。

この例では、競合の解決は非常に簡単です。しかし、それがポイントではありません。明らかに、ベンダーブランチを初期化するためのより良い方法が必要でした。しばらくの間、難しい方法で作業していました。svn importを使用する代わりに、svn add、ソースデータのプロパティセットを手動で模倣するための多数のsvn propset呼び出し、そしてsvn commitを使用しました。面倒でしたが、機能しました。その一方で、Apache Subversionプロジェクトの課題トラッカーでより良いものに対する機能要求を提出しました。

Subversion 1.7.0の基礎となったSubversionのワーキングコピー管理ライブラリの大量の書き換え、そしてCollabNetの同僚Bert Huijbenによる具体的な追加の努力のおかげで、Subversion 1.8.0が外部リポジトリコピーをサポートするようになったことを嬉しく思います。今では、外部リポジトリからベンダーブランチを初期化することは、ソースとして外部リポジトリのURL、ターゲットとしてローカルワーキングコピーディレクトリを使用してsvn copyを実行するほど簡単です。

$ svn cp http://otherfolks.com/svn/trunk my-project-wc/vendor
--- Copying from foreign repository URL 'http://otherfolks.com/svn/trunk':
A         my-project-wc/vendor
A         my-project-wc/vendor/src
A         my-project-wc/vendor/src/source_file.c
A         my-project-wc/vendor/src/source_file.h
A         my-project-wc/vendor/notes
A         my-project-wc/vendor/notes/how_to_do_stuff.txt
A         my-project-wc/vendor/README
$ svn ci -m "Initialize third-party vendor branch." my-project-wc
Adding         my-project-wc/vendor
Adding         my-project-wc/vendor/README
Adding         my-project-wc/vendor/notes
Adding         my-project-wc/vendor/notes/how_to_do_stuff.txt
Adding         my-project-wc/vendor/src
Adding         my-project-wc/vendor/src/source_file.c
Adding         my-project-wc/vendor/src/source_file.h
Transmitting file data ....
Committed revision 13.
$ svn plist -vR my-project-wc/vendor
Properties on 'my-project-wc/vendor/src':
  svn:ignore
    a.out
$

今回は、ベンダーのsvn:ignoreプロパティが保持されました!これは、後でベンダーの最近の変更をマージする必要がある場合、マージがスムーズに実行されることを意味します(もちろん、競合するカスタマイズを導入していない限り)。

$ svn merge -r61:62 http://otherfolks.com/svn/trunk my-project-wc/vendor
--- Merging (from foreign repository) r62 into 'my-project-wc/vendor':
 U   my-project-wc/vendor/src
A    my-project-wc/vendor/Makefile
$

チャリーン!

完全を期すために、コピー中に発生する外部リポジトリのデータの完全な保存に対する1つの例外について言及しておく必要があります。そこに存在するsvn:mergeinfoプロパティは、ローカルワーキングに作成されたレプリカからフィルターされます。これにより、Subversionがマージ追跡情報が独自のレポジトリの履歴に適用されると考える場合に発生する可能性のある多くの問題を回避できます。しかし、すべてうまくいきます。外部リポジトリのマージも同様にsvn:mergeinfoプロパティを無視するため、この例外はベンダーブランチの維持にそのようなマージを使用することを妨げません!

また、svn copyコマンド構文では、コピーのソースとターゲットをリポジトリURLとワーキングコピーパスのいずれかとすることもできますが、svn copy REPOS-URL WC-PATH構文のみが外部リポジトリコピーをサポートしています。たとえば、あるリポジトリのURLから別のリポジトリのURLターゲットに直接コピーすることはできません。

このアプローチを使用してベンダーブランチを管理する方法の詳細については、新しく書き直された「Subversionによるバージョン管理」のセクションを参照してください。Subversion 1.8で提供されている機能の詳細については、公式リリースノートを参照してください。

(Bertさん、ありがとう!)

著者について

C. Michael Pilatoは、Subversionのコア開発者であり、「Subversionによるバージョン管理」(O'Reilly Media)の共著者であり、ViewVCの主要なメンテナーです。彼はノースカロライナ州の自宅からCollabNetのソフトウェアエンジニアとしてリモートで勤務しており、2001年初頭からアクティブなオープンソース開発者です。Mikeは誇り高き夫であり父親であり、旅行、サッカー、家族との質の高い時間、そしてそれらの組み合わせが大好きです。また、作曲と演奏も楽しんでいます。また、ロックスターになるというあまり秘密ではない空想をいだいています。Mikeはノースカロライナ大学シャーロット校でコンピューターサイエンスと数学の学位を取得しています。