Subversion FAQ

(English)

Based on r32490

Table of Contents

General questions:

How-to:

Troubleshooting:

Developer questions:

References:


General questions:

このプロジェクトの存在理由は?

CVSユーザを乗っ取ること。より正確に言うなら、CVSに良く似た、でも多くの問題点が修正されている、新しいバージョンコントロールシステムを開発している。 詳細はプロジェクトのフロントページを参照のこと。

Subversionって、プロプラエタリなの? CollabNetが所有しているって聞いたんだけど...?

いや、Subversionはオープンソースでありフリーソフトウェアだよ。 CollabNetは、何人かのフルタイム開発者へ給料を払っていて、コードのコピーライトをもっているけど、でもそのコピーライトは、Debian Free Software Guidelinesへ完全準拠なApache/BSD-style ライセンスだ。 言い換えれば、ダウンロードや改変、そして再配布は、あなたが望むように、自由に行える。 CollabNetや他の人に許諾を得る必要はない。

Subversionって、僕等のプロジェクトで使える位に安定している?

はい、全くもって。 重要プロダクトで十分使えるよ。

Subversion は2000年から開発が続けられていて、1年を過ぎた頃から、自分自身をホストできるようになった。我々がα版と宣言した年の1年後には、Subversionは、プライベートな開発者や実際の業務など、既に数多くの場所で使われるようになっていた。 その時から、2年以上をバグ修正と安定化に費やし、1.0になったんだ。 他のプロジェクトでは、もっと早い段階で「1.0」って宣言するじゃないかと思う。 でも我々はその名称を使うのを、意図的に、出来るだけ引き伸ばそうと決心した。 多くの人々がSubversionが1.0 になってから使おうと考えていることも、そのバージョン名が非常に特別な意味を持っている事にも気がついていたからだ。 だから、この規律を守り続けたんだ。

Subversionのクライアント/サーバ相互接続性に関するポリシーは?

クライアントとサーバは、最大、1世代のメージャーリリースバージョンを跨がない限り動作するように設計されている。 例えば、1.Xクライアントは、1.Yのサーバとともに動作するだろう。 但し、クライアントとサーバのバージョンが一致しない場合には、何らかの機能が使えないかもしれない。

クライアントとサーバの相互接続性ポリシーに関しては、Hacker's Guide to Subversionの「Compatibility」セクションに書かれている。

SubversionはどのOS上で動作するの?

最近のUNIXや、Win32、BeOS、OS/2、MacOS Xで動作する。

Subversionは ANSI C で書かれていて、APR(Apache Portable Rutime Library)をポータビリティ実現の為に使っている。 Subversionクライアントは、APRを稼動可能なOS上ならば何処ででも動作するだろうから、多くの環境で使うことが出来る。 Subversionサーバ(つまり、リポジトリ側)についても同様だけど、Win9xプラットフォーム(Win95/Win98/WinME)では、Berkeley DBリポジトリを使うことは出来ない。 これは、Win95上の Berkeley DB に、shared-memory セグメント問題が存在するためだ。(version 1.1から導入された)FSFSリポジトリにはこの制約は存在しない。 しかし、Win9xのファイルロックサポートの制限により、こちらもWin9x 上では、動作しない。

整理すると、Subversionクライアントは、APRが動作するプラットフォーム上でならばどこででも動作する。 Subversionサーバも、APRが動作する全てのプラットフォームで動作するが、Win95/Win98/WinMeではリポジトリを提供することは出来ない。

「新ファイルシステム」って、どういうこと? ext2みたいのもの?

いや違う。「Subversion Filesystem」は、OSに実装されているようなカーネルレベルのファイルシステムではない。 これはSubversionのリポジトリインターフェイスで、リビジョン間の状態が保持されているディレクトリツリーを保存する、という意味では、「版付けされたファイルシステム」と言える。 リポジトリへアクセスするプログラムを書くことは、他のファイルシステムAPIを使うプログラムを書くのと同じようなものだ。 大きな違いは、この特別なファイルシステムでは、書き込みが行われてもデータが失われない、ということ。 最新の状態を取得するの同様、古いファイルツリーの状態を簡単に取り出すことが出来る。

Subversionサーバを動作させるためには、どんなハードウェアが必要?

サーバの要求は多くの要素が関係してくる。 例えば、ユーザ数や、コミットを初めとするサーバ関連操作の頻度、リポジトリのサイズ、独自に設定したリポジトリフックの負荷などだ。 もし、Apacheを使っているならば、Apache自体がメモリ使用量の最大要因となるだろう。より詳しい話は、メイリングリストの議論を参照してほしい。

同じサーバ上で動作している、他のアプリケーションを考慮に入れるのを忘れないこと。 例えば、リポジトリブラウザを使うのであれば、Subversion 自体とは関係なくリソースが必要になる。

一般的に行って、同等のCVSリポジトリと比べて、より少ないサーバメモリで済むことは期待して良いよ。

Subversion って、Apacheのエクステンションって聞いたんだけど? サーバとして使うってこと?

いや、Subversion は一連のライブラリセットで、コマンドラインクライアントが付属してくるんだ。 Subversionには2種類のサーバプロセスが存在する。 1つは svnserv。これは、小さなスタンドアロンプログラムで cvs の pserver に似ている。 もう1つは、mod_dav_svn という特別なモジュールと組み合わせて Apahce httpd-2.0 を使うやり方。 svnserve は独自のプロトコルを使うけど、mod_dav_svn は、WebDAV をネットワークプロトコルとして使う。 より詳しく知りたい場合には、Subversion Book の6章を参照のこと。

ってことは、Subversion を使うには、Apacheを設定しなきゃいけないってこと?

端的に言えば「違う」。

もう少し詳しく言うと、もし、リポジトリにアクセスしたいだけならば、Subversion クライアントを build しさえすれば良い。 もし、ネットワークから使えるリポジトリを提供したいならば、Apache2か「svnserve」サーバを設定しなければならない。

ネットワークからアクセス可能な Subversion サーバの設定方法に関しては、詳細が Subversion Bookの6章に書いてある。

現在 Apache 1.x を使っていて、Subversion のリポジトリを提供するためだけに Apache 2.0 へと移行することは出来ないんだ。 これって、Subversion サーバを使うことが出来ないって、ことになるのかな?

いや、Subversion サーバとして svnserve を利用すればよい。 十二分に動いてくれるよ。

