そのMergeinfoはどこから来たのですか?

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

著者: Paul Burba

投稿 2009-11-19

マージ追跡において混乱を招く領域の1つは、svn:mergeinfoプロパティの設定方法です。多くの一般的なユースケースでは、マージターゲット上のmergeinfoのみが設定されます。しかし、ターゲットの下にあるmergeinfo(いわゆる「サブツリーmergeinfo」)が作成または更新されるシナリオが数多くあります。これらの状況では、ユーザーはマージ中に何か問題が発生したかどうか、そしてこれらのサブツリーmergeinfoの変更をコミットする必要があるかどうかを疑問に思うことがよくあります。その混乱は、特定のサブツリーにsvn:mergeinfoプロパティ自体に加えられた変更以外の変更がない場合があるという事実によってさらに複雑になります。

この投稿では、マージ中にサブツリーmergeinfoが作成または更新されるいくつかの一般的なケースについて説明します。

既存のサブツリーMergeinfo

サブツリーmergeinfoの変更の最も一般的な原因は、ワーキングコピーのマージターゲットにマージの前にサブツリーmergeinfoが存在することです。

たとえば、trunkから作成されたブランチB1.0があり、いくつかのサブツリーmergeinfoがあります。

1.6.6>svn propget svn:mergeinfo branches/B1.0 -vR
'branches/B1.0/A/D/H/psi'のプロパティ
  svn:mergeinfo
    /trunk/A/D/H/psi:4-10

revision 12をtrunkからB1.0にマージすると、マージの出力に新しいファイルが追加されたことが示されます。

1.6.6>svn merge ^/trunk branches/B1.0 -c12
— 'branches/B1.0'にr12をマージしています
A    branches/B1.0/A/C/nu

しかし、ワーキングコピーのステータスを確認すると、いくつかのプロパティの変更が見られます。

1.6.6>svn status
 M      branches/B1.0
A  +    branches/B1.0/A/C/nu
 M      branches/B1.0/A/D/H/psi

B1.0単体のdiffを確認すると、ちょうど行ったマージ、つまりtrunkからのr12を記述するmergeinfoが追加されていることがわかります。それは理にかなっています。私たちがまさにやったことです!

1.6.6>svn diff –depth empty branches/B1.0

branches/B1.0のプロパティ変更
___________________________________________________________________
追加済み: svn:mergeinfo
   マージ済み /trunk:r12

しかし、A/D/H/psiのプロパティ変更はどうでしょうか?

1.6.6>svn diff branches/B1.0/A/D/H/psi

branches/B1.0/A/D/H/psiのプロパティ変更
___________________________________________________________________
変更済み: svn:mergeinfo
   マージ済み /trunk/A/D/H/psi:r12

ああ、それはmergeinfoの変更です。しかし待ってください、r12はpsiに影響を与えていないことをたまたま知っており、ログを確認してこれを確認します。

1.6.6>svn log -v -r12
————————————————————————
r12 | pburba | 2009-11-17 18:21:47 -0500 (Tue, 17 Nov 2009) | 1行
変更されたパス
   A /trunk/A/C/nu.c

では、なぜpsiのmergeinfoが変更されたのでしょうか?簡単に言えば、1.6.xまでのすべてのバージョンのSubversionでは、サブツリーがマージによって影響を受けたかどうかに関係なく、サブツリーmergeinfoは常に更新されてマージを記述します。これは、より簡単なmergeinfoの省略*をサポートするため、および範囲の単一マージと、同じ結果になる複数の個別マージ(例:svn merge ^/trunk branch -r 100:103またはsvn merge ^/trunk branch -c101、svn merge ^/trunk branch -c102、およびsvn merge ^/trunk branch -c103)の間の一貫性を保つために行われました。

初期段階で、開発コミュニティでは、この動作が、比較的マイナーな利点によって正当化されるよりも多くの混乱を引き起こしていることに気づきました。確かに、特定のマージによって影響を受けたサブツリーのみが、そのmergeinfoを更新する必要があります。その点については異論はほとんどなく、コーディングの観点からは、その変更はほとんど笑えるほど簡単でした。残念ながら、この変更を加えることで、後続のマージに予期せぬ影響がありました。ここでは詳細には触れませんが、これらの影響の1つは、マージのパフォーマンスが大幅に低下する可能性があったことです。

朗報は、最終的にマージのパフォーマンスを維持し(多くの場合、向上させ)、マージによって影響を受けないサブツリーのmergeinfoの変更の記録を停止できたことです。残念なことに、これらの変更は広範囲に及ぶものであり、1.5.xまたは1.6.xリリースにはバックポートされず、1.7でのみ利用可能になります。

