« .svn ディレクトリを perl で消す | メイン | ファイル名に出来ない文字をエスケープ »

2008年01月06日

日常の備忘録:: SVNで古いリポジトリと新しいリポジトリをつなげる

    

サーバーのHDDが死んでSubversionのリポジトリを失った。
そこで、仕方なくローカルの作業コピーを使って、新たにリポジトリを作っていた。
が、死んだと思っていたHDDからデータを取り出すことに成功したため、古いリポジトリのデータを復活できた。
と言うことで、この2つのリポジトリのコミットログをマージして、つなげられないかと試行錯誤。
svnadmin dump と load とスクリプトで何とか出来たので、その方法を記しておく。
ただ、ある程度理解してやらないとうまくつながらないので注意。

まず、古いリポジトリの最後と新しいリポジトリでインポート後の最初のリビジョンのtrunkの構成を一致させる必要がある。
今回、不幸なことに新しいリポジトリに入れるまでに間があったことから、だいぶ異なっていた。
また、リポジトリの構成も、古いのはフォルダを切った下に trunk を作っていたのに対して、新しいのはtrunk の下にフォルダを切っていた。
なんと言う適当っぷり。
まあ、新しいのはAll In One Trac で入れたので、それがデフォルトでtrunkを一番下に作るせいでそうしたのだろう。
ただ、新しい方は trunk の下に分断されたものしか入れていなかったのが救い。

と言うことで、古い方は対象のもののみ取り出す必要がある。
これは、ダンプの時に svndumpfilter を使えばいい。
svnadmin dump /repos | svndumpfilter include project1 > dump.dat
ってな感じ。
単純にリビジョンごとにダンプするperlスクリプトは以下のような感じ。
svndumpfilter を使う時はこれを少し変えればいい。

$repo_path = 'C:\trac\svn_repo\projects\tools';
$svn_admin = 'C:\trac\subversion\bin\svnadmin';
$svn_filter = 'C:\trac\subversion\bin\svndumpfilter';
$max_revision = 302;
for( $i = 0; $i < $max_revision; $i++ ) {
  system("$svn_admin dump --incremental -r $i:$i $repo_path > .\\dump_tools\\dump$i.dat");
}

古い方から対象もののみ取り出したら、新たにリポジトリ作ってそこにロード。
連番から読むのは以下のようなperlスクリプトでOK。

$repo_path = 'C:\trac\svn_repo\projects\new_tools';
$svn_admin = 'C:\trac\subversion\bin\svnadmin';
$max_revision = 513;
for( $i = 0; $i < $max_revision; $i++ ) {
  system("$svn_admin load $repo_path <  .\\dump_tools\\dump$i.dat");
}

次に、新しい方のインポート後の最初のリビジョンと上の古いほうの最後のリビジョンを取り出して、古いほうにマージ ( と言うかコピー。タイムスタンプが変わらないようにするためにもコピーでないとダメかも ) 。なくなったものは消す必要がある。
で、古いほうにコミット。
古いほうは、ディレクトリ構成が1段深くなっているので、1つ上げて新しいのと同じにする。
これで、古いのの最後と新しいのの最初が同じになってつながるように。
tagsとかbranchesはtrunkからコピーしたりしているだけで、分断されていないので放置。
で、この状態のものをダンプする。

次に、新しい方のリポジトリをダンプして、ダンプ結果のリビジョンを上げる。
リビジョン番号は古いものの最後の次の番号と新しい方のインポート後の次のリビジョンが一致するようにする。
リビジョンを上げるには、以下のような perl スクリプトを使った。
最初、Node-copyfrom-rev: の方に気付かずにうまくいかなかった。

$rev_shift = 302;
foreach( glob("*.dat") ) {
  $org_name = $_;
  /([0-9]+)/;
  $num = $1;
  $new_num = $num + $rev_shift;

  open IN, "<$org_name" or die $!;
  open OUT, ">./new/dump$new_num.dat" or die $!;
  binmode(IN);
  binmode(OUT);

  while(<IN>) {
    if(/^Revision-number: [0-9]+/ ) {
      s/[0-9]+/$new_num/;
    } elsif( /^Node-copyfrom-rev: ([0-9]+)/ ) {
      $ref_num = $1 + $rev_shift;
      s/[0-9]+/$ref_num/;
    }
    print OUT $_;
  }
  close(IN);
  close(OUT);
}

これは、実行するディレクトリに new ってディレクトリを作っておいてから実行する。
インポートしたリビジョンまではいらないので削除して、古いもののダンプ結果と新しいもののリビジョンを上げたのをひとつのディレクトリに入れて、新しいリポジトリを作ってロード。
これでひとつにつながった。



投稿者 Takenori : 2008年01月06日 00:46




comments powered by Disqus
Total : Today : Yesterday : なかのひと