もし、WebDAVや、Apache サーバに付いている、他の「便利な機能」を使いたいな、と思ったら、その通り、Apache 2.0 が必要になる。 とは言え、Apache 1.x をポート番号80で可動させたまま、Apache 2.0 を別のポートで実行させる、って選択肢もある。異なるバージョンのApacheは、同じマシン上で問題なく同居させることが可能だ。 httpd.conf の中にある Listen ディレクティブを、「Listen 80」から「Listen 8080」などの適当なポート番号へと変更した上で、リポジトリ URL を告知するときに、そのポート番号を明確に示す(例えば、http://svn.mydomain.com:8080/repos/blah/trunk/とかね)だけ。

えーと、SCM system Yがやってるみたいに X って機能を採用するってのはどう?

僕達は、SCM の未知なる世界を切り開こうってわけじゃないし、この世に存在する各種SCMが有している最良の機能群を、全てとりこもう、と考えているわけでもない。 ただ、CVSを置き換えよう、と頑張っているだけ。最初の質問を読んでみて。

どうして、リポジトリ全体でリビジョン番号を共有するの? 僕は、個々のプロジェクト毎に、それぞれのリビジョン番号が欲しいんだけど。

リポジトリ全体という単位で割当られるグローバルなバージョン番号は、ユーザの観点からは無意味だ。 これは根底にあるスキーマデザインの目的実現のための、内部実装の一つである。 とはいえ、ユーザインターフェイス的には、憂鬱な気になる、長ったらしい日付や時間の文字列を入力するよりは、場合によっては、少しだけ楽になる、ということはあるけれど。

リビジョン番号は、ただリポジトリの為に、また、ユーザの利便性のために存在するに過ぎない。それは、あなたがリポジトリへ格納しているものとの関係性は一切ない。 コードベースの変更レートに関する正確な指標としては、リポジトリのリビジョン番号変化は、決して適切なものではない。コードベースの変更レートに関する全体把握の為には、より適した、もっと複雑な手法が他に存在する。

Subversion には「チェンジセット」って存在する?

この質問は、ちょっと厄介だ。 というのは、皆「チェンジセット」に対して、少しづつ異なる定義を持っているように思えるし、少なくとも、バージョンコントロールシステムが「チェンジセット機能を持つ」という意味に対して異なる期待を抱いているだろうから。

以後の議論の為に、チェンジセットを簡単に定義しておこう。「チェンジセットとは、一意な名前をもった変更の集合である」。 「変更」には、ファイルコンテンツに対するテキスト的な編集や、ツリー構造に対する修正、また、メタデータに対するちょっとした調整も含まれる。 より一般的に言うならば、チェンジセットとは、あなたが参照できる名前をもったパッチのことだ。

Subversionは、バージョン付けされたツリーを第一階オブジェクトとして扱っており(リポジトリは、ツリーの配列だ)、チェンジセットは(近接のtreeと比較することで得られる)そこからの導出物だ。 ArchやBitkeeperなどのシステムでは、逆の理念の上に作られていて、これらのシステムはチェンジセットを第一階オブジェクトとして管理するように設計されている(リポジトリはパッチの集合体だ)。 ツリーは、パッチの集合を互いに組み合わせることで導出される。

どちらかの哲学が、他方よりも絶対的に素晴しい、というわけではない。 この議論は少なくとも30年は遡れる。 この2つの設計は、ソフトウェア開発のタイプによって、適していたり、そうでなかったりする。 ここでは、この議論を行うのは止めにして、その代わり、Subversionを使ってあなたは何が出来るのか、ということを説明しよう。

Subversionでは、グローバルリビジョン番号「N」は、リポジトリ内のツリーの名前である。 これはN番目のコミットを終えたリポジトリの姿だ。 またこれは暗黙的に一つのチェンジセットの名前にもなる。 もし、ツリーNとツリーN-1を比較すれば、コミットされたパッチそのものを引き出すことが可能だ。

これ故に、「リビジョンN」を、ただツリーとしてだけではなく、チェンジセットとして同様に捉えることも容易い。 もしあなたが要求管理システム(issue tracker)をバグ管理に使っているならば、特定のリビジョン番号を、バグを修正した特定のパッチを参照する為に用いることができる。 例えば、「この問題は、リビジョン9238で修正しました」という具合に。 他の人は 'svn log -r9283' と実行することで、そのバグを修正した完全なチェンジセットに関して読むことが出来るし、'svn diff -r9237:9238'とすれば、パッチそのものを見ることができる。 また、svn の merge コマンドもリビジョン番号を利用する。特定のチェンジセットを、あるブランチから他のブランチへマージするには、そのチェンジセット名を merge の引数へと与えればよい。 'svn merge -r9237:9238 branchURL'は9238番のチェンジセットをあなたの作業コピーへとマージすることになるだろう。

これは、チェンジセットを根源オブジェクトに据えて構築されたシステムみたいに複雑なことは出来ないけれども、でも、CVSよりは凄く便利だよね。

次のリリースは何時?

次のステータスページを参照。http://subversion.tigris.org/project_status.html

他にも質問があるんだけど、何処で情報が入手できるかな?

もし、このFAQの残りを読んでも回答を見付けられなければ、以下のリソースをあたってみると良いだろう。

なんで、メイリングリストへ投稿した私のメイルが流れないの?

我々のメイリングリストでは、SPAM配信を防ぐ為に、モデレータ制を採用している。 その為、何れのリストに対するあなたの最初の投稿も、モデレータがそのメイル流すまでの間、遅延してしまうかもしれない。 一度投稿が認められれば、以後、同じアドレスからの投稿は自動的に承認されるので、遅延状態になることはなくなるだろう。 勿論、あなたの投稿アドレスが変更された場合には、再びモデレータの許可を待つことになるけど。

How-to:

Subversion のコードをチェックアウトするにはどうするの?

Subversion クライアントを使おう。

        $ svn co http://svn.collab.net/repos/svn/trunk subversion

あなたのローカルマシンにある subversion という名前のディレクトリの中へ Sunversion のソースツリーのコピーがチェックアウトされるよ。

リポジトリを作るにはどうするの? その中にデータをインポートするには?

http://svn.collab.net/repos/svn/trunk/READMEを参照。特に「セクションIV」の「Quickstart Guide」参照のこと。

もっと詳しい情報を知りたい人は、The Subversion Bookの5章を読もう。

既存のCVSリポジトリを Subversion リポジトリに変換するには?

cvs2svn という変換ツールを試してみて。 これは、http://cvs2svn.tigris.org/ から取得可能だ(機能リストドキュメントも参照のこと)。 cvs2svn は多くの人々が利用できるように作られてはいるけど、何らかの理由で、このツールがあなたの希望にそぐわないときには、少なくともこれ以外に、2つのツールを試してみることが出来る。

あわせてSubversion linksページも参照のこと。

Proxyサーバに阻まれているんだけどどうしよう?

Subversion クライアントを適切に設定することで、プロキシを超えることが出来るよ。 まずはじめに、「servers」設定ファイルを編集して、どのプロキシサーバを使うか指定しよう。 このファイルが置かれている場所は使っている OS に依存する。 LinuxやUnixでは「~/.subversion」ディレクトリの中に置かれている。 Windowsでは「%APPDATA%\Subversion」中にある(「echo %APPDATA%」を試してみよう。これは隠しディレクトリなので注意)。

このファイルの中には、各要素の説明がコメントとして書かれている。 もしこのファイルが存在しない場合には、最新のSubversionクライアントを入手して、適当なコマンドを実行してみよう。 設定ディレクトリとテンプレートファイルが作成される。

次に、プロキシサーバ自身が、Subversionの利用している全てのHTTPメソッドをサポートしているかどうかを確認する必要がある。 いくつかのプロキシサーバは、標準では、次のメソッド群をサポートしていない: PROPFIND、REPORT、MERGE、MKACTIVITY、CHECKOUT。 一般的に、これを解決する方法、どのプロキシソフトウェアを使っているかに依存する。 例えばSquidでは、設定オプションをこんな風にしてみよう。

   #  TAG: extension_methods
   #       Squid only knows about standardized HTTP request methods.
   #       You can add up to 20 additional "extension" methods here.
   #
   #Default:
   # none
   extension_methods REPORT MERGE MKACTIVITY CHECKOUT

(Squid 2.4以降では、PROPFINDについてはすでにサポートされている)。

プロキシサーバへ通過を許可させる、その他HTTPメソッドに関しては、「Subversionが使っている全ての HTTP メソッドは?」も併せて参照のこと。

プロキシに Subversion トラフィックを通過させるのが難しい、または不可能で、でも Subversion のソースコードをチェックアウトしたい場合には、プロキシを迂回することができるかもしれない。 いくつかのプロキシは、80番ポートをフィルタしているにもかかわらず、81番ポートは何でも許可してたりする。このため、svn.collab.net のリポジトリサーバは、80番ポートと同様に81番でも待ち受けている。 というわけで、

   svn checkout http://svn.collab.net:81/repos/svn/trunk subversion

を試してみよう。もしかすると、プロキシは素通ししてくれるかもしれない。 別の戦略としては、SSL上でチェックアウトする、というのもあって、多くのプロキシがこれを許可している。

   svn checkout https://svn.collab.net/repos/svn/trunk subversion

勿論、あなたの使っている svn クライアントが、SSLサポートを有効にしてビルドされている必要がある。 これには./configureスクリプトへ --with-sslを渡せばよい。 「https」スキームをサポートしているかどうかは、svn --versionで確認することができるよ。

僕の管理者は、Subversion用のHTTPサーバを建てて欲しくないみたいなんだ。それでも僕はリモートから使いたいんだけど、どうしたらいいかな?

簡単な案は、Apache ではなくsvnserveサーバを使うこと。 詳細は、Subversionブックの第6章を参照のこと。

でも、もしあなたの管理者がApacheの実行を認めてくれないんだったら、3690番ポートでカスタムサーバプロセスを実行するのも認めてくれそうにないよね! というわけで、残りの回答は、管理者が既存のSSHインフラを使うことを許可してくれたら、って想定で書きます。

もし、以前にCVSサーバを使っていたのだとすれば、多分、CVSサーバへログインするのに SSH を使っていた筈。 ra_svn Subversion アクセス手法は、Subversion で、これと同等のことを実現するための方法だ。 ただ Subversion リポジトリURLの前に「svn+ssh」を付けるだけで良い。

$ svn checkout svn+ssh://your.domain.com/full/path/to/repository

これにより、SSHプログラムがリモートマシン上でプライベートな「svnserve」プロセスを稼動させ、あなたのUIDによるリポジトリアクセスや、暗号化されたリンク上での情報トンネリングを司ってくれる。

また、これとは別の解決策としては、SSHポートフォワーディングの力を借りて、保護されているサーバへ ra_dav 経由で接続する、というのもある。 SSHを経由することで、ファイアウォールの背後に位置している、Subversion サーバへアクセス可能なマシンへと接続することができるだろう。 SSHサーバが、Subversionのインストールされたサーバと同じでマシンでなくてもよい、という点に注目して欲しい。 もちろん同じでも構わないけど、同じである必要性はない。

まずは、Subversionリポジトリを提供しているHTTPサーバへと接続する為の、ローカルなポートフォワードを作る。 それから、このローカルポートを経由してSubversionサーバへ「接続」する。 これで、リクエストがSSHサーバを経由して、Subversionサーバへ「トンネル」されることになる。

例を示そう。ra_dav の設定された Subversion サーバが、会社のファイアウォールの背後に立っている。 IPアドレスは10.1.1.50 だ(このサーバを、svn-server.example.comと呼ぼう)。 会社は、皆がアクセス可能な ssh-server.example.com 経由でのSSHアクセスを許可している。 内部的には、Subversion リポジトリへ http://svn-server.example.com/repos/ours 経由でアクセスできる。

: クライアントは、ポートフォワーディングを使ってssh-serverへ接続し、そのポートフォワードを経由して、チェックアウトする。

% ssh -L 8888:svn-server.example.com:80 me@ssh-server.example.com
% svn checkout http://localhost:8888/repos/ours

svn-server.example.com は、non-trustedユーザによる、非特権ポート上で稼動している httpd インスタンスでも構わないことに注意しよう。 この方法では、Subversion サーバに対して root アクセス権限を必須とはしない。

Joe Orton は以下を注記してくれた。

サーバは、MOVEならびにCOPYリクエストの同期先のヘッダで使われているホスト名に敏感なので、この個所には少し注意を払う必要がある。
この方法を上手く機能させる為には、「ServerAlias localhost」が必要になるかもしれない。

SSHポートフォワーディングに関する幾つかのリンクはこちら。

幾つかの異なるプロジェクトを Subversion で管理するにはどうすれば?

それは取り扱うプロジェクトに依存する。 もしそれらのプロジェクトに関連性があって、データを共有する可能性があるなら、一つのリポジトリ内に幾つかのサブディレクトリを作るという方法が最良だ。 例えばこんな感じ。

        $ svnadmin create /repo/svn
        $ svn mkdir file:///repo/svn/projA
        $ svn mkdir file:///repo/svn/projB
        $ svn mkdir file:///repo/svn/projC

もし、それらのプロジェクトが完全に関係性がなく、プロジェクト間でデータを共有する可能性がないのなら、恐らく、独立した無関係のリポジトリを作るのがベストだろう。

        $ mkdir /repo/svn
        $ svnadmin create /repo/svn/projA
        $ svnadmin create /repo/svn/projB
        $ svnadmin create /repo/svn/projC

この二つのアプローチの差は、(Ben Collins-Sussman<sussman@collab.net>によれば)次の通り。

  • 最初のケースでは、プロジェクト間でコードのコピーや移動が簡単に実行でき、履歴も保存される(今のところ、'svn cp/mv'は、単一リポジトリの中でしか動作しない)。
  • リビジョン番号はリポジトリ全体で共有されるから、最初のケースでは、如何なるプロジェクトに対する単一コミットも、グローバルなリビジョン番号の引き上げが発生する。というわけで、もし、誰かがprojBをチェックアウトしていて、10リビジョンが進んでいることに気がついても、実は、projB自体はちっとも変化していない、ということが起こるわけで、これは、少し奇妙に思えるかもしれない。 まぁ、実際には、大したことないよね。ちょっと不思議な気がするのは、最初だけ。 この現象、rapidsvn が同じリポジトリにあった時には、rapidsvn へのコミットが発生する度に svn で起こっていたことだから :-)。
  • 2番目のケースの方が、安全性の維持は簡単になると思う。 Apacheのアクセスコントロールを使うことにより、(ユーザとパーミッションという面で)プロジェクトを互いに隔離することが容易になる。最初のケースでは、リポジトリに対し、プロジェクトを区別するための小さなスクリプトが必要になるだろう(「このユーザは、このディレクトリ以下へのコミットは許可されている?」)。 勿論、この為のスクリプトは提供されているので、それを使うことは可能だよ。