それまでの間、これらのサブツリーmergeinfoの変更をコミットする必要があるかどうか疑問に思っている場合は、コミットする必要があります。コミットする前にそれらを元に戻すことを選択すると、merge –reintegrateオプションを今後使用できなくなり、さらに悪いことに、長期間存続するブランチでは、後続のマージで許容できないレベルに簡単に達する可能性のあるパフォーマンスの低下が発生します。

プロパティのdiff

svn:mergeinfoプロパティはバージョン管理されたプロパティであり、他のバージョン管理されたプロパティと同様に、マージによって適用される違いには、そのプロパティの変更または追加が含まれる場合があります。

たとえば、mergeinfoがまったくないブランチのワーキングコピーがある場合があります。

1.6.6>svn propget svn:mergeinfo branches/B3.0 -vR

trunkから単一のrevisionをcherry pickします。

1.6.6>svn merge ^/trunk branches/B3.0 -c21
— 'branches/B3.0'にr21をマージしています
UU   branches/B3.0/A/D/gamma

2列目の'U'に注目してください。プロパティの変更はr21の一部であり、ワーキングコピーのステータスを確認するとわかります。

1.6.6>svn status
 M      branches/B3.0
MM      branches/B3.0/A/D/gamma

このブログのトピックを考えると、受信したプロパティの変更がsvn:mergeinfoプロパティに対するものだったことは驚くことではありません。

1.6.6>svn propget svn:mergeinfo branches/B3.0 -vR
'branches/B3.0'のプロパティ
  svn:mergeinfo
    /trunk:21
'branches/B3.0/A/D/gamma'のプロパティ
  svn:mergeinfo
    /branches/B1.0/A/D/gamma:20
    /trunk/A/D/gamma:21

マージソースのdiffを確認すると、r21でtrunk/A/D/gammaにsvn:mergeinfoプロパティが追加されたことがわかります。

1.6.6>svn diff -r20:21 ^/trunk
インデックス: A/D/gamma
===================================================================
— A/D/gamma   (revision 20)
+++ A/D/gamma   (revision 21)
@@ -1 +1 @@
-the new gamma file
+nc

A/D/gammaのプロパティ変更
___________________________________________________________________
追加済み: svn:mergeinfo
   マージ済み /branches/B1.0/A/D/gamma:r20

このような状況は、さまざまな方法で発生する可能性がありますが、通常はサブツリーマージ(つまり、ブランチのルート以下のターゲットを対象とするマージ)が関係し、後で全体ブランチマージ(つまり、ブランチのルートを対象とするマージ)として別のブランチにマージされます。

不足しているサブツリー

残りのケースはすべて、共通点があります。サブツリーmergeinfoは、マージターゲットの一部が「不足」しているために記録されます。さまざまな理由で不足している可能性がありますが、結果として生じるmergeinfoは非常に似ています。

浅いワーキングコピー

浅いワーキングコピー(つまり、無限大以外のdepthに設定されているもの)にマージする場合、サブツリーmergeinfoが作成されます。

たとえば、depth immediatesでブランチのワーキングコピーをチェックアウトするとします。

1.6.6>svn checkout %ROOT_URL%/branches/B2.0–depth immediates
A    B2.0/A
revision 13をチェックアウトしました。

この場合、ブランチにはmergeinfoがまったくありません。

1.6.6>svn propget svn:mergeinfo -vR B2.0

これで、利用可能なすべてのrevisionをtrunkからマージします。浅いチェックアウトのためにワーキングコピーの一部が不足しているため、いくつかのツリーコンフリクトが発生します。

1.6.6>svn merge ^/trunk B2.0
— 'B2.0/A'にr4からr13をマージしています
   C B2.0/A/mu
   C B2.0/A/C
   C B2.0/A/D
コンフリクトのサマリー
  ツリーコンフリクト: 3

また、B2.0/Aに新しいmergeinfoが追加されます。

1.6.6>svn status B2.0
 M      B2.0
 M      B2.0/A
!     C B2.0/A/mu
      >   ローカルが不足、マージ時の着信編集
!     C B2.0/A/C
      >   ローカル削除、マージ時の着信編集
!     C B2.0/A/D
      >   ローカル削除、マージ時の着信編集

1.6.6>svn propget svn:mergeinfo -vR B2.0
'B2.0'のプロパティ
  svn:mergeinfo
    /trunk:4-13
'B2.0/A'のプロパティ
  svn:mergeinfo
    /trunk/A:4-13*

