svk によるレポジトリ分割の作業記録
前回は svnadmin dump
を利用してレポジトリの分割を行いましたが,今回は svk をレポジトリ操作ツールとして使用し,レポジトリの分割をおこなってみました。
svndumpfilter
に比べるとやや柔軟性が落ちますが,ことレポジトリの分割ということに焦点をおくのであれば,svk を利用したほうが簡便かつ安定しているようです。以下の手順は私があまり svk に慣れていないので煩雑にみえますが,svk に慣れている方からすると直感的でしょうし DEPOTs の切り替えを行うことなくやってのけることもできるはずです。
他の文献には svk repository をそのまま新レポジトリとする手法が載ってたりしたんですが,今回は SVN レポジトリがリモートにあったため愚直な方法を使いました。もっといい方法があるよ,という方はご教示ください。
前説
svk がなんなのかは省略します。
svk は SVN レポジトリをあやつるものであることはいうまでもないですが,バックエンド(というかローカルレポジトリ)として SVN repository を利用しています。以下この svk が利用するローカル SVN repository のことを便宜上 svk repository(ないし DEPOTs)と呼ぶことにします。
svk は各プロジェクトで使用するディレクトリを DEPOTPATH と呼んでいます。たとえば,
//mirror/MyProject
のような形式のものが DEPOTPATH です。これは実際に svk repository に mirror/MyProject
として存在します。
また,svk はどの DEPOTPATH がリモートの mirror であるのか,や,どの DEPOTPATH をどこに checkout したのか,などの mapping data を保持しています。このような mapping 属性等には,
- depotpath mapping
- mirror mapping
- checkout mapping
- DEPOTPATH copy chain
などがあります。
たとえば mirror mapping に登録されている DEPOTPATH に対して svk が(内部的に)commit を行った場合,mirror 元と sync をとります。また,checkout mapping に登録されている local path で svk が commit を行った場合,その宛先は checkout mapping で対応する DEPOTPATH になります((だから svk の working directory には .svn
などの管理用ディレクトリが必要ないんですね))。
以上の内容についてはドキュメントやソースを読んだわけではなくて,今回の手順から推察したものなので,間違いなどあるかもしれません。また,理解できなくても以下の手順は行えますので。
状況
server というリモートマシン上に SVN レポジトリが存在します。この,
を
- 新規 foobar レポジトリを作成し,trunk ディレクトリ下につっこむ
ことが目的です。
リモートマシン(レポジトリサーバ)には svk はインストールされていません。ローカルには svk がインストールされています。
前準備(新規レポジトリの作成)
まずはサーバ側で foobar プロジェクト用のレポジトリを作成します。
[dayflower@server] % svnadmin create foobar
サーバ側でやる必要があるのは,この新規レポジトリの作成のみです。
次に,定番ディレクトリの trunk, tags, branches を作っておきます。
% svn mkdir http://server/repos/foobar/trunk \ http://server/repos/foobar/tags \ http://server/repos/foobar/branches リビジョン 1 をコミットしました。
作業用 DEPOTs の作成
現在の DEPOTPATH のマッピングを見てみます。
% svk depotmap --list Depot Path ============================================================ // /home/dayflower/.svk/local
ふつーに作業をしていた方なら,このように ~/.svk/local
に ROOT(//
)の DEPOTPATH への mapping があるかと思います。
svk repository と DEPOTPATH への mapping は複数指定できます。ですが,作業ミスによって普段使いの svk の環境が壊れてしまうと困るので,念のために新しい svk repository を作り,そこを ROOT DEPOTPATH にします。
まずローカルで svk 用 SVN repository を作成します。
% svnadmin create ~/tmp/workplace
次に depotmap
の relocate
機能を使って,ROOT DEPOTPATH として指定します。
% svk depotmap --relocate // ~/tmp/workplace Depot '' relocated to '/home/dayflower/tmp/workplace'.
ここで与えるパスは,必ず絶対パスを指定してください。相対パス(ここの例だと,たとえば tmp/workplace
)で指定してしまうと,作業中のディレクトリに対する相対パスとみなされ,DEPOTPATH が不在になったりして怒られるので。~
などのシェル展開を使うのは構いません。
depotmap がどのようになったか確認します。
% svk depotmap --list Depot Path ============================================================ // /home/dayflower/tmp/workplace
無事新しい作業用 repository が ROOT DEPOTPATH になりました。
現状の mirror mapping を確認してみましょう。
% svk mirror --list
このように何も表示されません。mirror mapping は,svk repository に記録されているので,現状で mirror mapping はないんですね。
では,checkout mapping についてはどのようになっているでしょうか。
% svk co --list Depot Path Path ======================================================================== //local/MyProject /home/dayflower/dev/MyProject
このように,私の環境では既存の DEPOTPATH と checkout path のマッピングが表示されました。これは,checkout mapping については ~/.svk/config
に記録されているからです。
つまり,現在の状態で ~/dev/MyProject
で svk ci
などの作業を行うと,おかしなことになっていまいます。と,警告しておきます。
Sandbox レポジトリの mirror-ing
リモートレポジトリ(Sandbox 側)の mirror 設定を行います。
% svk mirror //Sandbox/foobar http://server/repos/Sandbox/foobar Mirror initialized. Run svk sync //Sandbox/foobar to start mirroring.
svk をお使いの方ならお馴染みのメッセージが表示されました。あくまで mirror mapping に登録しただけなのでまだ mirroring されていません。svk sync
して,同期しておきます。
% svk sync //Sandbox/foobar Syncing http://server/repos/Sandbox/foobar Retrieving log information from 1 to 80 Committed revision 2 from revision 70. Committed revision 3 from revision 71. ...... snip ...... Committed revision 12 from revision 80.
Sandbox レポジトリ全体では 80 のコミットログがあったのですが,foobar に関わるものは 12 で済んだようです。
NG: mirror mapping の relocate
mirror mapping にも depotpath
コマンドと同様,--relocate
オプションがついています。これを使えば,簡単に同期できるんじゃ……?
% svk mirror --relocate //foobar/trunk http://server/repos/foobar/trunk Mirror source UUIDs differ.
ミラー元の UUID が違う,といって怒られてしまいました。
SVK book をひもとくと……
SVK won't let you relocate a mirror unless the new mirrored repository has the same UUID as the original mirror had. This prevents you from accidentally using relocate to point a mirror at something that isn't really the same repository after all.
Version Control with SVK
間違えて全然違うレポジトリに relocate してレポジトリを壊してしまう可能性を避けるために,このようなチェック機構が働いています。
実際,ここで relocate できたとしても,relocate 先のレポジトリがどのような状況にあるのか svk が知る術はないのでうまくいかないことでしょう。
svk mirror --relocate
コマンドは,
など,レポジトリ全体の同一性が保たれている場合にのみ行うようにしましょう。
foobar レポジトリの mirror-ing
新規に作成した foobar レポジトリの trunk ディレクトリについて mirror-ing 設定を行います。
% svk mirror //foobar/trunk http://server/repos/foobar/trunk Mirror initialized. Run svk sync //foobar/trunk to start mirroring.
さっきも当然のように指定しましたが,レポジトリの下位のみの mirror-ing もできるので素敵ですね(もちろん svn 自体にもその機能があるわけですが)。
% svk sync //foobar/trunk Syncing http://server/repos/foobar/trunk Retrieving log information from 1 to 1 Committed revision 14 from revision 1.
まだ新規レポジトリでは何も行っていないので,これだけのコミットログで済みました。実は,今回の状況では destination の sync
は行う必要がないのですが(どうせ空なので),念のためにやっておきましょう。
ここまでで設定された mirror mapping を確認してみます。
% svk mirror --list Path Source ======================================================== //Sandbox/foobar http://server/repos/Sandbox/foobar //foobar/trunk http://server/repos/foobar/trunk
旧レポジトリと新レポジトリの両者が,DEPOTPATH として mapping 指定されていることがわかります。
旧レポジトリから新レポジトリへの smerge
svk には,レポジトリの変更をパッチ集として他のパスによしなに適用してくれる smerge
という素敵コマンドが存在します。普段は svk push
等のコマンドのバックエンドとして自動的に作動するので手で触る必要はないのですが*1,今回のような場合に重宝します。
と,いうことで個別コミット+簡略版コミットログ,にするためのオプション --incremental
((-I
のような省略形もあります。大文字の<アイ>ですからお間違えなく!)) と --verbatim
オプションをつけて smerge
を実行してみましょう。
% svk smerge --incremental --verbatim //Sandbox/foobar //foobar/trunk Can't find merge base for /Sandbox/foobar and /foobar/trunk
merge する base がわからんよ,と怒られてしまいました。
困ったときの SVK book。
The
Version Control with SVK--baseless
switch makes the smerge assume there is no common ancestor (which there isn't yet).
smerge
コマンドは本来,異なる branch などで進行したコミットログを別の branch 等に merge する際に用いるコマンドです。ですから,普通はどのリビジョンからの差分か,という情報が必要になります。ですが,今回の場合は,新旧レポジトリともに,作成時点から最新時点までのコミットを扱うわけです。なので,共通する祖先はいませんよ,ということを明示する必要があります。
--baseless
((-B
という短縮形アリ)) というオプションを指定してやり直します。
% svk smerge --baseless --incremental --verbatim //Sandbox/foobar //foobar/trunk Auto-merging (0, 12) /Sandbox/foobar to /foobar/trunk (base /:0). ===> Auto-merging (0, 1) /Sandbox/foobar to /foobar/trunk (base /:0). Merging back to mirror source http://server/repos/foobar/trunk. Empty merge. ===> Auto-merging (1, 2) /Sandbox/foobar to /foobar/trunk (base /:0). Merging back to mirror source http://server/repos/foobar/trunk. Empty merge. ===> Auto-merging (2, 3) /Sandbox/foobar to /foobar/trunk (base /:0). Merging back to mirror source http://server/repos/foobar/trunk. A foobar.c A Makefile U . New merge ticket: 41f9f42d-c407-4326-8799-8341091d697e:/foobar:71 Merge back committed as revision 2. Syncing http://server/repos/foobar/trunk Retrieving log information from 2 to 2 Committed revision 15 from revision 2. ...... snip ...... ===> Auto-merging (11, 12) /Sandbox/foobar to /foobar/trunk (base /Sandbox/foobar:11). Merging back to mirror source http://server/repos/foobar/trunk. U foobar.c New merge ticket: 41f9f42d-c407-4326-8799-8341091d697e:/foobar:80 Merge back committed as revision 11. Syncing http://server/repos/foobar/trunk Retrieving log information from 11 to 11 Committed revision 24 from revision 11.
無事 merge されました。新レポジトリに旧レポジトリの変更ログがコミットされたことになります。
ここで注目してほしいのは,各 merge ログ。
Merging back to mirror source http://server/repos/foobar/trunk.
mirror 元のソース(http://server/repos/foobar)にまで merge が及んでいます。これは mirror mapping に登録されている DEPOTPATH に対する操作なので,自動的に mirror 元に波及するんですね。
つうわけで,以上の手順により,新レポジトリに旧レポジトリのコミットログがコピーされました。
後始末
あとは,作業用に使っていた svk repository の depot mapping を解除して,削除すればおしまいです。
% svk depotmap --relocate // ~/.svk/local Depot '' relocated to '/home/dayflower/.svk/local'. % svk depotmap --list Depot Path ============================================================ // /home/dayflower/.svk/local
今回は新規に作業用の svk repository を作成したので,単にディレクトリごと削除してしまって構いません((既存の DEPOTs を利用していた場合,svk delete
を使用する必要があるでしょう))。
% rm -rf ~/tmp/workplace
さて,もともと使っていた DEPOTs の情報は残っているでしょうか。
% svk mirror --list Path Source ================================================================= //mirror/MyProject http://server/repos/MyProject
無事,普段使いの svk 環境に復帰しました。