完全に分離している二つのリポジトリをマージするにはどうすればよい?

片方のリポジトリについて、履歴の完全な維持、という点を気にしないのであれば、一つのプロジェクトの下へ単に新しいディレクトリを作った上で、そこへもう片方のデータをインポートすれば良い。

もし、両方のリポジトリの履歴を維持したいのならば、'svnadmin dump'を使って片方のリポジトリのダンプを取り、'svnadmin load'で、そのダンプをもう片方のリポジトリへロードすることになる。 リビジョン番号は変わっちゃうけれど、でも履歴は維持できるよ。

Peter Davis <peter@pdavis.cx>は、svnが有するCVSモジュール同様の機能を使う方法について述べている。

異なるディレクトリツリーのマージを行うのであれば、CVSモジュールのsvn版を使うことが出来るよ。

svn:externalsプロパティをディレクトリにセットしよう。これで、オリジナルディレクトリがチェックアウトする時には何時でも、他のリポジトリからディレクトリをチェックアウトさせることが出来るようになる。 リポジトリの分離を維持したまま、作業コピー上では、それらがマージされたかの様に見える。 インポートされたディレクトリへコミットすれば、外部のリポジトリに対して効果が発生する。

このマージは完全にはクリーンではない。インポートは作業コピーにしか影響を及ぼさないから、二番目のリポジトリからインポートされたモジュールへアクセスするために、最初のリポジトリのURLを使うことは出来ない。 両者は異なるURLのままなんだ。

あわせてmiscellaneous utilitiesも探して見よう。 複数のリポジトリをマージする時に、リビジョンの選択や並び換えを行うために役に立つツールを見つけることが出来る。 特に、基本的な操作を行うためにはsvn-merge-repos.plという perl スクリプトが、また、より高度な再編成を行う際にはSvnDumpToolという python クラスが有益だ。

私のレポジトリや作業コピー、NFSサーバ上に置くべきでしょうか?

もしあなたのリポジトリが、Berkeley DB をバックエンドに使っているならば(Subversion 1.0と1.1で作られたリポジトリでは、これがデフォルト。それ以降の版ではデフォルトではない)、リモートファイルシステム(例えば、NFS)上にリポジトリを置くことはお勧めしない。 Berkeley DBのデータベースとログファイルをリモートファイルシステム上に格納することは出来るが、Berkeley DB の共有リージョンファイルをリモートファイルシステム上へ格納することは出来ないから、リポジトリは、たった1台のファイルシステムクライアントからしかアクセスできないだろうし、また、1台のクライアントにすら提供できないSubversionの機能も存在するだろう。

もしあなたがリポジトリのバックエンドにFSFSを使っているならば、リポジトリを最近のNFSサーバ(即ち、lockをサポートしている、ってこと)上に格納しても大丈夫だろう。

作業コピーはNFS上へ格納することができる(基本的なところでは、ホームディレクトリがNFSサーバ上に位置している、というのがある)。 Subversionは、チェックアウト時、大量のリネーム処理を内部的に行っている為、LinuxのNFSサーバを使う場合には'subtree checking'を無効化すべきだ、との報告がある(デフォルトでは有効になっている)。 subtree checking を無効化する方法については、NFS Howto Server Guideとexports(5)を参照のこと。

我々は、少なくとも1通、SMBでアクセスした後、作業コピーがWedged になった、というレポートを受け取っている。問題のサーバはやや古めのバージョン(2.2.7a)のSambaを稼動していた。この問題は新しめのSamba(3.0.6)では再発していない。

なんで、私のリポジトリ、こんなにディスクスペース喰うの?

リポジトリは、あなたの全てのデータを、リポジトリの /db/ サブディレクトリ内にある Berkeley DBの「環境」内に蓄積している。 この環境は、テーブルの集合やログファイル(log.*) の束を格納している。Berkeley DB はテーブルに行われた全ての変更を記録するので、実行が遮られた場合でも、首尾一貫した状態へと復元することが可能だ(詳細はこちら)。

ログファイルは永遠に成長を続け、あなたが(リポジトリ管理者として)何らの処理を行わない限りは、ディスク空間を食いつづけるだろう。ある時点で、Berkeley DB が実際に使用するログファイルは僅かでしかない(この投稿と続くスレッドを参照)。 というわけで、残りは安全に削除することができる。もし、あなたが全てのログファイルを永遠に保存しておくのであれば、Berkeley DBは、リポジトリがこの世に生を受け手から後、施された全ての変更を、理論上は再現することが出来ることになる。 でも現実的には、もしバックアップをとっているなら、多分、ディスク空間という面で、コストに見合わないと思うよ。

どのファイルが削除可能かを確認するためには、svnadmin を使おう。cron でこんな感じのジョブを実行すると良いだろう。

$ svnadmin list-unused-dblogs /repos
/repos/db/log.000003
/repos/db/log.000004
[...]

$ svnadmin list-unused-dblogs /repos | xargs rm
# ディスク空間を取り戻した!

この変わりに、Berkeley DB の db_archiveコマンドを使うこともできる。

$ db_archive -a -h /repos/db | xargs rm
# ディスク空間を取り戻した!

svnadmin hotcopyhotbackup.pyも参照のこと。

注意:もしあなたが Berkeley DB 4.2 を使っているならば、Subversion は、自動ログ削除機能を有効にしてリポジトリを作成しているだろう。 svnadmin createを実行時に、--bdb-log-keepオプションを指定することで、これを変更することが可能だ。 Berkeley DBマニュアルに書かれた DB_LOG_AUTOREMOVEフラグを参照のこと。

どうしたら、リポジトリのパーミションを正しく設定できる?

リポジトリにアクセスできるユーザの数を、極力少なくしよう。例えば、apache や 'svnserve -d'を特定ユーザで起動し、リポジトリ全体をそのユーザの所有にする。他のユーザには、file:///URL経由でのリポジトリアクセスを許可しないようにし、また 'svnlook' や 'svnadmin' は、そのリポジトリ所有者権限でだけ実行されるようにしよう。

もしクライアントが、file:///svn+ssh://経由でアクセスするならば、複数ユーザからのアクセスを無効化させる方法は存在しない。 この場合、第6章の最終セクションを読んで、下のほうにある「チェックリスト」サイドバーへ十分注意を払おう。 このリストには、このシナリオを安全に行う為の幾つかのステップが概説されている。

注意: SELinux / Fedora Core 3+ / Red Hat Enterpriseをお使いの方々へ

通常の Unix パーミッションに加え、SELinuxの元では、全てのファイル、ディレクトリ、プロセスなどが「セキュリティコンテキスト」を有している。 プロセスがファイルへアクセスしようとした場合、Unixパーミションチェックの他に、システムは、プロセスのセキュリティコンテキストが、ファイルのコンテキストと互換性があるかを確認しようとする。

Fedora Core 3 は(他にも同様のシステムはあるけど)、SELinux が標準でインストールされ、また設定されるので、Apacheは非常に制限されたセキュリティコンテキストの中で実行されることになる。 SubversionをApacheの元で動作させる為には、Apacheからのアクセスを許可するよう、リポジトリのセキュリティコンテキストを設定しなければならない(もしくは、この制限機能はちょっと過剰だなぁ、と思うならば、Apache側で制限を無効化しよう)。 ファイルのセキュリティコンテキストを設定するためには、chcon コマンドが使われる(chmodが伝統的なUNIXパーミッションをセットするのと似た方法だ)。 例えば、リポジトリへ問題なくアクセスできるようにする為には、次のコマンドを実行し、

   $ chcon -R -h -t httpd_sys_content_t PATH_TO_REPOSITORY

セキュリティコンテキストを設定しなければならないだろう。

リードオンリーの操作を行う場合にも、リポジトリへ書きこみ権限が必要になるのはなぜ?