これは、svn:mergeinfoプロパティが継承可能であるためです。ワーキングコピーにB2.0/Aの子が実際にはないため、trunkからr3:13を実際にマージしていません。B2.0/Aの非継承mergeinfo範囲である"/trunk/A:4-13*"は、事実上「このdepthまでtrunkからr3:13をマージしましたが、それ以上はマージしていません」という意味です。

B2.0/Aにこの非継承mergeinfoがない場合、ツリーコンフリクトを解決してこのマージをコミットし、その後別のユーザーがブランチの完全なdepthのワーキングコピーをチェックアウトすると、r3:13がブランチに完全にマージされたように見えますが、明らかにそうではありません。

このタイプのサブツリーmergeinfoは、常に完全なdepthのワーキングコピーにマージする場合に簡単に回避できます。浅いワーキングコピーにマージする必要がある場合は、この動作を念頭に置いて、すべてのサブツリーmergeinfoをコミットしてください。

浅いマージ

浅いワーキングコピーと密接に関連しているのが、浅いマージです。ここでは、マージターゲットのdepthが浅いのではなく、マージコマンドの–depthオプションで指定されたマージ自体のdepthが浅くなります(浅いワーキングコピーに浅いマージを行うこともできます)。

たとえば、ブランチの完全なdepthのワーキングコピーをチェックアウトします。

1.6.6>svn checkout %ROOT_URL%/branches/B2.0/branches/B2.0 B2
A    B2/A
A    B2/A/B
A    B2/A/B/lambda
A    B2/A/B/E
A    B2/A/B/E/alpha
A    B2/A/B/E/beta
A    B2/A/B/F
A    B2/A/mu
A    B2/A/C
A    B2/A/D
A    B2/A/D/gamma
A    B2/A/D/G
A    B2/A/D/G/pi
A    B2/A/D/G/rho
A    B2/A/D/G/tau
A    B2/A/D/H
A    B2/A/D/H/chi
A    B2/A/D/H/omega
A    B2/A/D/H/psi
revision 13をチェックアウトしました。

浅いマージは、要求されたdepthまでしか「降下」しません。この場合、ターゲットの直下の子までです。

1.6.6>svn merge ^/trunk/A B2/A –depth immediates
— 'B2/A/mu'にr4からr13をマージしています
U    B2/A/mu

浅いワーキングコピーへのマージと同様に、マージされた範囲の制限に非継承mergeinfoが設定されます。

1.6.6>svn status B2
M B2
M B2/A/B
M B2/A/mu
M B2/A/C
M B2/A/D

1.6.6>svn propget svn:mergeinfo -vR B2
'B2'のプロパティ
  svn:mergeinfo
    /trunk:4-13
'B2/A/B'のプロパティ
  svn:mergeinfo
/trunk/A/B:4-13*
'B2/A/C'のプロパティ
  svn:mergeinfo
/trunk/A/C:4-13*
'B2/A/D'のプロパティ
  svn:mergeinfo
/trunk/A/D:4-13*

繰り返しますが、これは`--depth infinity`を指定して完全なマージを行うことで回避できます。

切り替えられたサブツリー

マージ対象に切り替えられたサブツリーがある場合、それらのサブツリーは、深さが空であるかのようにほぼ同じように扱われます。主な違いは、その時点から下位は完全なワーキングコピーを持っているため(切り替えられたサブツリー内の切り替えられたサブツリー、または浅い切り替えられたサブツリーなどを除く)、マージは切り替えられたサブツリーのルートに通常の継承可能なmergeinfoを記録することです。

承認制限

"サブツリーが見つからない"というもう一つのケースは、完全な読み取りアクセス権を持っていないワーキングコピーにマージする場合です。これも、見つからないサブツリーの周囲に継承不可能なmergeinfoが追加されます。これは稀な発生だと推測されますが、マージ後に突然サブツリーのmergeinfoが表示され、上記の理由が当てはまらない場合は、これが原因である可能性があります。

* mergeinfoの省略についてよく分からない場合は、こちらをご覧ください。http://www.open.collab.net/community/subversion/articles/merge-info.html

著者について

Paul Burbaは、Apache Software FoundationのSubversionプロジェクトのコミッターであり、過去9年間Subversionに取り組んできました。彼はニューハンプシャー州の自宅でCollabnetのソフトウェアエンジニアとして働いており、コーディングをしていないときは、通常、甥っ子とスキーをしたり、友人とマウンテンバイクに乗ったり、妻と旅行したりしています。昔々、Paulはニューハンプシャー大学を卒業し、経営学の学位を取得しました。もっと最近では、ボストン大学でコンピュータサイエンスの修士号を取得しました。