この記事は、元の場所 https://www.open.collab.net/community/subversion/articles/merge-info.html から許可を得てミラーリングされています。無効なリンクは削除または更新されています。
著者: Paul Burba
概要: Subversion のマージ追跡機能の内部構造を理解します。
投稿 2008-05-06
この記事は、Subversion の本の第 4 章で扱われているトピックに関する基本的な知識、または Subversion 1.5 のある程度の経験(open.collab.net で入手可能な早期採用者向けの 1.5 バイナリ、または 1.5.0 リリース候補のいずれか)を前提としています。この記事の例は、リリース候補 4 を使用して作成されました。2008 年 5 月 6 日現在、最新の RC は Subversion 1.5.0 リリース候補 5 です。
Mergeinfo、より具体的にはバージョン管理されたプロパティ svn:mergeinfo
は、特定のファイルまたはディレクトリに対して行われたマージの履歴です。この記事では、mergeinfo について詳しく説明します。その意味と仕組みについてです。
svn:mergeinfo
プロパティの値は、改行で区切られたマージ元パスのリスト(リポジトリルートを基準とした相対パス)です。各ソースパスはコロンで続き、コロンの後に、そのソースから以前にマージされたリビジョンのリストが続きます。正確な文法について知りたい場合は、Subversion のコードに記述されています。svn_mergeinfo.h のコメント「@c SVN_PROP_MERGEINFO プロパティの概要」を参照してください。
注: この記事は長く、多くの特殊なユースケースを網羅しています。そのため、Subversion の本で説明されている「同期と再統合」のパラダイムに従う場合は、この記事の大部分は不要かもしれません。その場合は、「明示的な Mergeinfo の継承」までの最初の数セクションを読み、その後「結び」セクションにスキップすることをお勧めします。
パスに svn:mergeinfo
プロパティが設定されている場合、そのパスは明示的な mergeinfo を持つと言われます。明示的な mergeinfo は、通常、マージのワーキングコピーのターゲット(ここでは単にマージターゲットと呼びます)で作成(または既に存在する場合は変更)されます。「通常」と言うのは、マージによって mergeinfo が設定または変更されない場合もあるためです。「Mergeinfo はどこにあるのか?」セクションを参照してください。
明示的な mergeinfo は、マージターゲットのサブツリーにも作成または変更される場合があります。通常、これらのサブツリーは、それ自体がかつてマージターゲットであったため、マージ前に明示的な mergeinfo を持っています。ただし、マージ前に明示的な mergeinfo がなかったサブツリーに mergeinfo が作成される場合もあります。「Mergeinfo の継承と継承不可能な範囲」セクションを参照してください。
それでは、実例として Subversion 自身の 1.5.x ブランチのワーキングコピーを見てみましょう。このブランチは、1.5 のリリース準備のために分岐した trunk のコピーです。作成後すぐに、trunk からブランチへの変更のマージ(つまり、チェリーピック)を開始します。
>svn info \svn\src-1.5.x
Path: \SVN\src-1.5.x
URL:http://svn.collab.net/repos/svn/branches/1.5.x
Repository Root:
http://svn.collab.net/repos/svn
Repository UUID: 612f8ebc-c883-4be0-9ee0-a4e9ef946e3a
Revision: 30056
Node Kind: directory
Schedule: normal
Last Changed Author: hwright
Last Changed Rev: 30056
Last Changed Date: 2008-03-26 00:32:28 -0400 (Wed, 26 Mar 2008)
>svn pg svn:mergeinfo \svn\src-1.5.x –recursive
\SVN\src-1.5.x - /trunk:29085-29089,29091,29094-29107,29111,29114,29117,29126-29127, 29129-29133,29135-29150,29153-29164,29166,29174,29176-29186,29188-29189, 29193-29194,29198-29200,29202-29206,29208-29251,29254-29256,29261, 29267-29273,29277,29280-29281,29284,29287-29303,29305-29307,29309-29325, 29327-29343,29345-29348,29358-29379,29381-29392,29397,29399,29401,29409, 29412,29414-29415,29417-29423,29425-29426,29429,29433-29434,29436-29447, 29449-29466,29468-29478,29482,29484,29486-29487,29489,29491,29493,29496, 29498,29508,29527-29528,29531,29533,29539-29540,29542,29544,29546,29551, 29553,29556,29559,29565,29567-29569,29571-29578,29581,29583,29591,29594, 29600,29603,29607,29611,29613-29614,29619,29623,29625-29626,29630-29631, 29634,29642,29648,29650,29656,29659-29660,29663-29664,29671-29672, 29677-29680,29692,29738-29739,29742-29744,29746,29751,29763,29769-29770, 29784,29787,29797,29801,29821,29824,29828,29835,29855,29868-29869,29878, 29883-29884,29895,29898,29900,29914,29920,29925,29930,29940,29950,29958, 29962,29968,29980,29994-29997,30004,30020注: これらの例では、バックスラッシュの付いたパスの多さが目につきます。モニターの調整や眼科医への予約は不要です…はい、私は Windows で Subversion の開発を行っています。
上記の例では、マージ元パスは /trunk のみであり、その後ろに、1.5.x ブランチに以前にマージされたリビジョンのリストが続きます。多くの Subversion サブコマンドで使用される familiar -rX:Y 表記とは異なり、svn:mergeinfo のバージョン範囲は A-B 形式を使用し、リビジョン A は包含的です。つまり、-r3:7 をマージする場合は、範囲 4-7 を持つ mergeinfo が表示されることを期待してください。
特定のソースの svn:mergeinfo
プロパティにリストされているすべてのリビジョンが、そのソースで有効とは限らないことに注意することが重要です。上記の例では、1.5.x ブランチの mergeinfo に r29093:29107 が trunk からマージされたことが示されています。しかし、r29095 のログを見ると、trunk に影響を与える変更ではないことがわかります。
>svn log
http://svn.collab.net/repos/svn/trunk
-v -r29095
------------------------------------------------------------------------
>
では、なぜ r29095 が 1.5.x の mergeinfo に含まれているのでしょうか?これは、ある時点で誰かが trunk から 1.5.x にリビジョンの範囲 -rX:Y をマージし、X < 29095 <= Y となったためです。開発コミュニティは、このような場合、無効なリビジョンについても mergeinfo を記録することに決定しました。これにより、mergeinfo プロパティが断片化されにくくなり、人間の目にとって扱いやすくなります。1.5.x の mergeinfo を見ると、「何の意味があるのか?すでにかなり断片化されている!」と思うかもしれません。そして、それは正しいです。1.5.x はリリースブランチですが、他のユースケース、たとえば最終的に trunk に再統合されるフィーチャブランチなどでは、この動作により、mergeinfo をきれいに整理し、多くの場合、単一の範囲にすることができます。
マージによって mergeinfo が作成または変更されない場合がいくつかあります。
--ignore-ancestry
オプションを使用する場合。さらに、このオプションを使用するマージでは、マージするものを決定する際に mergeinfo は考慮されません。
>svn co %url% wc
A wc\A
A wc\A\B
A wc\A\B\lambda
A wc\A\B\E
A wc\A\B\E\alpha
A wc\A\B\E\beta
A wc\A\B\F
A wc\A\mu
A wc\A\C
A wc\A\D
A wc\A\D\gamma
A wc\A\D\G
A wc\A\D\G\pi
A wc\A\D\G\rho
A wc\A\D\G\tau
A wc\A\D\H
A wc\A\D\H\chi
A wc\A\D\H\omega
A wc\A\D\H\psi
A wc\iota
Revision 1 をチェックアウトしました。このワーキングコピーには mergeinfo がありません。
>svn pg svn:mergeinfo wc -R
>次に、単純なテキスト変更を行い、r2 としてコミットします。
>echo 'text change to a file' > wc\A\mu
>svn ci -m "" wc
送信中 wc\A\mu
ファイルデータの送信中。
Revision 2 をコミットしました。しまった、その変更は不要だと気づき、r2 をそれ自体から逆マージします。Subversion では、mergeinfo の設定に関係なく、常にこのタイプのマージを実行できます。
>svn merge %url%/A/mu wc/A/mu -c-2
--- 'wc\A\mu' に r2 を逆マージしています。
U wc\A\mu現在の mergeinfo の実装では逆マージを表す方法がないため、前のマージでは mergeinfo の証拠が残されません。
>svn pg svn:mergeinfo wc -R
>そして、mergeinfo を設定または変更しないマージができました。
Subversion の 1.5.x ブランチのワーキングコピーの mergeinfo をもう一度見てみましょう。--recursive
オプションに注目してください。これは、\SVN\src-1.5.x をルートとするワーキングコピーツリー全体に設定されているすべての svn:mergeinfo プロパティのリストを取得することを意味します。しかし、表示される明示的な mergeinfo は、\SVN\src-1.5.x に設定されているものだけです。trunk から \SVN\src-1.5.x への多数のマージは、\SVN\src-1.5.x のサブツリーに影響を与えているはずです。trunk から最近マージされたリビジョンを選択すると、これが確認できます。
>svn log -v -q -c30020
http://svn.collab.net/repos/svn/trunk
------------------------------------------------------------------------
r30020 | pburba | 2008-03-24 11:15:48 -0400 (Mon, 24 Mar 2008)
変更されたパス:
M /trunk/subversion/libsvn_client/copy.c
------------------------------------------------------------------------
\SVN\src-1.5.x\subversion\libsvn_client\copy.c が trunk の r30020 がマージされたことをどのように「知っている」のでしょうか?それは、mergeinfo の継承によって知っています。パスに明示的な svn:mergeinfo がなくても、明示的な mergeinfo を持つ親(または祖父母、曽祖父母など)があれば、継承された mergeinfo を持つことができます。
「最も近い親」という概念は、ワーキングコピーに限定されません。明示的な mergeinfo を持たないパスの継承された mergeinfo を決定する際、Subversion はまず、明示的な mergeinfo を持つ親を検索するために、ワーキングコピーを可能な限り上方に辿ります。ワーキングコピーの一番上まで到達してもそのような親が見つからない場合、次にリポジトリに対して他の親パスを問い合わせ、必要であればリポジトリのルートまで遡ります。リポジトリ内で継承可能な mergeinfo が見つからない場合にのみ、そのパスはmergeinfo を全く持たないと最終的に言えます(そして、次のセクションで説明するように、時にはそれすら言えないこともあります)。
\SVN\src-1.5.x\subversion\libsvn_client\copy.c をもう一度見て、継承の具体的な例を見てみましょう。\SVN\src-1.5.x の mergeinfo から、trunk の r30020 のマージがこのファイルを変更するはずだと分かっていますが、copy.c 自身には明示的な mergeinfo がないことも分かっています。しかし、copy.c の明示的な mergeinfo を持つ最も近い親が \SVN\src-1.5.x であることも分かっているので、mergeinfo の継承により、copy.c の継承された mergeinfo は \SVN\src-1.5.x のものと等しくなります。
残念ながら、コマンドラインから直接これを見る簡単な方法はありません。1.5 は新しい svn mergeinfo サブコマンドを提供していますが、1.5 では、指定されたソースから以前にマージされた(またはマージの対象となる)リビジョンの一覧のみを提供します。
>svn mergeinfo --show-revs merged http://svn.collab.net/repos/svn/trunk/subversion/libsvn_client/copy.c\svn\src-1.5.x\subversion\libsvn_client\copy.c
r229
r282
r316
r326
r380
.
.
<多くのリビジョンを省略>
.
.
r28472
r28512
r28825
r29374
r30020
ご覧のとおり、出力は各リビジョンが個別にリストされているため、スクリプトへの入力として意図されています。また、svn:mergeinfo
とは異なり、有効なリビジョンのみがリストされています。前述の出力にリストされている各リビジョンは、実際には http://svn.collab.net/repos/svn/trunk/subversion/libsvn_client/copy.c を変更しています。
mergeinfo の継承を暗黙的に見る方が簡単です。1.5.x ワーキングコピーの copy.c に2つのリビジョンを直接マージしてみましょう。そのリビジョンの1つは r30020 ですが、copy.c の継承された mergeinfo によって既にマージされていることが示されているため、無視されるはずです。マージの対象となる別の有効なリビジョンを見つけるには、svn mergeinfo を再度使用しますが、今回は --show-revs eligible オプションを使用します。
>svn mergeinfo --show-revs eligible
http://svn.collab.net/repos/svn/trunk/subversion/libsvn_client/copy.c\svn\src-1.5.x\subversion\libsvn_client\copy.c
r29167
r29961
それでは、r29167 と r30020 を copy.c にマージしてみましょう(1.5 では、マージの -c
オプションを使用して複数のリビジョンを指定できることに注意してください)。
>svn merge -c29167,30020
http://svn.collab.net/repos/svn/trunk/subversion/libsvn_client/copy.c\svn\src-1.5.x\subversion\libsvn_client\copy.c
--- Merging r29167 into '\SVN\src-1.5.x\subversion\libsvn_client\copy.c':
U \SVN\src-1.5.x\subversion\libsvn_client\copy.c
Subversion の書籍から、1.5 のマージ追跡の主要な機能の1つは、マージの重複を回避することです。上記の出力を参照すると、Subversion は copy.c の継承された mergeinfo に基づいて、リビジョン r30020 が既にマージされていることを認識したため、r29167 のみをマージしようとしました。
これで、明示的な mergeinfo と mergeinfo の継承の基本の大部分は網羅されました。より高度なトピックに移る前に、mergeinfo と継承について常に心に留めておくべき点が2つあります。
まず、パスに明示的な mergeinfo がある場合、その mergeinfo はそのパスに対して行われたマージを完全に記述しており、パスは他の場所から何も継承しません。つまり、継承はパスに明示的な mergeinfo がない場合にのみ有効になります。
第二に、これはおそらく非常に明白ですが、強調する価値があります。パスが mergeinfo を継承する場合、それは明示的な mergeinfo を持つ最も近い親からのみ継承されます。したがって、次の mergeinfo を持つワーキングコピーがあるとします。
>svn pg svn:mergeinfo -R src-branch
src-branch\subversion - /trunk/subversion:30045-30191,30210
src-branch - /trunk:30045-30197
src-branch\www - /trunk/www:30045-30212
ファイル src-branch\subversion\libsvn_repos\reporter.c はどのような mergeinfo を継承するでしょうか?src-branch\www には mergeinfo がありますが、それは reporter.c の親パスではありません。src-branch には mergeinfo があり、それは reporter.c の親ですが、src-branch\subversion というより近い親があります。そのため、reporter.c はそこから mergeinfo を取得します。
パスの明示的な mergeinfo や継承された mergeinfo に関係なく、すべてのパスには自然な履歴があり、Subversion はこれを暗黙的な mergeinfo とみなします。正直に言って、これは一般的なユーザーが理解する必要のあるものではないため、概要だけを探している場合は、このトピックをスキップしても安全です。
それでもここにいますか?それでは、Subversion の開発者の1人が作業している機能ブランチのワーキングコピーをチェックアウトして、暗黙的な mergeinfo がどのように機能するかを見てみましょう。
>svn co http://svn.collab.net/repos/svn/branches/in-memory-cache mem-cache-wc -q
いくつかの log サブコマンドを実行することで、このブランチが最近、r29755 の Subversion の trunk のコピーから作成されたことが分かります。
>svn log --stop-on-copy -q mem-cache-wc
------------------------------------------------------------------------
r30314 | glasser | 2008-04-04 19:08:12 -0400 (Fri, 04 Apr 2008)
------------------------------------------------------------------------
r30313 | glasser | 2008-04-04 19:07:41 -0400 (Fri, 04 Apr 2008)
------------------------------------------------------------------------
r30312 | glasser | 2008-04-04 19:06:14 -0400 (Fri, 04 Apr 2008)
------------------------------------------------------------------------
.
.
<出力を簡潔にするために一部を省略>
.
.
------------------------------------------------------------------------
r29775 | glasser | 2008-03-07 13:57:45 -0500 (Fri, 07 Mar 2008)
------------------------------------------------------------------------
r29773 | glasser | 2008-03-07 13:23:54 -0500 (Fri, 07 Mar 2008)
------------------------------------------------------------------------
r29755 | glasser | 2008-03-06 19:46:43 -0500 (Thu, 06 Mar 2008)
------------------------------------------------------------------------
>svn log -v -r29755 mem-cache-wc
------------------------------------------------------------------------
r29755 | glasser | 2008-03-06 19:46:43 -0500 (Thu, 06 Mar 2008) | 14 lines
変更されたパス
A /branches/in-memory-cache (from /trunk:29754)
<実際のログメッセージを省略>
------------------------------------------------------------------------
それでは、ブランチの mergeinfo を見てみましょう。
>svn pg svn:mergeinfo -R mem-cache-wc
mem-cache-wc - /branches/svn-mergeinfo-enhancements:30045-30214
/trunk:29755-30312
/trunk からの mergeinfo は r29755 から始まっていることに注目してください。r29754 より前のリビジョンをマージしようとしたらどうなるでしょうか?Subversion は in-memory-cache 自身の履歴からそれらの変更をマージしようとしますか?試してみましょう。通常の機能ブランチの trunk との同期ではリビジョン範囲を指定しませんが、ここでは明示的に範囲を設定してみます。
>svn merge
http://svn.collab.net/repos/svn/trunk
mem-cache-wc -r23000:HEAD
--- Merging r30313 through r30422 into 'mem-cache-wc':
U mem-cache-wc\COMMITTERS
U mem-cache-wc\subversion\libsvn_fs_base\tree.c
U mem-cache-wc\subversion\libsvn_fs_base\bdb\node-origins-table.c
.
.
<snip>
.
.
U mem-cache-wc\contrib\client-side\svnmucc\svnmucc-test.py
U mem-cache-wc\configure.ac
G mem-cache-wc
通知を見てください。Subversion は r30313 以降のみのマージを試みました。既に見てきたことから、r29754:30312 の範囲は明示的な mergeinfo に既に含まれているため、Subversion がマージを試みないことを期待しています。しかし、-r23000:29754 はどうでしょうか?Subversion がそれらのリビジョンをマージしようとしないのはなぜでしょうか?答えは、/branches/in-memory-cache の暗黙的な mergeinfo にあります。/branches/in-memory-cache は r29755 で /trunk からコピーされたため、前者はコピーとして、r29754 以前から /trunk と履歴を共有しています。Subversion は、trunk からマージするものを決定する際に、この「自然な」履歴を暗黙的な mergeinfo とみなします。事実上、これは /branches/in-memory-cache が明示的な mergeinfoに加えて、暗黙的な mergeinfo "/trunk:1-29754" を持っていることを意味します。また、マージ後、in-memory-cache ブランチの mergeinfo には "/trunk:30313-30422" のみが追加されていることにも注目してください(パスの独自の履歴を記述する mergeinfo は冗長であるため)。
>svn pg svn:mergeinfo -R mem-cache-wc
mem-cache-wc - /branches/1.5.x-r30215:30238
/trunk:29755-30422
Subversion では、リポジトリの不完全な表現であるワーキングコピーを使用できます。これは、浅いチェックアウト、切り替えられたサブツリー、またはツリーの一部をチェックアウトできない承認制限のために可能です。必要に応じて不完全なツリーにマージできます。Subversion は mergeinfo を正確に維持しようとします。これは主に、継承不可能な mergeinfo 範囲によって行われます。これらがどのように機能するかを示す最も簡単な方法は、例を使用することです。
まず、Subversion 1.5.x ブランチの浅いチェックアウトを行うことで、不完全なワーキングコピーを作成します。
注:--depth オプションも 1.5 で新しく、Subversion サブコマンドの操作をターゲットのワーキングコピーまたは URL 内の特定の深さに制限します。ここでは 'immediates' 値を使用しており、1.5.x ブランチのルートと、ルートの直下のファイルまたはディレクトリの各子のみを取得します。
>svn co
http://svn.collab.net/repos/svn/branches/1.5.x@30435
1.5.x --depth immediates
A 1.5.x\Makefile.in
A 1.5.x\STATUS
A 1.5.x\build.conf
A 1.5.x\www
A 1.5.x\win-tests.py
A 1.5.x\COMMITTERS
A 1.5.x\TRANSLATING
A 1.5.x\notes
A 1.5.x\README
A 1.5.x\subversion
A 1.5.x\build
A 1.5.x\tools
A 1.5.x\BUGS
A 1.5.x\contrib
A 1.5.x\configure.ac
A 1.5.x\HACKING
A 1.5.x\doc
A 1.5.x\INSTALL
A 1.5.x\COPYING
A 1.5.x\CHANGES
A 1.5.x\autogen.sh
A 1.5.x\gen-make.py
A 1.5.x\aclocal.m4
A 1.5.x\packages
U 1.5.x
Checked out revision 30435.
これで、'subversion' ディレクトリの深さを変更して、サブツリー全体が存在するようにします。
注:ここでは、1.5 で新しく追加された --set-depth オプションを使用します。--depth は基本的にサブコマンド全般に対する制限であるのに対し、--set-depth は更新のための積極的な操作です。ここでは 'infinity' 値を使用して、1.5.x\subversion サブツリーを最大限に展開します。
>svn up 1.5.x\subversion --set-depth infinity --quiet
1.5.x ブランチにある mergeinfo を見てみましょう。
>svn pg svn:mergeinfo -R 1.5.x
1.5.x\CHANGES - /branches/1.5.x-r30215/CHANGES:30236,30238,30245,30288
/branches/svn-mergeinfo-enhancements/CHANGES:30122
/trunk/CHANGES:29085-29089,29091,29094-29107,29111,29114,29117,29126-29127,29129-29133,29135-29150,29153-29164,29166-29170,29174,29176-29186,29188-29189,29193-29194,29198-29206,29208-29251,29254-29256,29261,29267-29273,29277,29280-29281,29284,29287-29303,29305-29307,29309-29343,29345-29348,29358-29379,29381-29392,29397,29399,29401,29409,29412,29414-29415,29417-29423,29425-29426,29429,29433-29434,29436-29447,29449-29466,29468-29478,29482,29484,29486-29487,29489,29491,29493,29496,29498,29508,29527-29528,29531,29533,29539-29540,29542,29544,29546,29551,29553,29556,29559,29565,29567-29569,29571-29578,29581,29583,29591,29594,29600,29603,29607,29611,29613-29614,29619,29623,29625-29626,29630-29631,29633-29634,29642,29645,29648,29650,29656,29659-29660,29663-29666,29671-29672,29677-29680,29692,29738-29739,29741-29744,29746,29751,29763,29767,29769-29770,29784,29786-29787,29797,29801,29815,29821,29824,29828,29835,29852,29854-29855,29857-29859,29868-29869,29876,29878,29883-29884,29895,29898,29900,29914,29920,29922,29925,29930,29939-29940,29942,29950,29958,29962,29965,29967-29968,29980,29986,29994-29997,30004,30009,30020,30030,30050,30053-30054,30059,30061-30062,30067,30070,30074,30086,30098,30101,30112,30117,30124,30129-30130,30137,30145,30151,30159,30161-30162,30180-30181,30185,30210,30233,30237,30239,30246,30249,30256,30278-30279,30281,30285,30297,30299,30304,30319-30321,30328,30335-30336,30340,30342,30347,30362,30368,30373,30375,30378,30380,30392,30402,30407-30409,30412
1.5.x - /trunk:29085-29089,29091,29094-29107,29111,29114,29117,29126-29127,29129-29133,29135-29150,29153-29164,29166-29170,29174,29176-29186,29188-29189,29193-29194,29198-29206,29208-29251,29254-29256,29261,29267-29273,29277,29280-29281,29284,29287-29303,29305-29307,29309-29343,29345-29348,29358-29379,29381-29392,29397,29399,29401,29409,29412,29414-29415,29417-29423,29425-29426,29429,29433-29434,29436-29447,29449-29466,29468-29478,29482,29484,29486-29487,29489,29491,29493,29496,29498,29508,29527-29528,29531,29533,29539-29540,29542,29544,29546,29551,29553,29556,29559,29565,29567-29569,29571-29578,29581,29583,29591,29594,29600,29603,29607,29611,29613-29614,29619,29623,29625-29626,29630-29631,29633-29634,29642,29645,29648,29650,29656,29659-29660,29663-29666,29671-29672,29677-29680,29692,29738-29739,29741-29744,29746,29751,29763,29767,29769-29770,29784,29786-29787,29797,29801,29815,29821,29824,29828,29835,29852,29854-29855,29857-29859,29868-29869,29876,29878,29883-29884,29895,29898,29900,29914,29920,29922,29925,29930,29939-29940,29942,29950,29958,29962,29965,29967-29968,29980,29986,29994-29997,30004,30009,30020,30030,30050,30053-30054,30059,30061-30062,30067,30070,30074,30086,30098,30101,30117,30124,30129-30130,30137,30145,30151,30159,30161-30162,30180-30181,30185,30210,30233,30237,30239,30246,30249,30256,30278-30279,30281,30285,30297,30299,30304,30319-30321,30328,30335-30336,30340,30342,30347,30362,30368,30373,30375,30378,30380,30392,30402,30407-30409,30412
1.5.x\CHANGESには、直接マージが行われています(つまり、かつてはマージの対象でした)。そのため、独自の明示的なmergeinfoを持っていることに注意してください。1.5.xへのマージを行う際には、1.5.x\CHANGESを異なるmergeinfoを持つサブツリーとして参照します。これらのサブツリーについては後で詳しく説明します。
それでは、trunkからこのワーキングコピーにいくつかの変更をマージしてみましょう。一度にtrunkから2つのリビジョンをマージします。1つのリビジョンは、存在するワーキングコピーの一部を変更し、もう1つは、スパースチェックアウトのために存在しないパスに変更を加えようとします。
使用する特定のリビジョンはr30431とr30435です。
>svn log --verbose --quiet -r30430:30435
http://svn.collab.net/repos/svn/trunk
------------------------------------------------------------------------
r30431 | epg | 2008-04-07 19:40:11 -0400 (Mon, 07 Apr 2008)
変更されたパス
M /trunk/subversion/tests/cmdline/changelist_tests.py
------------------------------------------------------------------------
r30435 | julianfoad | 2008-04-08 09:56:02 -0400 (Tue, 08 Apr 2008)
変更されたパス
A /trunk/notes/tree-conflicts/policy.txt
------------------------------------------------------------------------
それでは、マージを実行しましょう。
注記: ここでは`--depth infinity`を使用することで、存在する1.5.xの子ノードにも強制的にマージします。元の浅いチェックアウトのため、1.5.xの深さは「直下」であり、マージ操作の深さはマージ対象の深さをデフォルト値としています。無限の深さを指定しなかった場合、Subversionはr30435のマージを試行しません。
>svn merge --depth infinity
http://svn.collab.net/repos/svn/trunk
1.5.x -r30430:30435
Skipped missing target: '1.5.x\notes\tree-conflicts\policy.txt'
Skipped missing target: '1.5.x\notes\tree-conflicts'
--- Merging r30431 through r30435 into '1.5.x':
U 1.5.x\subversion\tests\cmdline\changelist_tests.py
スパースワーキングコピーのため、1.5.x\notes\tree-conflictsと1.5.x\notes\tree-conflicts\policy.txtが存在しないため、r30435のマージを試行した際にスキップされます。しかし、1.5.x\subversion\tests\cmdline\changelist_tests.pyは存在するため、r30431からの変更はそのファイルにマージされます。
それでは、現在の1.5.xに存在するmergeinfoを見てみましょう。
>svn pg svn:mergeinfo 1.5.x
/trunk:29085-29089,29091,29094-29107,29111,29114,29117,29126-29127,29129-29133,29135-29150,29153-29164,29166-29170,29174,29176-29186,29188-29189,29193-29194,29198-29206,29208-29251,29254-29256,29261,29267-29273,29277,29280-29281,29284,29287-29303,29305-29307,29309-29343,29345-29348,29358-29379,29381-29392,29397,29399,29401,29409,29412,29414-29415,29417-29423,29425-29426,29429,29433-29434,29436-29447,29449-29466,29468-29478,29482,29484,29486-29487,29489,29491,29493,29496,29498,29508,29527-29528,29531,29533,29539-29540,29542,29544,29546,29551,29553,29556,29559,29565,29567-29569,29571-29578,29581,29583,29591,29594,29600,29603,29607,29611,29613-29614,29619,29623,29625-29626,29630-29631,29633-29634,29642,29645,29648,29650,29656,29659-29660,29663-29666,29671-29672,29677-29680,29692,29738-29739,29741-29744,29746,29751,29763,29767,29769-29770,29784,29786-29787,29797,29801,29815,29821,29824,29828,29835,29852,29854-29855,29857-29859,29868-29869,29876,29878,29883-29884,29895,29898,29900,29914,29920,29922,29925,29930,29939-29940,29942,29950,29958,29962,29965,29967-29968,29980,29986,29994-29997,30004,30009,30020,30030,30050,30053-30054,30059,30061-30062,30067,30070,30074,30086,30098,30101,30117,30124,30129-30130,30137,30145,30151,30159,30161-30162,30180-30181,30185,30210,30233,30237,30239,30246,30249,30256,30278-30279,30281,30285,30297,30299,30304,30319-30321,30328,30335-30336,30340,30342,30347,30362,30368,30373,30375,30378,30380,30392,30402,30407-30409,30412,**30431-30435**
/trunkからの-r30430:30435が1.5.xのmergeinfoに追加されたことがわかります。これは理にかなっています。マージで要求した範囲です!また、「mergeinfoにおける無効なリビジョンと有効なリビジョン」のセクションで説明されているように、r30432、r30433、r30434は、trunkではすべて無効なリビジョンですが、mergeinfoには記録されている点にも注意してください。
ここで、「良いですね、でもこの変更をコミットした後、別のユーザーが完全な1.5.xワーキングコピーをチェックアウトしたらどうなるのでしょうか?notes\tree-conflicts\policy.txtのコピーは、ルートからr30430:30435を誤って継承しませんか?そのファイルはマージで実際には変更されていません!」と考えているかもしれません。それは完全に正しいのですが、私は前にワーキングコピーのルートのmergeinfoしか見ていないため、少し誤解を招く表現でした。もう少し詳しく見て、ワーキングコピーのステータスを確認しましょう。
>svn st 1.5.x
M 1.5.x
M 1.5.x\www
M 1.5.x\notes
M 1.5.x\build
M 1.5.x\subversion\tests\cmdline\changelist_tests.py
M 1.5.x\contrib
M 1.5.x\tools
M 1.5.x\doc
M 1.5.x\CHANGES
M 1.5.x\packages
明らかに、Subversionはマージ中に通知された以上のことを行っています。なぜなら、depth emptyでチェックアウトされている1.5.xの子ノードごとにプロパティの変更があるからです。では、それらのプロパティの変更とは一体何でしょうか?`svn diff`を使って1つ見てみましょう。
>svn diff 1.5.x\www
Property changes on: 1.5.x\www
___________________________________________________________________
Added: svn:mergeinfo
Merged /trunk/www:r29085-29089,29091,29094-29107,29111,29114,29117,29126-29127,29129-29133,29135-29150,29153-29164,29166-29170,29174,29176-29186,29188-29189,29193-29194,29198-29206,29208-29251,29254-29256,29261,29267-29273,29277,29280-29281,29284,29287-29303,29305-29307,29309-29343,29345-29348,29358-29379,29381-29392,29397,29399,29401,29409,29412,29414-29415,29417-29423,29425-29426,29429,29433-29434,29436-29447,29449-29466,29468-29478,29482,29484,29486-29487,29489,29491,29493,29496,29498,29508,29527-29528,29531,29533,29539-29540,29542,29544,29546,29551,29553,29556,29559,29565,29567-29569,29571-29578,29581,29583,29591,29594,29600,29603,29607,29611,29613-29614,29619,29623,29625-29626,29630-29631,29633-29634,29642,29645,29648,29650,29656,29659-29660,29663-29666,29671-29672,29677-29680,29692,29738-29739,29741-29744,29746,29751,29763,29767,29769-29770,29784,29786-29787,29797,29801,29815,29821,29824,29828,29835,29852,29854-29855,29857-29859,29868-29869,29876,29878,29883-29884,29895,29898,29900,29914,29920,29922,29925,29930,29939-29940,29942,29950,29958,29962,29965,29967-29968,29980,29986,29994-29997,30004,30009,30020,30030,30050,30053-30054,30059,30061-30062,30067,30070,30074,30086,30098,30101,30117,30124,30129-30130,30137,30145,30151,30159,30161-30162,30180-30181,30185,30210,30233,30237,30239,30246,30249,30256,30278-30279,30281,30285,30297,30299,30304,30319-30321,30328,30335-30336,30340,30342,30347,30362,30368,30373,30375,30378,30380,30392,30402,30407-30409,30412,**30431-30435***
1.5.x\wwwには、/trunk/wwwからのマージを記述する明示的なmergeinfoがあります。注意深く見ると、リビジョン自体は1.5.xのものと同一ですが、重要な例外が1つあります。このマージで1.5.xに追加されたr30430:30435の範囲には、1.5.x\wwwに対して「*」接尾辞が付いています。この「*」は、継承されないmergeinfo範囲のマーカーです。「*」は、mergeinfoが明示的に設定されているパスのみが、この範囲をマージされたことを意味します。
ここでは詳細には説明しませんが、1.5.xの空の子ノードそれぞれに、独自の明示的なmergeinfoが作成されます。このmergeinfoは、マージ前の空の子ノードが1.5.xから継承したmergeinfoと、それらのリビジョンが空の子ノードまでしかマージされなかったことを示す30431-30435*という追加部分の組み合わせです。
この変更をコミットし、別のユーザーが1.5.xブランチの完全な`--depth infinity`チェックアウトを実行した場合、notes\tree-conflicts\policy.txtのコピーは、notesからのすべてのmergeinfoを継承しますが、30431-30435は除きます。これは、それらのリビジョンがpolicy.txtに実際にはマージされていないため、良いことです。
Subversionがマージターゲットのサブツリーにアクセスできない場合にも、同様のプロセスが発生します。サブツリーは、別のURLに切り替えられている場合、またはディスク上に存在しない場合にアクセスできません。後者は、上記の浅いワーキングコピーが原因である場合もあれば、承認制限が原因である場合もあります。サブツリーが存在しない理由にかかわらず、Subversionは常に上記のような処理を試みます。
注記: 切り替えられているために欠落しているサブツリーは、ここで説明したものよりもさらに複雑です。切り替えられたパス自体にも明示的なmergeinfoが設定されるためです。ただし、これは今後の記事で説明します。
通常、ほとんどのユーザーは、サブツリーが欠落しているターゲットにマージすることはありませんが、必要であれば、Subversionは各パスの明示的/継承されたmergeinfoが、そのパスにマージされたもののみを正確に反映するように試行することを安心してください。
空のmergeinfoとは、空の文字列を値として持つsvn:mergeinfoプロパティです。「このパスの状態は、何もマージされていない状態と同じです」ということを意味します。空のmergeinfoは、通常、ワーキングコピー間での移動またはコピー(今後のSubmerged投稿の主題)を行う場合、またはサブツリーから以前のすべてマージを逆マージする場合に発生します。後者の例を見てみましょう。
現在の作業ディレクトリは単純なブランチです。
>svn ls -R .
B/
B/E/
B/E/alpha
B/E/beta
B/F/
B/lambda
C/
D/
D/G/
D/G/pi
D/G/rho
D/G/tau
D/H/
D/H/chi
D/H/omega
D/H/psi
D/gamma
mu
mergeinfoを見ると、いくつかのリビジョンが既にこのブランチにマージされていることがわかります。
>svn pl -vR .
Properties on '.'
svn:mergeinfo : /A:2-6
ブランチのサブツリーからそれらのリビジョンをすべて逆マージするとどうなるでしょうか?
>svn merge %url92%/A/D/H .\D\H -r6:1
--- Reverse-merging r6 through r2 into 'D\H'
U D\H\omega
U D\H\psi
>svn pl -vR .
Properties on '.'
svn:mergeinfo : /A:2-6
Properties on 'D\H'
svn:mergeinfo
空のmergeinfoになります。.\D\Hに明示的な空のmergeinfoがない場合、'.'から/A/D/H:2-6のmergeinfoを誤って継承します。
Subversionは、すべてのマージの最後に、冗長なサブツリーmergeinfoを「統合」しようとします。この統合プロセスは、省略と呼ばれます。マージが完了すると、Subversionはマージターゲットをルートとするワーキングコピーツリーを走査します。明示的なmergeinfoを持ち、同等の明示的なmergeinfoを持つサブツリーを持つパスが見つかった場合、サブツリーのmergeinfoは省略(削除)されます。「同等性」は次のように定義されます。
言い換えれば、サブツリーのmergeinfoを削除しても安全です。サブツリーのmergeinfoが、明示的なmergeinfoを持つ最も近い親と同等である場合、その親からサブツリーが継承するmergeinfoは、既にサブツリーへのマージを記述するのに十分だからです。mergeinfoの継承と省略は、同じものの異なる見方であることが今では明らかになっているでしょう。継承とは、mergeinfoが親から子へツリーを「下って」いくことであり、省略とは、mergeinfoが子から親へツリーを「上って」いくことです。
理論はさておき、実際に省略を見てみましょう。この例では、現在のSubversionフィーチャーブランチのワーキングコピーをチェックアウトします。
>svn co http://svn.collab.net/repos/svn/branches/dont-save-plaintext-passwords-by-default no_pass_wc -q
>svn pg svn:mergeinfo -R no_pass_wc
no_pass_wc - /branches/1.5.x-r30215:30238
/branches/diff-callbacks3:29985-30687
/branches/svn-mergeinfo-enhancements:30045-30214
/trunk:30654-30731
このブランチの開発者は、定期的にSubversionのtrunkと同期してきました。しかし、trunkでの開発はほぼ常に実行されており、svn mergeinfoサブコマンドを使用すると、マージ可能なtrunk上のいくつかのリビジョンがあることがわかります。
>svn mergeinfo --show-revs eligible http://svn.collab.net/repos/svn/trunk no_pass_wc
r30735
r30736
r30738
r30741
r30743
r30745
r30746
r30747
r30748
r30749
r30750
r30751
r30753
r30754
r30756
Windows開発者で、このブランチで作業しているとします。trunk上の変更(r30754)が、Windows上でブランチをビルドするために必要であることがわかっていますが、現時点ではtrunkからのすべての変更をマージしたくありません(多くの競合が発生し、対応する準備ができていないことがわかっているかもしれません)。必要な小さな修正のみを、ブランチ上の問題のあるファイルbuild.confに直接マージすることにします。
>svn merge http://svn.collab.net/repos/svn/trunk/build.conf no_pass_wc\build.conf -c30754
--- r30754を'no_pass_wc\build.conf'にマージしています
U no_pass_wc\build.conf
予想通り、ブランチの差分には、明示的なmergeinfoがbuild.confに追加されていることが示されており、r30754を除いて、ワーキングコピーのルートのmergeinfoと同等に見えます。
>svn diff no_pass_wc
Index: no_pass_wc/build.conf
===================================================================
--- no_pass_wc/build.conf (revision 30756)
+++ no_pass_wc/build.conf (working copy)
<テキスト差分を省略>
no_pass_wc\build.confのプロパティ変更
___________________________________________________________________
Added: svn:mergeinfo
Merged /branches/diff-callbacks3/build.conf:r29985-30687
Merged /trunk/build.conf:r30654-30731,30754
Merged /branches/1.5.x-r30215/build.conf:r30238
Merged /branches/svn-mergeinfo-enhancements/build.conf:r30045-30214
その後、trunkと同期する準備が整い、実行しますが、build.confに対して既に実行したマージのことを一時的に忘れていました。
>svn merge http://svn.collab.net/repos/svn/trunk no_pass_wc
--- r30732からr30753を'no_pass_wc'にマージしています
U no_pass_wc\subversion\include\svn_client.h
A no_pass_wc\subversion\include\private\svn_opt_private.h
U no_pass_wc\subversion\include\svn_opt.h
U no_pass_wc\subversion\libsvn_wc\status.c
U no_pass_wc\subversion\libsvn_subr\opt.c
U no_pass_wc\subversion\libsvn_subr\mergeinfo.c
A no_pass_wc\subversion\libsvn_client\cmdline.c
U no_pass_wc\subversion\libsvn_client\merge.c
U no_pass_wc\subversion\libsvn_client\prop_commands.c
U no_pass_wc\subversion\libsvn_client\mergeinfo.h
U no_pass_wc\subversion\tests\libsvn_client\client-test.c
U no_pass_wc\subversion\tests\cmdline\special_tests.py
U no_pass_wc\subversion\tests\cmdline\basic_tests.py
U no_pass_wc\subversion\tests\cmdline\merge_tests.py
U no_pass_wc\subversion\tests\cmdline\depth_tests.py
U no_pass_wc\subversion\svn\merge-cmd.c
U no_pass_wc\subversion\svn\cl.h
U no_pass_wc\subversion\svn\propdel-cmd.c
U no_pass_wc\subversion\svn\checkout-cmd.c
U no_pass_wc\subversion\svn\move-cmd.c
U no_pass_wc\subversion\svn\mkdir-cmd.c
U no_pass_wc\subversion\svn\cat-cmd.c
U no_pass_wc\subversion\svn\revert-cmd.c
U no_pass_wc\subversion\svn\diff-cmd.c
U no_pass_wc\subversion\svn\copy-cmd.c
U no_pass_wc\subversion\svn\mergeinfo-cmd.c
U no_pass_wc\subversion\svn\list-cmd.c
U no_pass_wc\subversion\svn\util.c
U no_pass_wc\subversion\svn\blame-cmd.c
U no_pass_wc\subversion\svn\propget-cmd.c
U no_pass_wc\subversion\svn\changelist-cmd.c
U no_pass_wc\subversion\svn\log-cmd.c
U no_pass_wc\subversion\svn\update-cmd.c
U no_pass_wc\subversion\svn\resolved-cmd.c
U no_pass_wc\subversion\svn\cleanup-cmd.c
U no_pass_wc\subversion\svn\commit-cmd.c
U no_pass_wc\subversion\svn\add-cmd.c
U no_pass_wc\subversion\svn\propset-cmd.c
U no_pass_wc\subversion\svn\switch-cmd.c
U no_pass_wc\subversion\svn\delete-cmd.c
U no_pass_wc\subversion\svn\import-cmd.c
U no_pass_wc\subversion\svn\proplist-cmd.c
U no_pass_wc\subversion\svn\resolve-cmd.c
U no_pass_wc\subversion\svn\export-cmd.c
U no_pass_wc\subversion\svn\status-cmd.c
U no_pass_wc\subversion\svn\propedit-cmd.c
U no_pass_wc\subversion\svn\lock-cmd.c
U no_pass_wc\subversion\svn\info-cmd.c
U no_pass_wc\subversion\svn\unlock-cmd.c
U no_pass_wc\subversion\libsvn_fs_fs\structure
--- r30754からr30757を'no_pass_wc'にマージしています
U no_pass_wc\subversion\include\svn_config.h
U no_pass_wc\subversion\libsvn_wc\merge.c
Subversionは、r30754が既にbuild.confにマージされていることを認識し、そのマージ部分を繰り返そうとしません。それだけでなく、マージが完了すると、Subversionはワーキングコピーのルートのmergeinfoとbuild.confのmergeinfoが同等であることに気づき、後者を省略します。これは、ワーキングコピーのステータスを確認するか、`svn:mergeinfo`プロパティを直接確認することで確認できます。
>svn st no_pass_wc
M no_pass_wc
M no_pass_wc\build.conf
<省略>
M no_pass_wc\subversion\svn\unlock-cmd.c
M no_pass_wc\subversion\libsvn_fs_fs\structure
>svn pg svn:mergeinfo -R no_pass_wc
no_pass_wc - /branches/1.5.x-r30215:30238
/branches/diff-callbacks3:29985-30687
/branches/svn-mergeinfo-enhancements:30045-30214
/trunk:30654-30757
マージが完了した後、省略が発生する前にSubversionを停止できた場合、このmergeinfoが表示されていました。
no_pass_wc - /branches/1.5.x-r30215:30238
/branches/diff-callbacks3:29985-30687
/branches/svn-mergeinfo-enhancements:30045-30214
/trunk:30654-30757
no_pass_wc\build.conf - /branches/1.5.x-r30215/build.conf:30238
/branches/diff-callbacks3/build.conf:29985-30687
/branches/svn-mergeinfo-enhancements/build.conf:30045-30214
/trunk/build.conf:30654-30757
no_pass_wc/build.confのmergeinfoはno_pass_wcのものと同等であるため、前者は省略されます。
1.5の新規マージサブコマンドオプションは`--record-only`です。`--record-only`オプションを使用して実行されたマージは、何もマージしようとしませんが、実際のマージが行われたかのように、mergeinfoを記録および省略します。これは、実際にマージせずに(ブロックして)変更がマージされたように見せるため、およびサブツリーmergeinfoをクリーンアップするためにも役立ちます。
1.5でのブロックは非常に簡単で、`--record-only`を使用してリビジョンをマージするだけで、Subversionはマージが行われたかのようにmergeinfoを作成します。その後、Subversionはmergeinfoを確認し、リビジョンが実際にマージされたかのように動作し、将来のマージ試行をブロックします。たとえば、前の例からのクリーンなチェックアウトをもう一度見てみましょう。最初に、`--record-only`を使用せずに、利用可能なリビジョンをマージします。
>svn merge http://svn.collab.net/repos/svn/trunk no_pass_wc -c30757
--- r30757を'no_pass_wc'にマージしています
U no_pass_wc\subversion\include\svn_config.h
予想通り、このマージはマージターゲットのmergeinfoを更新します。
>svn st no_pass_wc
M no_pass_wc
M no_pass_wc\subversion\include\svn_config.h
>svn diff no_pass_wc --depth empty
no_pass_wcのプロパティ変更
___________________________________________________________________
Modified: svn:mergeinfo
Merged /trunk:r30757
これで、そのマージを元に戻し、繰り返しますが、今回は`--record-only`を使用します。
>svn revert -R no_pass_wc
'no_pass_wc'を元に戻しました。
'no_pass_wc\subversion\include\svn_config.h'を元に戻しました。
>svn merge http://svn.collab.net/repos/svn/trunk no_pass_wc -c30757 --record-only
>
何もマージされていないため、マージからの出力はありません。しかし、差分が表示するように、mergeinfoは変更されています。
>svn diff no_pass_wc
no_pass_wcのプロパティ変更
___________________________________________________________________
Modified: svn:mergeinfo
Merged /trunk:r30757
`--record-only`を使用せずにマージをもう一度試行すると、ブロックされていることがわかります。
>svn merge http://svn.collab.net/repos/svn/trunk no_pass_wc -c30757
>
注:1.5のブロックは、実際にマージされたものとブロックされたものだけを容易に識別できる「真のブロック」とは異なります。1.5では、特定のパスが与えられたmergeinfoによって表されるすべてのソースと範囲が実際にマージされたのか、それともブロックされただけなのかを判断することは可能ですが、これは必ずしも簡単ではありません。開発コミュニティは、将来のリリースに向けて何らかの種類の真のブロックを検討しています。
サブツリーmergeinfoのクリーンアップに`--record-only`を使用する方法については、簡単な例を見てみましょう。非常に簡単なリポジトリをチェックアウトします。
>svn co %SIMPLEURL% simple_wc
A simple_wc\A
A simple_wc\A\B
A simple_wc\A\B\lambda
A simple_wc\A\B\E
A simple_wc\A\B\E\alpha
A simple_wc\A\B\E\beta
A simple_wc\A\B\F
A simple_wc\A\mu
A simple_wc\A\C
A simple_wc\A\D
A simple_wc\A\D\gamma
A simple_wc\A\D\G
A simple_wc\A\D\G\pi
A simple_wc\A\D\G\rho
A simple_wc\A\D\G\tau
A simple_wc\A\D\H
A simple_wc\A\D\H\chi
A simple_wc\A\D\H\omega
A simple_wc\A\D\H\psi
A simple_wc\iota
A simple_wc\A_branch
A simple_wc\A_branch\B
A simple_wc\A_branch\B\lambda
A simple_wc\A_branch\B\E
A simple_wc\A_branch\B\E\alpha
A simple_wc\A_branch\B\E\beta
A simple_wc\A_branch\B\F
A simple_wc\A_branch\mu
A simple_wc\A_branch\C
A simple_wc\A_branch\D
A simple_wc\A_branch\D\gamma
A simple_wc\A_branch\D\G
A simple_wc\A_branch\D\G\pi
A simple_wc\A_branch\D\G\rho
A simple_wc\A_branch\D\G\tau
A simple_wc\A_branch\D\H
A simple_wc\A_branch\D\H\chi
A simple_wc\A_branch\D\H\omega
A simple_wc\A_branch\D\H\psi
リビジョン4をチェックアウトしました。
ログから、このリポジトリはAをルートとするツリーで構成されており、r1で追加され、r2でブランチにコピーされ、r3とr4で変更されたことがわかります。
>svn log --verbose -r1:HEAD simple_wc
------------------------------------------------------------------------
r1 | jrandom | 2008-04-23 13:00:56 -0400 (Wed, 23 Apr 2008) | 1行
変更されたパス
A /A
A /A/B
A /A/B/E
A /A/B/E/alpha
A /A/B/E/beta
A /A/B/F
A /A/B/lambda
A /A/C
A /A/D
A /A/D/G
A /A/D/G/pi
A /A/D/G/rho
A /A/D/G/tau
A /A/D/H
A /A/D/H/chi
A /A/D/H/omega
A /A/D/H/psi
A /A/D/gamma
A /A/mu
A /iota
改訂版1のログメッセージ。
------------------------------------------------------------------------
r2 | pburba | 2008-04-23 13:02:04 -0400 (水, 23 4月 2008) | 1行
変更されたパス
A /A_branch (from /A:1)
Aからブランチを作成する
------------------------------------------------------------------------
r3 | pburba | 2008-04-23 13:02:44 -0400 (水, 23 4月 2008) | 1行
変更されたパス
M /A/D/H/psi
------------------------------------------------------------------------
r4 | pburba | 2008-04-23 13:03:09 -0400 (水, 23 4月 2008) | 1行
変更されたパス
M /A/B/E/beta
------------------------------------------------------------------------
まず、r3をA_branch\D\H\psiに直接マージします。
>svn merge %SIMPLEURL%/A/D/H/psi simple_wc\A_branch\D\H\psi -c3
--- 'simple_wc\A_branch\D\H\psi'へのr3のマージ
U simple_wc\A_branch\D\H\psi
>svn ci -m "merged r3 to A_branch/D/H/psi" simple_wc
送信中 simple_wc\A_branch\D\H\psi
ファイルデータの送信中。
改訂版5をコミットしました。
>svn pl -vR merge_tests-92
>svn pl -vR simple_wc
'simple_wc\A_branch\D\H\psi'のプロパティ
svn:mergeinfo : /A/D/H/psi:3
次に、r4をブランチのルートにマージします。
>svn merge %SIMPLEURL%/A simple_wc\A_branch -c4
--- 'simple_wc\A_branch'へのr4のマージ
U simple_wc\A_branch\B\E\beta
>svn pl -vR simple_wc
'simple_wc\A_branch'のプロパティ
svn:mergeinfo : /A:4
'simple_wc\A_branch\D\H\psi'のプロパティ
svn:mergeinfo : /A/D/H/psi:3-4
simple_wcはリポジトリで改訂版5であるため、コミット時に古いバージョンエラーを回避するために、ワーキングコピーを更新する必要があります。
>svn up simple_wc
改訂版5です。
>svn ci -m "" simple_wc
送信中 simple_wc\A_branch
送信中 simple_wc\A_branch\B\E\beta
送信中 simple_wc\A_branch\D\H\psi
ファイルデータの送信中。
改訂版6をコミットしました。
マージターゲットのサブツリー、A_branch\D\H\psiもmergeinfoが更新されていることに注意してください。
>svn pl --verbose -R simple_wc
'simple_wc\A_branch'のプロパティ
svn:mergeinfo : /A:4
'simple_wc\A_branch\D\H\psi'のプロパティ
svn:mergeinfo : /A/D/H/psi:3-4
しまった、会社のポリシーでは、明示的なmergeinfoを一元化するために、ブランチのルートにのみマージするということを思い出しました。最初のマージの際にそれを忘れてしまい、今は上司から叱責されています。どうすれば修正できるでしょうか?r3はA/D/H/psiのみに影響を与えるため、A_branchのmergeinfoに"/A:r3"を追加すれば、mergeinfoは現在と同じ意味を持ちます。もちろん、そうすれば、A_branch\D\H\psiのmergeinfoはA_branchのmergeinfoと同等になり、省略できます。これは、--record-onlyマージで1つの簡単な手順で行うことができます。ただし、最初にワーキングコピーを更新する必要があります(その理由については、「混合リビジョンワーキングコピー」を参照してください)。
>svn up simple_wc
改訂版6です。
>svn merge %SIMPLEURL%/A simple_wc\A_branch -c3 –record-only
>svn st simple_wc
M simple_wc\A_branch
M simple_wc\A_branch\D\H\psi
>svn pl -vR simple_wc
'simple_wc\A_branch'のプロパティ
svn:mergeinfo : /A:3-4
--record-only
マージによって、r3がA_branchのmergeinfoに追加され、A_branch\D\H\psiの同等のmergeinfoが省略されたことがわかります。昇給を要求する時間です!
Subversionの基本的な設計原則の1つは、可能な限り柔軟にすることです。多くの場合、柔軟性とはより大きな複雑さを意味し、より大きな複雑さがある場合、常に混乱の可能性があります。混合リビジョンワーキングコピーとmergeinfoの場合も同様です。
柔軟性とは、Subversionでは混合リビジョンワーキングコピーにマージできます。
複雑さとは、mergeinfoの継承と省略は、ワーキングコピー全体で一様なワーキングリビジョンに依存することです。
混乱とは、混合リビジョンワーキングコピーを扱う場合、mergeinfoの継承と省略が予想どおりに動作しない可能性があることです。
問題は、「サブツリーマージ」(つまり、ブランチのルートではなく、ルートのサブツリーへのマージ)を行う場合に最も発生する可能性があります。次の例では、openCOLLABNETのmerge-trackingプロジェクトのサンプルリポジトリを使用します。
まず、サンプルリポジトリの新しいワーキングコピーをチェックアウトします。
>svn co %URL% wc --quiet
リポジトリは、trunk、branches、tagsフォルダがルートから分岐するというかなり一般的な方法で構成されています…
>svn ls wc
branches/
tags/
trunk/
…そして、branchesの下にtrunkのいくつかのコピーがあります。
>svn ls wc\branches
a/
b/
c/
cブランチで作業を行うため、そこでmergeinfoを確認してみましょう。
>svn pg svn:mergeinfo -R wc\branches\c
wc\branches\c - /branches/a:3-11
/branches/b:10-13
/trunk:5-14
ここで、trunkに変更を加えます。
作業中…
>svn ci -m "some changes under trunk" wc
送信中 wc\trunk\jobs\index.html
ファイルデータの送信中。
改訂版18をコミットしました。
作業中…
>svn ci -m "some changes under trunk" wc
送信中 wc\trunk\jobs\index.html
ファイルデータの送信中。
改訂版19をコミットしました。
作業中…
>svn ci -m "some changes under trunk" wc
送信中 wc\trunk\about\index.html
送信中 wc\trunk\jobs\index.html
ファイルデータを送信中..
改訂版20をコミットしました。
それではマージを始めましょう。r18、r19、r20の変更をcブランチにマージする必要があると仮定しますが、aboutサブツリーへの変更ではなく、jobsサブツリーに影響を与える変更のみが必要なため、変更をbranches\c\jobsに直接マージします。
>svn merge %URL%/trunk/jobs wc\branches\c\jobs -c18,19,20
--- 'wc\branches\c\jobs'へのr18のマージ
U wc\branches\c\jobs\index.html
--- 'wc\branches\c\jobs'へのr19のマージ
G wc\branches\c\jobs\index.html
--- 'wc\branches\c\jobs'へのr20のマージ
G wc\branches\c\jobs\index.html
もちろん、これはbranches\c\jobsがbranches\cとは異なる独自の明示的なmergeinfoを持つことを意味します。
>svn pg svn:mergeinfo -R wc\branches\c
wc\branches\c - /branches/a:3-11
/branches/b:10-13
/trunk:5-14
wc\branches\c\jobs - /branches/a/jobs:3-11
/branches/b/jobs:10-13
/trunk/jobs:5-14,18-20
マージをコミットすると、混合リビジョンワーキングコピーがあることに気付きます。
>svn ci -m "Merged some changes from trunk to a subtree of c branch" wc
送信中 wc\branches\c\jobs
送信中 wc\branches\c\jobs\index.html
ファイルデータの送信中。
改訂版25をコミットしました。
>svnversion wc\branches\c
17:25
改訂版25?初期のチェックアウトとこのコミットの間で、他の開発者がリポジトリに変更を加え、r21~r24という新しいリビジョンが作成されたようです。
後で、aboutサブツリーに影響するr20からのその他の変更をbranches\cにマージする必要があります。上司のブランチのルートへのマージに関する発言を思い出して、r20をブランチのルートにマージすることにします。また、マージ追跡ロジックによって繰り返しのマージを防ぎ、branches\c\jobsのmergeinfoを省略することを知って、r18とr19を再マージすることを選択します。
>svn merge %URL%/trunk wc\branches\c -c18,19,20
--- 'wc\branches\c'へのr20のマージ
U wc\branches\c\about\index.html
コミットする前に、branches\cのmergeinfoを確認します。これは何ですか?branches\c\jobs\index.htmlにはまだmergeinfoがあり、branches\cのmergeinfoと完全に同等に見えます。branches\c\jobsのmergeinfoがbranches\cに省略されなかったのはなぜですか?
>svn pg svn:mergeinfo -R wc\branches\c
wc\branches\c - /branches/a:3-11
/branches/b:10-13
/trunk:5-14,18-20
wc\branches\c\jobs - /branches/a/jobs:3-11
/branches/b/jobs:10-13
/trunk/jobs:5-14,18-20
問題は、混合リビジョンワーキングコピーにあります。
>svn st -v wc\branches\c
M 17 16 cuser wc\branches\c
17 15 merger wc\branches\c\products
17 2 user wc\branches\c\products\little.html
17 15 merger wc\branches\c\products\medium.html
17 2 user wc\branches\c\products\big.html
17 15 merger wc\branches\c\products\roadmap.html
17 15 merger wc\branches\c\products\index.html
17 15 merger wc\branches\c\about
M 17 15 merger wc\branches\c\about\index.html
17 15 merger wc\branches\c\index.html
17 15 merger wc\branches\c\news
17 15 merger wc\branches\c\news\index.html
17 2 user wc\branches\c\support
17 2 user wc\branches\c\support\index.html
25 25 pburba wc\branches\c\jobs
25 25 pburba wc\branches\c\jobs\index.html
branches\c\jobsはワーキングリビジョン25であるのに対し、branches\cの残りはr17であることに注意してください。Subversionsの省略ロジックは、2つのワーキングリビジョンが異なるため、ワーキングコピーからbranches\c\jobsのmergeinfoをbranches\cに省略しようと試みません。なぜでしょうか?branches\c@17で見つかったmergeinfoがbranches\c@25と同じであるかどうかを知る方法がないためです。同僚がr21~r24で行った変更によって、branches\cのmergeinfoが変更された可能性があります。この場合、このマージをコミットしようとすると、古いバージョンエラーが発生し、コミットする前にワーキングコピーを更新する必要があります。
r21~r24がbranches\cブランチに影響するかどうかを、--show-updatesステータスで確認できます。
>svn st --show-updates --verbose wc\branches\c
17 2 user wc\branches\c\products\little.html
17 15 merger wc\branches\c\products\medium.html
17 2 user wc\branches\c\products\big.html
17 15 merger wc\branches\c\products\roadmap.html
17 15 merger wc\branches\c\products\index.html
17 15 merger wc\branches\c\products
M 17 15 merger wc\branches\c\about\index.html
17 15 merger wc\branches\c\about
17 15 merger wc\branches\c\index.html
17 15 merger wc\branches\c\news\index.html
17 15 merger wc\branches\c\news
17 2 user wc\branches\c\support\index.html
17 2 user wc\branches\c\support
25 25 pburba wc\branches\c\jobs\index.html
25 25 pburba wc\branches\c\jobs
M 17 16 cuser wc\branches\c
基準リビジョンに対するステータス: 25
いいえ、誰もbranches\cに変更を加えていません。変更があれば、8列目に「*」の古いバージョンマーカーが表示されます。したがって、branches\cを更新することにします。
>svn up wc\branches\c
改訂版25です。
現在、ブランチは統一された作業リビジョンになっています(そして、コミットされていないマージからのローカル変更もまだ残っています)。
>svnversion wc\branches\c
25M
branches/c/jobs にある冗長な明示的な mergeinfo を削除したいので、マージを繰り返します。マージ追跡ロジックにより、重複したマージを回避します(ここでは `--record-only` オプション付きのマージも使用できますが、このケースでは両者に実質的な違いはありません)。
>svn merge %URL%/trunk wc\branches\c -c18,19,20
>
良好です。マージは発生しませんでしたが、確かに、作業コピーが統一されたリビジョンになったことで、mergeinfo の削除が行われました。
>svn st wc\branches\c -v
M 25 25 pburba wc\branches\c
25 15 merger wc\branches\c\products
25 2 user wc\branches\c\products\little.html
25 15 merger wc\branches\c\products\medium.html
25 2 user wc\branches\c\products\big.html
25 15 merger wc\branches\c\products\roadmap.html
25 15 merger wc\branches\c\products\index.html
25 15 merger wc\branches\c\about
M 25 15 merger wc\branches\c\about\index.html
25 15 merger wc\branches\c\index.html
25 15 merger wc\branches\c\news
25 15 merger wc\branches\c\news\index.html
25 2 user wc\branches\c\support
25 2 user wc\branches\c\support\index.html
M 25 25 pburba wc\branches\c\jobs
25 25 pburba wc\branches\c\jobs\index.html
>svn pg svn:mergeinfo -R wc\branches\c
wc\branches\c - /branches/a:3-11
/branches/b:10-13
/trunk:5-14,18-20
この例は、mergeinfo の削除に関する問題を示しています。前に述べたように、削除と継承は本質的に同じものであるため、継承を含む混合リビジョン作業コピーに関する問題も確認できます。以前のマージを r26 としてコミットした後の、次の混合リビジョン作業コピーがあるとします。
>svn st -v wc\branches\c
26 26 pburba wc\branches\c
26 15 merger wc\branches\c\products
26 2 user wc\branches\c\products\little.html
26 15 merger wc\branches\c\products\medium.html
26 2 user wc\branches\c\products\big.html
26 15 merger wc\branches\c\products\roadmap.html
26 15 merger wc\branches\c\products\index.html
25 15 merger wc\branches\c\about
26 26 pburba wc\branches\c\about\index.html
26 15 merger wc\branches\c\index.html
26 15 merger wc\branches\c\news
26 15 merger wc\branches\c\news\index.html
26 2 user wc\branches\c\support
26 2 user wc\branches\c\support\index.html
26 26 pburba wc\branches\c\jobs
26 25 pburba wc\branches\c\jobs\index.html
>svn pg svn:mergeinfo -R wc\branches\c
wc\branches\c - /branches/a:3-11
/branches/b:10-13
/trunk:2,5-14,18-20
リビジョン 17:20 を branches\c\about に直接マージしようとすると、Subversion は branches\c\about の mergeinfo を特定して、重複したマージを回避しようとします。残念ながら、branches\c は異なる作業リビジョンにあるため、branches\c から明示的な mergeinfo を継承することはできません。そのため、Subversion は、branches\c\about@25 の明示的または継承された mergeinfo をサーバーに問い合わせます。このパスには、そのリビジョンで明示的な mergeinfo はありませんが、branches\c@25 から mergeinfo を継承しますが、これは r26 までコミットされなかったため、r18-20 は含まれていません!そのため、Subversion は r18-20 が branches/c/about をルートとするツリーに適用されていないと考え、マージを繰り返します。
>svn merge %URL%/trunk/about wc\branches\c\about -c18,19,20
--- 'wc\branches\c\about' への r20 のマージ
U wc\branches\c\about\index.html
この場合、branches\c\about に明示的な mergeinfo が追加されるだけですが、重複したマージによる競合が容易に発生する可能性があります。
>svn st wc\branches\c
M wc\branches\c\about
>svn diff wc\branches\c
wc\branches\c\about のプロパティ変更
___________________________________________________________________
Added: svn:mergeinfo
マージ済み /branches/b/about:r10-13
マージ済み /trunk/about:r2,5-14,18-20
マージ済み /branches/a/about:r3-11
そのマージを元に戻し、マージターゲットを統一された作業コピーリビジョンに更新してからマージを繰り返すと、何も起こらないことがわかります。
>svn revert -R wc
'wc\branches\c\about' を元に戻しました。
>svn up wc
リビジョン 26 で。
>svn merge %URL%/trunk/about wc\branches\c\about -c18,19,20
>svn st wc
>
これは、branches\c\about が r18-20 を含む branches\c から明示的な mergeinfo を継承できるようになったためです。これらのリビジョンはすでに branches\c\about にマージされているため、Subversion はマージを試みません。
確かに、これらの例はいずれも少し contrived であり、このようなものに遭遇することはないかもしれません。しかし、mergeinfo に関する不可解な動作が見られた場合は、常に混合リビジョン作業コピーが原因であるかどうかを確認してください。
著者は、混合リビジョン作業コピーと mergeinfo の継承/削除の組み合わせに何度か困惑させられたことを恥ずかしげもなく認めています。Subversion の問題トラッカーに新しい問題を書き始めるほどになったこともありました…
多くのことを網羅しました! mergeinfo の動作、特にいくつかの非典型的なユースケースにおける動作について、より深く理解できたことを願っています。しかし、これらの複雑さをすべて回避したい場合はどうすればよいでしょうか?ニーズによっては、それほど難しくありません。開発プロセスと互換性がある場合、次のルールに従うことで、mergeinfo(およびマージ)を可能な限りシンプルに保つことができます。
そうです、多くの「しないこと」があります。そして、もう一つあります。「必要であれば、これらのことをためらわずに行う」ことです。最初に述べたように、Subversion は常に mergeinfo について「正しいことを行う」よう試み、この投稿が皆さんが同じようにすることを助けることを願っています。