ある種のクライアント操作、例えば、チェックアウトや更新は「リードオンリー」だ。 アクセスコントロールという観点で言えば、Apacheはこれらの操作をその様に扱う。 しかし、libsvn_fs(リポジトリファイルシステムAPI)は、ツリー差分を生成する為、一時データを書き込む必要がある。 その為、リポジトリへアクセスするプロセスが機能する為には、Berkeley DBに対して、常に読み込み書き込みのアクセスが必要になる。

特に、リポジトリは、多くの「リードオンリー」操作に対し、2つのツリーを比較する事で対応する。 1つのツリーは、大抵 HEADリビジョンで、もう片方は概ね一時的なトランザクションツリーだ。というわけで、書き込み権限が必要になる。

この制限は、Berkeley DBをバックエンドを使っている場合にだけ生じ、FSFSバックエンドでは発生しない。

リポジトリのヒストリーから、完全にファイルを消去するには、どうしたらよいの?

ファイルやコミットに関する全ての痕跡を完全に消し去りたい、という特別な場合がある(例えば、誰かが間違えて、極秘ドキュメントをコミットしちゃった、とか)。 これは、そう簡単な話ではない。 というのも、Subversionは決して情報を失うことのないよう、よくよく考えて設計されているのだから。 リビジョンは、他のリビジョンの上に構築される、不変のツリーだ。 あるリビジョンを履歴上から除去した場合、ドミノ倒しのように以降に続く全てのリビジョンを目茶苦茶にしてしまい、恐らく全ての作業コピーがだめになってしまうだろう。

とはいえ、プロジェクトとしては、いつの日か、svnadmin obliterate コマンドを実装する、というプランを持っている。 このコマンドを使うことで、情報を永久に消し去ることが出来るようになるだろう(issue 516を参照の事)。

それまでの間は、あなたの取り得る手段としては、svnadmin dumpでリポジトリのダンプを取り、そのファイルをパイプ経由でsvndumpfilterを通過させ(不正なパスを取り除く)、その出力をsvnadmin loadコマンドへ読み込ませる、ということになる。 詳細は、Subversion bookの第5章を参照の事。

コミット済みリビジョンのログメッセージを変更するには?

ログメッセージは、各リビジョンの属性として貼り付けられた上で、リポジトリに中に保存されている。 デフォルトでは、一度コミットされてしまったログメッセージ属性(svn:log)は、変更することが出来ない。 これは、リビジョン属性(svn:logはその中の一つ)への変更は、以前のプロパティ値を完全に廃棄してしまう為で、この操作が誤って実行されないよう、Subversionは、あなたを守ってくれている、というわけだ。 とは言え、リビジョン属性を変更する為の方法は、幾つか存在する。

最初の方法は、リビジョン属性の変更を有効にしたいリポジトリ管理者向けのものだ。 これは「pre-revprop-change」と呼ばれるフックを作ることで実現される(実現方法の詳細に関しては、Subversion book のこのセクションを参照)。 この「pre-revprop-change」フックは、ログメッセージが変更される前に、古いログへアクセスするので、何らかの方法(例えば、メイルで送る、など)により、このログを保存することは可能だ。 ひとたびリビジョン属性の変更が有効化されれば、svn propeditsvn propsetへ--revpropスイッチを引き渡すことでリビジョンのログメッセージ変更が可能になる。例えば、こんな感じ。

$ svn propedit -r N --revprop svn:log URL
$ svn propset -r N --revprop svn:log "new log message" URL

ここで N は、ログメッセージを変更したいと思っているリビジョンの番号で、URLはリポジトリの場所。 もし、このコマンドを作業コピーの中で実行するのであれば、URLを指定する必要はない。

ログメッセージを変更する2番目の方法は、svnadmin setlogを使う方法。 これは、ファイルシステム上のリポジトリの場所を指定して実行しなければならない。 リモートのリポジトリを、このコマンドを使用して変更することはできない。

$ svnadmin setlog REPOS_PATH -r N FILE

REPOS_PATHにはリポジトリの場所を、N には変更したいログメッセージのリビジョン番号を、FILEには新しいログメッセージの書かれているファイルを指定する。 もし「pre-revprop-change」フックが適切に動作していない(または、何らかの理由で、フックスクリプトを迂回したい)場合には、--bypass-hooks オプションが利用可能だ。 しかし、このオプションを使う場合には、十分に注意すること。例えば、メイルによる変更伝達や、リビジョン属性を追跡するためのバックアップシステムを迂回してしまうことになるかもしれない。

Subversion のパッチ、どうやって送ればよいかな?

まず最初に、Hacker's Guide to Subversionを読むこと。

熟読したら、[PATCH]という単語と1行説明をサブジェクトに記述し、(あなたの MUA がメイルをぐちゃぐちゃにしてしまわないことが前提で)パッチをメイル内へインラインで取り込んだ上で、そのメイルをdevリストへ送ろう。 その後、コミッタはそれを拾い上げ、適用を行い(必要に応じてフォーマットや内容の変更が行われる)、チェックインすることになる。

基本的な手順はこんな感じ。

        $ svn co http://svn.collab.net/repos/svn/trunk subversion
        $ cd subversion/www

                [ make changes to faq.html ]
        
        $ svn diff faq.html > /tmp/foo

        $ Mail -s "[PATCH] FAQ updates" < /tmp/foo

勿論、Hacker's Guide to Subversionに従って、あなたのメイルには、そのパッチが何を為してくれるのか、という点に関する、分かりやすい十分な長さの説明文が含まれている筈。 って、説明するまでもないよね。だって、実際にコードをハックし始めるに、既にこのガイドを読んで、完全に理解しているんだもんね :)

その場 'import'ってどうやるの? つまり、オリジナルデータがそのまま作業コピーとなるように Subversion へツリーを追加したいんだけど。

例えば、/etc 内の幾つかを、あなたのリポジトリ内で、バージョン管理下に置きたいのだと仮定してみよう。

     # svn mkdir file:///root/svn-repository/etc \
         -m "リポジトリ内に/etcに対応するディレクトリを作る"
     # cd /etc
     # svn checkout file:///root/svn-repository/etc .
     # svn add apache samba alsa X11 
     # svn commit -m "僕の設定ファイル群への最初のバージョン"

ここでは、ちょっと見珍しい、svn checkoutの便利な機能を使っている。 ディレクトリを、リポジトリから既存のディレクトリ内に対して、直接チェックアウトすることができる。 まず最初に新しい空のディレクトリをリポジトリの中へ作る。 それから、それを/etcの中にチェックアウト。 これで/etcは作業コピーへと変化する。 一度この作業が済んだ後は、普通にsvn addコマンドをつかって、ファイルやサブツリー群をリポジトリへ追加することができる。

svn import を強化して、インポートされたツリーを自動的に作業コピーへ変換できるようにする、というのは課題だ。issue 1328を参照。

Subversion サーバのアップグレードについて語るとき、時々話に出てくる「ダンプ/ロードサイクル」ってなんのこと?

サブバージョンのリポジトリデータベーススキーマは、開発中、まれに変更になる場合がある。古いリポジトリ(Subverision 1.0 より前の開発版で作られたもの)は、アップグレードをする際、以下の手順が必要になるかも知れない。 もし、スキーマ変更が、Subversionリリース X と Yの間で起こった場合、Yへとアップグレードするリポジトリ管理者は、以下手順を踏む必要がある。

  1. svnserveやApache、その他リポジトリへアクセスするかもしれないものを、シャットダウンする。
  2. svnadmin dump /path/to/repository > dumpfile.txt を実行する。svnadmin は、バージョン X のものを使うこと。
  3. mv /path/to/repository /path/to/saved-old-repository (即ち、既存リポジトリをリネームしておく)
  4. Subverion を Y へアップグレードする(つまり、Yをビルド後インストールして、Xを置き換える)
  5. svnadmin create /path/to/repositoryを実行。バージョンYの svnadmin を使うこと。
  6. svnadmin load /path/to/repository < dumpfile.txt。ここでも、バージョンYのsvnadminを使用。
  7. フックスクリプトなどを、古いリポジトリから新しいリポジトリへコピー。
  8. svnserveやApacheを再起動。

ダンプとロードの方法の詳細に関しては、Subversion bookのこのセクションを参照のこと。

注意: Subversion のほとんどのアップグレード時には、ダンプやロードは必要ない。 これが必要になる場合、リリースアナウンスや、新版の CHANGES ファイルで、十分な告知がなされるだろう。 もしあなたがその様な告知を目にしていないのであれば、それはスキーマに変更はない、ということであり、ダンプ/ロードも必要ない。

SSPI認証を使って、Windows ドメインコントローラに対して認証を行い、クライアントへ許可を与えたいんだけど、どうすればよい?

TortoiseSVNには、Windows 上で Subversion サーバを設定する為の、素晴らしいドキュメントが同梱されている。 http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-serversetup.html#tsvn-serversetup-apache-5へアクセスして、SSPI認証のセクションを参照してみよう。

設定上の重要な箇所は、次の行。

   SSPIOfferBasic On

この行が無くても、SSPIをサポートしているブラウザでは、ユーザのクレデンシャルを要求するだろう。 しかし、SubversionのようなSSPIをサポートしていないクライアントは要求しない(現在のリリースのNeon(SubversionのHTTPライブラリのこと)は、ベーシック認証しか扱えない)。 クライアントが決してクレデンシャルを要求しない為、認証を必要とする操作はすべて失敗となる。 この行を加えることにより、mod_auth_sspiに対して、クライアントに対してはベーシック認証を使うことを、一方で、クレデンシャルの認証を行うためには、Windowsドメインコントローラを用いることを、指示することになる。

「.svn」っていうディレクトリの名前、好きじゃないんだ。「SVN」とかの方が嬉しいんだけど、どこ変えれば良いの?

我々としては、可能な限り「.svn」と生活を共にすることをお勧めするよ。 とは言え、Windows上でASP.NETを使っているならば、 ここ で説明しているようにSVN_ASP_DOT_NET_HACK環境変数を設定する必要があるかもしれない。

または、完全にカスタムな名前を管理用ディレクトリの名前として使うことも可能だろう。 我々としては、これはお勧めしない。と言うのも、あなたの作業コピーは、多分、あなたがカスタマイズした以外のSubversionクライアントでは使えないだろうから。 しかし、どうしてもやらなければならない、というのであれば、ただsubversion/include/svn_wc.h

#define SVN_WC_ADM_DIR_NAME   ".svn"

を、例えば、

#define SVN_WC_ADM_DIR_NAME   "SVN"

へと変更し、クライアントを再コンパイルすれば良い。

ファイル名の大文字小文字変換をするには?

この問題は、2つの状況で発生する。 Windows のような大文字小文字(つまり文字ケース)を区別しないファイルシステム上でファイルを追加した場合、意図せずファイル名の文字ケースが誤った状態で登録してしまったことに気がついたのかもしれない。 あるいは、単に、リポジトリ内にある既存ファイルの大文字小文字を変更したい、と考えたのかもしれない。

もしあなたが、文字ケースを区別するファイルシステムを使っているならば、全く問題はない。ただファイルを新しい名前に変更するだけだ。例えばこんな感じ。

svn mv file.java File.java

しかし、これは、Windowsのような大文字小文字を区別しないOS上では上手くいかないだろう。 Windows上でこれを実現するためには、ファイルをどこかへ一時的にコピーしておき、Subversion上からそのファイルを消した後、そのコピーを正しい文字ケースで追加することになる。 また、より良い方法は、Subversion URL を使って、move 操作を実行することだ。URLを使う方法がお薦めで、なぜなら、そのファイルの履歴が保存されるし、すぐに結果が反映されるることになるから。

とはいえ、どちらの方法も Windows 上の作業コピーには問題を残す。 というのも、名前の競合したファイルを更新する時、Windows は未だ混乱に陥るからだ(多分、次のようなメッセージが表示されるだろう。 svn: Failed to add file 'File.java': object of the same name already exists)。 この問題を解決する方法の1つは、ワーキングコピーを削除して、チェックアウトし直すことだ。 もし、これをしたくない場合には、2段階の更新手順を踏まなければならない。

大文字小文字の間違っている各ファイルに対して、次のコマンドを実行し、文字ケースを変更する。

svn mv svn://svnserver/path/to/file.java svn://svnserver/path/to/File.java

作業コピーを更新するため、適切なディレクトリへ移動して、次の操作を実行。

svn update file.java
svn update

最初の更新処理で、file.javaを作業コピーから消し去り、次の更新処理でFile.javaを追加して、作業コピーを正しい状態にする。 もし、問題のあるファイルが数多く存在するならば、次の方法で、作業コピーを更新することも可能だ。

svn update *
svn update

今まで見てきたように、間違った文字ケースで追加されたファイルを、文字ケースを区別しないOS上で修正するのは、骨が折れる。 是非、ファイルを最初に登録する時点で、正しく登録するようにしよう! 最初からこの問題を防ぐために、check-case-insensitive.plファイルを呼び出すpre-commitフックを作成すれば良い。 このファイルは、Subversion ソース tarball 内の、contrib/hook-scriptsディレクトリ内に置かれている。

branchからtrunkへマージする際、CVS でやってたように、tag を使いたいんだけど、出来ないんだよね?

以下で示すように、リビジョン番号を覚えることなく、branch からtrunk へマージを行なうことが可能だよ。また、その逆も可能(例には示してないけどね)。

以下の例では、/home/reposという既存リポジトリがあり、この中にbarという名前の branch を作りたいということを、また、このbranch は、fooという名前の編集対象ファイルを含んでいることを仮定している。

branch のマージトラックするため、このリポジトリには、tags/branch_traces というタグを記録しておくための場所が用意されている。

# ブランチとタグをセットアップ
$ svn copy file:///home/repos/trunk \
           file:///home/repos/branches/bar_branch \
           -m "start of bar branch"
$ svn copy file:///home/repos/branches/bar_branch \
           file:///home/repos/tags/branch_traces/bar_last_merge \
           -m "start"

# brach の作業コピーをチェックアウト
$ svn checkout file:///home/repos/branches/bar_branch wc
$ cd wc

# foo.txt ファイルを編集して commit。
$ echo "some text" >>foo.txt
$ svn commit -m "edited foo"

# trunk へ switch して、変更点を branch からマージ
$ svn switch file:///home/repos/trunk
$ svn merge file:///home/repos/tags/branch_traces/bar_last_merge \
            file:///home/repos/branches/bar_branch

# ここで foo.txt の中身を確認してみよう。先の変更が取り込まれているはず。 

# マージをcommit。
$ svn commit -m "Merge change X from bar_branch."

# 最後に、現在の状態を反映しておく為、追跡用 branch を更新。
$ svn delete -m "Remove old trace branch in preparation for refresh." \
             file:///home/repos/tags/branch_traces/bar_last_merge
$ svn copy file:///home/repos/branches/bar_branch                     \
           file:///home/repos/tags/branch_traces/bar_last_merge       \
           -m "Reflect merge of change X."

どうして $Revision$ キーワードが、僕の望んだとおりになってくれないの? これ、ファイルの最終変更リビジョンへ展開されるけど、でも、僕はファイルの現在のリビジョンとかになって欲しいんだ。

Subversion ではリポジトリー全体でリビジョン番号が増加してゆくから、どのキーワードもその番号へ変更することはできない。 それをやろうとすれば、毎更新とコミット時、作業コピーの中にある全てのファイルを検索し、恐らく更新してまわるはめになるだろう。

あなたが欲しい情報(作業コピーのリビジョン)は、svnrevisionコマンドを使って取得することが出来る。 これは、与えられたパスの作業コピーに対するリビジョン番号情報を表示してくれる(詳細はsvnversion --helpを参照のこと)。

これをビルドやリリースプロセスに統合することで、ソース自身にこの情報を引き渡すことが可能だ。 例えば、GNU makeを使ったビルド環境では、Makefileこのような処理を加えれば良い。

##
## これを使うには、yourfile.c の中で次のような感じにすればよい
## printf("このプログラムは SVN の revision %s からコンパイルされました\n",SVN_REV);
##

SVNDEF := -D'SVN_REV="$(shell svnversion -n .)"'
CFLAGS := $(SVNDEF) ... continue with your other flags ...

(これは、GNU版ではないmakeでは動作しないかも知れないことに注意。 もしあなたのビルドプロセスがポータビリティを必要としているならば、この方法を使ってはならない)

または、こんなのをどうぞ。

##
## すべてのビルドで、作業コピーのリビジョン文字列を記録する
##
svn_version.c: FORCE
    echo -n 'const char* svn_version(void) { const char* SVN_Version = "' \
                                       > svn_version.c
    svnversion -n .                   >> svn_version.c
    echo '"; return SVN_Version; }'   >> svn_version.c

##
## これで、svn_version.o をリンクするすべての実行ファイルは、
## svn_version() 関数を呼び出すことが出来る。この関数では、
## ビルドが行われたまさにその時のリビジョン番号の記載された
## 文字列を取得することが可能だ。
##

Windowsユーザは、SubWCRev.exeコマンドが使えるだろう。 これは、TortoiseSVNのダウンロードページから入手できる。 これは、指定されたファイル中に書かれている全ての $WCREV$ タグを、現在の作業コピーのリビジョンへと置き換える。

Subversion には、CVS で言うところの $Log$ のように機能するキーワードは存在しないの?

存在しない。 CVSの $Log$ と同等品は存在しないんだ。 もし、特定ファイルのログを取得したいのならば、'svn log your-file-name'を実行するか、'svn log url-to-your-file'を実行すればよい。 なぜ、$Log$ がマズイかを説明した、メイリングリストに流れた記述を次に。

"$Log$ は、branch間の変更をマージし始めた途端、全く持って恐怖となる。
ほとんど確実にその箇所で競合が生じることになり(なぜって、それがこのキーワードの特質だから)、自動的な競合の解消は、どうやっても不可能となる。"

加えて、次の通り。

Subversion のログメッセージは可変であり、svn:log リビジョン属性を用いることで変更することができる。
だから、あるファイルで$Log$を展開したとしても、古い内容となってしまっている可能性がある。
更新処理では、$Log$ キーワードへ遭遇する度に、実際にはそのファイルが変更されていない場合であっても、適切なログメッセージを取得しなければならならなくなるだろう。

僕はそんなことは気にしないよ。どうであれ、それを使いたいんだ。実装する気はない?

ない。 我々は、それを実装する気も、この機能を実装したパッチを受け入れる気もない。 もしあなたが、changelog 等を含んだファイルを配布したい、と考えているのならば、ビルドシステムで、この制約を回避できると思う。

我々のプロジェクトには、全ての開発者が変更しなければならないファイルがあるのですが、でも、私はそれらローカルの変更をコミットして欲しくないんです。 どうやって、'svn commit' にそのファイルを無視させれば良いでしょう?

回答: その手のファイルは、バージョン管理下に置かないようにしよう。 その変わりに、そのファイルのテンプレートを、「file.tmpl」といった名前で、バージョン管理下に置こう。

そして最初の 'svn checkout' 実行後、そのテンプレートを、あなたのユーザ(または、あなたのビルドシステム)に、普通のOSのコピーを使って適切な名前でコピーさせ、そのコピーをカスタマイズさせる。 このファイルはバージョン管理されていないから、決してコミットされることはないだろう。 またあなたが望むなら、そのファイルを、上位ディレクトリの svn:ignore 属性へ追加することも出来る。 こうすれば、'svn status' コマンドを実行しても、'?' のように表示されることはなくなるよ。

リポジトリへsvn+sshを使ってアクセスすると、パスワードが ~/.subversion/auth へキャッシュされないんだ。 何度もパスワードを入力しないで済ます方法は?

ssh は独自のパスフレーズを有していて、独自の認証キャッシュ機構を備えている。 この認証キャッシュは Subversion 外にあるので、Subversion とは独立して設定しなければならない。

OpenSSH には、ssh-ketgen という鍵生成プログラムと、ssh-agent というパスフレーズキャッシュプログラム、そして、ssh-addという、パスフレーズをエージェントのキャッシュへ追加するプログラムが同梱されている。 ssh-agentを簡単に使う為に人気のあるスクリプトがkeychain だ。Windows では、ssh の有名な代替クライアントとしてPuTTY がある。 OpenSSH の鍵をインポートする為には、PuTTYgen を、パスフレーズをキャッシュする為には、pageant を参照の事。

ssh-agentの設定方法はこのドキュメントの範疇外だけど、Googleで、ssh-agent を検索すれば、すぐに回答を得られるだろう。 もの凄く せっかちなあなたは、次のリンクを参照のこと。

   http://mah.everybody.org/docs/ssh
   http://kimmo.suominen.com/docs/ssh/

僕のsvnserveバイナリがインストールされているディレクトリは、は、僕のユーザ達のデフォルトPATHへは含まれていなくて、彼らはsvn+ssh を使うんだけど、svnserveを実行できるように、彼らのPATHを変更する方法が分からないんだ。

注意: ここでは、あなたが OpenSSH を使っていると仮定している。 世の中には、他のssh実装も存在していて、恐らく、それら実装でも同じようなことが出来るとは思うんだけど、詳細を把握していない。

あなたは、色々な login ファイル、例えば .bash_profile等と格闘して、でもどうにもならなかったんだね! これは、Subversion クライアントが ssh を起動するとき、ssh は、それらのファイルを無視する為だ。 でも、PATHを変更する必要なんてないんだ。そのかわりに ssh へ直接svnserveコマンドのフルパスを教えてやれば良い。 ここでは、その方法を説明しよう。

svn+ssh アクセスが必要な各ユーザに対して、Subversion 専用の(つまり、通常、ログインでは使わない)新しい ssh のpublic-keyペアを生成しよう。 そのキーペアには、特別の名前を付けておこう。 例えば、~/.ssh/id_dsa.subversion といった具合だ。 その鍵のうち、公開鍵を、サーバマシン上にある彼らの ~/.ssh/authorized_keysファイルへ追記する。 但し、行の先頭、ssh-rasssh-dssという語の前に、ちょっとだけマジックを挿入してね。

before
ssh-dss AAAAB3Nblahblahblahblah
after
command="/opt/subversion/bin/svnserve -t" ssh-dss AAAAB3Nblahblahblahblah

当然、/opt/subversion/bin/svnserveは、あなたの環境に適した値へ置き換えること。 また、Subversion リポジトリへのフルパスを、(-rオプションを使って)コマンドへ指定しても良いだろう。 ユーザはタイピングする手間を少し省くことができる。

このcommand=マジックは、例えユーザが、他のコマンドを実行しようとした場合でも、リモートマシンの sshd に対し、svnserve を実行させるように仕向ける。 詳細は sshd(8) のマニュアルページ(AUTHORIZED_KEYS FILE FORMATセクション)を参照のこと。

さて、あなたのユーザが Subversion クライアントを実行する際には、彼らのキーペアの秘密鍵が「指示されている」SVN_SSH環境変数が設定されていることを確認しよう。 (Bourne Again シェルでは)こんな感じになる。

SVN_SSH="ssh -i $HOME/.ssh/id_dsa.subversion"
export SVN_SSH

このファイルでは、この問題をより深く解説しているよ。

svn+ssh://経由でのアクセスを許可したいんだけど、私、パラノイアなんだよね。各ユーザへ login を許可する、ってのは嫌なんだ。 だって、彼らが私のマシンへのアクセス許可を持った人間なのかどうかって、気にしなきゃならなくなるから。

他の質問への回答だけど、この中に書かれた~/.ssh/authorized_keysファイルのハックに関するセクションを参照のこと。 svnserveをPATHへ含める件に関しては、無視してよいよ。

リポジトリにある全てのものに対して、特定のプロパティを付与するにはどうすればよい? また、どうやったら、リポジトリに登録される全ての新規ファイルへ、そのプロパティを付与できる?

Subversion はファイルのコンテンツをデフォルトでは変更しない。 もし変更したい場合には、ファイルに対し、明示的にsvn:eol-stylesvn:keywordsプロパティを設定する必要がある。 これが Subversion を CVSのデフォルト動作よりもずっと安全なものにしているだけど、この安全さは、ある種の不便さも引き起こす。

最初の質問に応えよう。既にリポジトリへ格納されている全てのファイルへ属性を付与する為には、面倒な作業が必要になる。やり方は、(作業コピー内にある)全てのファイルに対してsvn propsetを実行し、それをsvn commitすること、せいぜいこれだけだ。 多分、スクリプトを書くと作業が楽になると思う。

では、新規ファイルはに関してはどうだろう? 生憎、コミットされかかっているファイルに対して、サーバ側で属性を自動的に与える仕組みは用意されていないんだ。 これは、全てのユーザは、ファイルをsvn addする度、忘れずに、属性を適切に設定せねばならない、ということを意味する。幸い、この作業を補助するクライアントサイドのツールがある。 Subversion Book の auto-props機能に関して読んでみよう。 全てのユーザがクライアントの auto-props 設定を適切に行っているかどうかを、あなたは確認する必要がある。

また、ファイル属性を付け忘れた新規ファイルのコミットを拒否する pre-commit フックスクリプトを書くことも可能だ(例えば、http://svn.collab.net/repos/svn/trunk/contrib/hook-scripts/check-mime-type.plを参照)。 でもこのアプローチは、やりすぎかもしれない。例えば、もしsvn:eol-styleを付け忘れた人がいた場合、他の誰かが、そのファイルを異なるOS上で開いた瞬間に気がつくと思う。 一旦気がつけば、直すのは簡単。 ただ、属性を設定して、コミットするだけだ。

注意: 多くのユーザが、ランタイム設定、例えばauto-propsの設定等を、サーバからクライアントへ自動的に「ブロードキャスト」する機能が欲しい、と言ってきている。 これは、機能要求としては既に受け付けられているんだけど(issue 1974)、この機能は開発者の間で現在議論中なので、まだ作業には取りかかっていない。

エディタへのパスにスペースが含まれているんだけど、どうしたら良いでしょうか? また、このエディタへコマンドラインオプションを指定したいのですが、その方法は?

Subversion コマンドラインクライアントは、SVN_EDITOR環境変数で定義されたエディタを起動する。 この環境変数は、ログメッセージの入力や編集に利用される一時ファイル名と共に、直接OSへと引き渡される。

SVN_EDITOR文字列は、そのままシステムのコマンドシェルへ引き渡されることになるため、エディタ名やエディタへのパスにスペースが含まれている場合、クォートで囲む必要があるだろう。

例えば、Windows 上で、エディタにC:\Program Files\Posix Tools\bin\viを利用する場合、この変数を次のように設定することになる。

   set SVN_EDITOR="C:\Program Files\Posix Tools\bin\vi"

Windowsのシェルでは、クォートをエスケープする必要のないことに注意。 クォートはsetコマンドの構文には含まれていないからね。

Unixシステムでは、あなたのシェル特有の変数設定方法に従う必要がある。 例えば、bash では、こんな感じだ。

   SVN_EDITOR='"/usr/local/more editors/bin/xemacs"'
   export SVN_EDITOR

エディタの起動時にコマンドラインオプションが必要な場合、通常のコマンドラインと同様、エディタ名に続けてそのオプションを指定した上で、SVN_EDITOR環境変数へ設定すればよい。 例えば、上記のエディタへ-nx -rオプション指定したい場合、こんな感じになるだろう。

Windowsでは、

   set SVN_EDITOR="C:\Program Files\Posix Tools\bin\vi" -nx -r

UNIX/bashでは、

   SVN_EDITOR='"/usr/local/more editors/bin/xemacs" -nx -r'
   export SVN_EDITOR

SVN_EDITOR は、Subversion 特有の、エディタを指定する為に利用される変数だ。 Subversion では、より汎用的な EDITOR 変数もサポートしているけれど、もし Subversion で特有の挙動が必要ならば、SVN_EDITOR 変数を使うのが最良だよ。

リポジトリが、Berkeley DB のどのバージョンを使っているか知るには?

もし、そのリポジトリが現在稼働中のものならば、簡単な答えは「あなたがインストールしている Berkeley DB のバージョンだよ」となる。 しかし、もしそのリポジトリが、バックアップや不明なソースから作られたもので、どのバージョンの Berkeley DB で作られたのが手がかりがないなら、こんな感じで調べよう。

適当なコマンドを使って、リポジトリ内で最も大きな番号の割り振られた db/log.* ファイルについて、(10進で)12番目と16番目のオフセットから2つの4バイトの整数値を調べよう。 GNU od を使う場合はこんな感じ:「od -j12 -N8 -tx4 log.<number>」。Mac OS X のhexdump を使う場合には、こんな感じ:「hexdump -s12 -n8 -x log.<number>」。 最初の整数は、マジックナンバーである 0x00040988 となっている筈だ。 これは、そのファイルがBerkeley DBのログファイルであることを示している。 2番目の数値が、ログフォーマットのバージョンだ。 下のテーブルで、Berkelet DB のバージョンを確認しよう。

ログフォーマットバージョンBerkeley DBバージョン
5 (0x00000005)4.0
7 (0x00000007)4.1
8 (0x00000008)4.2
10 (0x0000000a)4.3
11 (0x0000000b)4.4
12 (0x0000000c)4.5
13 (0x0000000d)4.6

私はリポジトリを使って Webサイトを管理しています。どうしたら、コミット毎にアップデートが自動的に実行されるライブサイトを作れますか?

あなたのリポジトリへpost-commiフックスクリプトを加えることにより、何時でも簡単にこれを実現することができる。 フックスクリプトについて、Subversion Book の第5章を参照のこと。 基本的なアイディアは、その「ライブサイト」を一般的な作業コピーにした上で、post-commit フックスクリプトにより、作業コピー上で 'svn update' を実行させれば良い。

実際には、幾つか注意すべき点がある。 コミットを司るサーバプログラム(svnserveまたはapache)は、post-commitフックスクリプトを実行することになるプログラムと同一だ。 これは、このプログラムが、作業コピーを更新できる適切なパーミションを有していなければならないことを意味する。 言い換えれば、その作業コピーは、svnserveやapacheを稼動させているのと同一ユーザに所有されていなければならない。 または、少なくとも、その作業コピーは、適切なパーミッションを有している必要がある。

もしそのサーバが、所有権を有していない作業コピー(例えば、ユーザ joe の ~/public_html/ 領域)をアップデートする必要があるなら、更新を司る +s バイナリプログラム(setuidされたプログラムのこと)を作る、という方法がある。 これは、Unix が +s されたスクリプトの実行を許可しないためだ。 次の小さなCプログラムをコンパイルしよう。

#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
  execl("/usr/local/bin/svn", "svn", "update", "/home/joe/public_html/",
        (const char *) NULL);
  return(EXIT_FAILURE);
}

そして、このバイナリをchmod +sし、ユーザ 'joe' に対して所有権を与える。 その後、post-commit フックで、このバイナリを起動する為のようにすればよい。

そのフックの実行が上手く行かない場合には、「どうしてリポジトリのフックが動作しないの?」を参照のこと。

また恐らく、そのライブ作業コピー内にある .svn/ ディレクトリを、apache が公開してしまわないようにしたい、と考えるかもしれない。 次の行をhttpd.confへ追加しよう。

# Subversion 作業コピー管理ディレクトリの表示を不許可にする
<DirectoryMatch "^/.*/\.svn/">
    Order deny,allow
    Deny from all
</DirectoryMatch>

ファイル単体をチェックアウトするには?

Subversion では、ファイル単体のチェックアウトはサポートしていない。 サポートしているのは、ディレクトリ構造でのチェックアウトだけだ。

ただし、'svn export' を使うことでファイルを単体でエクスポートすることは出来る。 これは、そのファイルコンテンツを取得し、バージョン付けされた作業コピーは作成しない。

作業コピー内で、既に実行されてしまった追加や削除、コピー、名前の変更などを検知するにはどうすれば良い?

どうにも出来無い。試行するのも不味い考えだ。

作業コピーの基本デザインには、2つのルールがある。(1)ファイルを編集はあなたの望むのようにどうぞ。 (2)ツリーに対するどんな変更(追加、削除、移動、コピー)も、Subversionクライアントを用いること。もしこの規則に従のであれば、Subversionクライアントは完全に作業コピーを管理できる。 もしも、名前の変更や再配置がSubversion 外で行われた場合、UIは侵害され、作業コピーは破壊されることになるだろう。 クライアントは、何が起ったのか推測することができない。

人々は、時たま、この問題にぶちあたる。 というのも、バージョン管理を「透過」にしたいと考えるからだ。 ユーザには作業コピーを使わせ、その後に、何が行われたのかを推測し、適したクライアントコマンドを実行する為のスクリプトを走らせる。 生憎、このテクニックで走り通せるのは、僅かな距離だけだ。 'svn status' により、消失したファイルやバージョン管理されていないアイテムを知ることができる、スクリプトは自動的に 'svn rm' や 'svn add' を実行できる。 しかし、もし移動やコピーが発生したら、はい、ご愁傷様。 例えそのスクリプトが、これらを発見する素晴らしい方法を実現したとしても、'svn mv'や'svn cp'は、それが起こってしまった後では、実行することができない。

まとめ: 作業コピーは、完全に Subversion の管理下へ置こう。 Subversionは透過となるようにはデザインされていない。 もし、あなたが透過性を求めるならば、apache サーバを立ち上げ、Subversion bookの Appendix C に書かれている「SVNautoversioning」機能を使ってみよう。 これは、ユーザに対して、リポジトリをネットワークディスクのように mount させることを許可するもので、そのボリュームに対して行った如何なる変更も、サーバへ自動的にコミットされるようになる。

Windows 上で、svnserve をサービスとして実行させるには?

1.4.0以降であれば、ここでインストラクションが読めるよ。

1.4.0より前のバージョンの場合、svnserveバイナリそれ自身をWindowsサービスとしてインストールすることはできない。 ただし、幾つか「サービスラッパー」が存在していて、それを使うことで実現可能だ。例をあげよう。

  • SVNServiceは Magnus Norddahl が作ったフリーなツール。
  • SrvAny は Microsoft が作ったもので、無料で利用可能。

svnserve をサービスとして稼動させる方法に関しては、TortiseSVN マニュアルにもう少し記述があるよ。

リポジトリを、BDBからFSFSへ、またはFSFSからBDBへ変換するにはどうしたらよいの?

3つの手順がある。

  1. 古いフォーマットから新しいフォーマットへダンプ/ロードする
  2. フックスクリプトをコピーする
  3. 設定ファイルをコピーする

ここでは、あなたは /svn/myrepos という、BDBをバックエンドに使っているリポジトリを持っていて、FSFSバックエンドを使うように変更したいと思っている、としよう。

  1. この作業中にデータが変更されないよう、サーバを停止させる。
  2. fsfs をバックエンドに指定し、新しいリポジトリを作成(1.2以上であれば、これがデフォルト)。例えばこんな感じ。svnadmin create /svn/myreposfsfs --fs-type fsfs
  3. /svn/myreposのダンプ出力をパイプで繋ぎ、/svn/myreposfsfsへの入力としてロードさせる。こんな感じ。svnadmin dump /svn/myrepos -q | svnadmin load /svn/myreposfsfsWindows ユーザは、ファイルに対してダンプを行い、そのファイルからロードする、という2段階の手順で行おう。
  4. /svn/myrepos/hooks内にある、現在利用中のフックスクリプトを/svn/myreposfsfs/hooksへとコピーする。無闇と、全てをコピーしてしまわないように。Subversion の生成するテンプレートが変更されているかもしれないからね。
  5. svnadmin createコマンドによって /svn/myreposfsfs/hooksへ生成されたテンプレートスクリプトを、/svn/myrepos/hooks内のスクリプトを比較し、気に入った変更点があったら、それをアクティブスクリプトへ組み込もう。
  6. 設定ファイルを /svn/myrepos/conf から/svn/myreposfsfs/conf へコピーする(パスワードファイルを使っているなら、それも忘れずに)。もしくは、あなたが設定ファイルへ行った変更点を、新しいデフォルトの設定ファイルへ反映させてもよいかもね。
  7. /svn/myrepos/svn/myreposbdb へリネームして、その後/svn/myreposfsfs/svn/myrepos へとリネームする。ファイルのパーミションが、BDB版の時と同じになっていることを確認すること。
  8. サーバを再起動する。

無事、新しいリポジトリが全て正常に動作しているのを確認してから古いリポジトリを削除しよう。

反対に FSFS から BDB へと移行させる場合には、svnadmin createコマンドで BDB を指定しよう。

Subversion は、どうやってバイナリファイルを取り扱うの?

初めてファイルがSubversionへ追加、もしくはインポートされるとき、ファイルがバイナリファイルかどうかが判定される。 現時点では、Subversionはファイルの先頭の1024バイトを見るだけだ。 もし、何れかのバイトが0である場合、または、15%以上が非アスキー表示可能文字であった場合、そのファイルはバイナリと判断される。 とはいえ、このヒューリスティックな手法は、将来、改良されるかも。

ファイルがバイナリだと判断された場合、そのファイルは svn:mime-type 属性へ「application/octet-strem」が設定される(この挙動は、auto-props機能を用いることで、または、手動でsvn propsetを実行して属性を設定することで、何時でも上書きが可能だ)。

Subversionは以下のファイルをテキストとして扱う。

  • svn:mime-type が無いファイル
  • svn:mime-type が "text/" で始まっているファイル
  • svn:mime-type が "image/x-xbitmap" と一致するファイル
  • svn:mime-type が "image/x-xpixmap" と一致するファイル

これ以外のファイルは全てバイナリとして扱われる。つまり、Subversion は、以下の通りに動作する。

  • svn updatesvn merge 時に、受け取った変更と、ローカルな変更とを自動的にはマージしない。
  • svn diff で差分を表示しない。
  • svn blame で 行単位表示を行わない。

これ以外の点に関しては、Subversion はバイナリファイルをテキストファイルと同様に扱う。例えば、svn:keywords やsvn:eol-style 属性をセットした場合、Subversion はキーワード置換や、改行コード変換を、バイナリファイルに対しても実行するだろう。

ファイルがバイナリか否か、変更点を格納する為に利用されるリポジトリ容量へは影響を及ぼさないし、クライアントサーバ間でやり取りされるトラフィックの量にも影響しないことに注意して欲しい。 蓄積や転送に於いては、Subversionは、バイナリとテキストファイルの両者に対して同様に上手く機能する差分化手法を用いる。 これは、'svn diff'コマンドで使われる差分化手法とは、全く関係がない。

svn diff で、変更のあったファイル名だけ表示する方法は? 差分内容は必要ないんだけど。

svn diffには、それを実現するオプションはないけど、

  • もし、差分の興味の対象が、例えばリビジョン10と、その直前のリビジョンとの差ならば、
    svn log -vq -r10
    で希望の結果が入手できるよ。
  • 別の方法として、もし Unix を使っているならば、次の方法は、リビジョンの範囲に関わらず使うことが出来る。
        svn log -vq -r123:456 | egrep '^ {3}[ADMR] ' | cut -c6- | sort | uniq 
Version 1.4 のsvn diffコマンドには「--summarize」オプションが付く予定だ。

一度に複数のファイルを move したいんだけど、ワイルドカードや glob を使うにはどうすればよいの?

あなたは、

svn mv svn://server/trunk/stuff/* svn://server/trunk/some-other-dir

というような感じでやりたいんだろうけど、でもこれは、

svn: Path 'svn://server/trunk/stuff/*' does not exist in revision 123

といったような、訳の分からないエラーメッセージが表示されて、失敗になってしまう。

短くて、悲しい回答だけど、これを行うビルトインの方法はないんだ。 多くのコマンドは、mvで見たように、任意個の引数を扱うことができない。 また、何れにしても、Subversionは "*" のようなワイルドカードを、shell がやっているようには、展開しない。

もしも、全てのソースファイルと移動先のディレクトリとを含んだ作業コピーを持っているのであれば、シェルのワイルドカード機能を移動処理に利用する事ができる。 例えば、こんな感じだ(Bash用)。

  for i in stuff/*; do svn mv $i some-other-dir; done
  svn ci -m "moved all the stuff into some other dir"

また、移動元のファイル名のリストを準備した上で、そのリストの各要素に対して "svn mv" を行うことも出来る。 こんな感じになるだろう。

        s=svn://server/trunk/stuff/
        svn ls "$s"  | \
        while read f
           do svn mv "$s/$f" svn://server/trunk/some-other-dir -m "Moved just one file"
        done

但し、この方法は、ソースファイル毎に commit が発生することには注意して欲しい。 先の方法(作業コピーを使う方法)が全体で一度しか commit しないのとは、対照的だ。

「svnmucc」または「mucc」と呼ばれるプログラムがあり(名前は、Subversion のバージョンに依存する)、ソースコードが Subverision と共に配布されているのだけど(Subversion 1.4 以前では .../contrib/client-side/mucc/mucc.c に、Subversion 1.5以降では、.../contrib/client-side/svnmucc/svnmucc.cにある)、このプログラムは、今回の問題を解決するのに使えると思う。

注意: release 1.5 で、Subversion は「cp」と「mv」で複数のファイルを同時に指定することが可能になった。

Subversion を使って、サードパーティのソフトウェアの変更版(ベンダーブランチ)をメンテするには?

サードパーティのコードに対するローカルな変更管理に対し、サードパーティからのアップグレードも含め、Subversion を使いたいという要求を、しばしば耳にする。 即ち、分岐した自身のブランチを維持しつつ、上層の提供元から公開される新しいリリースも組み入れたいわけだ。 これは、一般的にベンダーブランチと呼ばれていて(この名称は Subversion 以前から使われている)、Subversion を使ってこれを管理するテクニックは、ここで説明されている

もし、ベンダーコードがリモートの Subversion リポジトリで管理されているならば、ベンダーコードのコピーを管理に、Pistonが利用できる。

次善の策ではあるけれど、もしsvn_load_dirs.plを使うのに多くの時間を費やしていたり、よりラクな方法を探しているならば、Jon Steven によって書かれた Subversion Vendor Branches Howtoのステップ・バイ・ステップ解説を参照してみよう。 この方法では、古いコードを新しいコードへ上書きする際、Subversion のバックエンドが提供している容量の増加を抑制する為の手法は用いない。 ベンダーコードのインポート毎に、完全に新しいコピーが作成され、同一ファイルに対しても容量削減は行わない。

Troubleshooting:

僕のリポジトリは、いつでも、リカバリが必要(DB_RUNRECOVERY)というエラーメッセージを出して、刺さっているみたい。これ、何が原因?

あなたのリポジトリで利用されている Berkeley DB データベースは、中断に対して弱い。データベースにアクセスしているプロセスが、環境を「綺麗に」閉じずに消えてしまった場合、データベースは、首尾一貫性が失われた状態になってしまう。 これが生じる原因は、一般的に次のようなものだ。

  • プロセスが、パーミッション問題により終了した
  • プロセスが、クラッシュ/セグメンテーションフォルトした
  • プロセスが、強制的に kill された
  • ディスク容量がなくなった

ほとんどの場合、こうした現象に対しては、「svnadmin revover」を実行すべきだ。 これは、リポジトリを正しい状態へと引き戻す。 詳細に関してはこちらの質問を参照。 ディスク容量不足が、度重なるチェックアウトや更新によって引き起こされている場合、リポジトリのクラッシュを引き起こす可能性がある。 この場合にはリカバリは不可能だ(というわけで、バックアップを取ろう)。

セグメンテーションフォルトや、強制的な kill、またディスク不足はかなり稀だ。パーミッション問題は非常に一般的である。 一つのプロセスがリポジトリへアクセスし、誤って所有権やパーミションを変更してしまう。 その後、他のプロセスがアクセスを試み、そのパーミッションによってお陀仏、というわけだ。

これを防ぐ最良の方法は、リポジトリのパーミッションと所有権を正しく設定すること。 我々の推奨に関してはこちらを参照の事。

毎回リポジトリへアクセスする度に、プロセスがハングアップするんだけど、僕のリポジトリが壊れているの?

あなたのリポジトリは壊れていないし、データも失われていない。 あなたのプロセスが、リポジトリへ直接アクセスしている(mod_dav_svn、svnlook、svnadmin または、file:// URL を使っている)ならば、データへアクセスするために、Berkeley DB を利用している。 Berkeley DB は、ジャーナリングシステムで、つまり、これから行おうとしている操作を、実際に行なう前に、全て記録する。 もし、あなたのプロセスが(Control-Cやセグメンテーションフォルトによって)終了した場合、未終了の作業内容が書かれたログファイルと共に、ロックファイルが残されたままとなる。 そのデータベースへアクセスを試みる他のプロセスは、そのロックファイルが消え去るまで、ただハングアップし続けることになる。 リポジトリを目覚めさせる為には、Berkeley DB に対し、作業を終了するか、データベースを首尾一貫している以前の状態へと巻き戻すかを指示する必要がある。

WARNING:もし、リカバリ実行中に他のプロセスがリポジトリへアクセスしたら、そのリポジトリは深刻なダメージを受ける可能性があるよ!

絶対的に確認しなければならないことは、この作業実行前に、リポジトリに対するアクセスを禁止すること(Apache をシャットダウンするとか、'svn' の実行属性を落としちゃうとか)。 このコマンドは、データベースを所有し、管理しているユーザ権限で実行しなければならず、root として実行してはならない。rootで実行した場合、データベースを管理している非rootユーザ(多くの場合、これは、あなただったり、Apacheプロセスだったりするんだけど)ではオープンすることのできないroot所有のファイルが、dbディレクトリへ残されてしまう。 また、recover を実行する場合には、正しい umask が設定されていることも確認すること。これを忘れると、リポジトリへのアクセスを許可されているグループに属しているユーザが、締め出されてしまうことになるだろう。

まず次のコマンドを実行しよう。

   svnadmin recover /path/to/repos

コマンドが終了したら、リポジトリ内のdbディレクトリ内にあるパーミションを確認しよう。

時には、"svnadmin recover"が上手く動作しない場合がある。この場合、こんな感じのエラーメッセージが表示されるかもしれない。

  Repository lock acquired.
  Please wait; recovering the repository may take some time...
  svnadmin: DB_RUNRECOVERY: Fatal error, run database recovery
  svnadmin: bdb: Recovery function for LSN 175 7066018 failed on backward pass
  svnadmin: bdb: PANIC: No such file or directory
  svnadmin: bdb: PANIC: fatal region error detected; run recovery

または、こんな感じだ。

  Repository lock acquired.
  Please wait; recovering the repository may take some time...
  svn: DB_RUNRECOVERY: Fatal error, run database recovery
  svn: bdb: DB_ENV->log_flush: LSN of 115/802071 past current end-of-log
  of 115/731460
  svn: bdb: Database environment corrupt; the wrong log files may have
  been removed or incompatible database files imported from another
  environment
  [...]
  svn: bdb: changes: unable to flush page: 0
  svn: bdb: txn_checkpoint: failed to flush the buffer cache Invalid argument
  svn: bdb: PANIC: Invalid argument
  svn: bdb: PANIC: fatal region error detected; run recovery
  svn: bdb: PANIC: fatal region error detected; run recovery
  [...]

このような場合には、Berkeley DB 自体のdb_recoverユーティリティを試してみよう(db_recover ドキュメントを参照のこと)。 このコマンドは、大抵、Berkeley DB がインストールされた 「bin/」サブディレクトリの中にある。例えば、Berkeley DB をソースからインストールしたのならば、/usr/local/BerkeleyDB.4.2/bin/db_recoverかもしれない。 Berkeley DB が予めインストールされたシステムでは、単純に /usr/bin/db_recoverかもしれない。 もし、複数のBerkeley DB がインストールされているならば、試そうとしているdb_recover のバージョンが、リポジトリの使っている Berkeley DB のバージョンと一致していることを確認しよう。

db_recover を 「-c」 フラグ(「catastrophic recovery: 悲劇からの復活」)付きで実行する。 冗長性の為に 「-v」 を付けても良いし、「-h」へ引数を渡して、どの db 環境をリカバリーするのかしても良い(これで、該当ディレクトリへ cd する必要がなくなる)。 つまりこんな感じだ。

   db_recover -c -v -h /path/to/repos/db

このコマンドを、リポジ