Subversion FAQ

(English)

Based on r872564 (partially updated about cvs2svn)

Table of Contents

General questions:

How-to:

Troubleshooting:

Developer questions:

References:


General questions:

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

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

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

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

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

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

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

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

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

クライアントとサーバの相互接続性ポリシーに関しては、Subversion Community Guideの「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よりは凄く便利だよね。

次のリリースは何時?

次のステータスページを参照

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

もし、この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 という変換ツールを利用しているようだ。 cvs2svn のソースコードは https://github.com/mhagger/cvs2svn に置かれている。 もしあなたが Linux あるいは BSD 由来のシステムを利用しているならば、 ディストリビューションはまだそのパッケージを供給しているかもしれない。

cvs2svn があなたの用途に合わなければ Lev Serebryakov が書いた refinecvs を http://lev.serebryakov.spb.ru/refinecvs/ から入手して試みることはできるかもしれない。

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マニュアルに書かれた (dead link: http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/env_set_flags.html#DB_LOG_AUTOREMOVE) 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 のパッチ、どうやって送ればよいかな?

まず最初に、Subversion Community Guideを読むこと。

熟読したら、[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

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

その場 '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 サーバを設定する為の、素晴らしいドキュメントが同梱されている。 https://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

僕の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以降であれば、ここでインストラクションが読めるよ。

リポジトリを、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以降では、.../tools/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ユーティリティを試してみよう(dead link: http://www.oracle.com/technology/documentation/berkeley-db/db/utility/db_recover.html) 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

このコマンドを、リポジトリを所有しているユーザとして実行しよう。 ただし、今一度、これを実行している間は、(svnserver や Apache をシャットダウンするなどして)他のプロセスがリポジトリへアクセスしないことを確認すること。

僕のリポジトリが「Cannot allocate memory(メモリが確保できない)」というエラーメッセージを吐き続けています。 どうしたらよいのでしょう?

http:// アクセスを使っている場合、「Cannot allocate memory」エラーは、httpd エラーログの中に、こんな感じで書かれている。

[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] (20014)
Error string not specified yet: Berkeley DB error while opening 
'strings' table for filesystem /usr/local/svn/repositories/svn/db: 
Cannot allocate memory
[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] 
Could not fetch resource information.  [500, #0]
[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] 
Could not open the requested SVN filesystem  [500, #160029]     
[Wed Apr 07 04:26:10 2004] [error] [client 212.151.130.227] (17) 
File exists: Could not open the requested SVN filesystem  [500, #160029]

これは、通常のオペレーションでは発生しない筈だが、発生した場合の解決策は、ここで述べたように、データベースリカバリを実行することだ。 もし、これが何度も起こるようならば、多分、db/DB_CONFIG ファイルの中のデフォルトロックパラメタ(set_lk_max_locksset_lk_max_lockers、並びにset_lk_max_objects)値を引き上げる必要があるだろう。 既存リポジトリの DB_CONFIG を変更した場合には、その後にリカバリを実行することを忘れないこと。

毎回 svn コマンドを実行する度に、作業コピーがロックされているよ、って言われるんだけど、僕のリポジトリが壊れているの?

あなたの作業コピーは壊れていないし、データも失われていない。 Subversionの作業コピーはジャーナリングシステムで、つまり、これから行おうとしている作業を、実際に実行する前に、全て記録する。 もし svn クライアントプログラムが(セグメンテーションフォルトや kill によって。Control-Cは含まない)手荒に終了された場合、1つ以上のロックファイルが、未終了の作業に関するログファイルと共に、残されたままになっている('svn status' コマンドを実行すると、ロックされたディレクトリの隣に'L'が表示されるだろう)。 作業コピーへとアクセスする他の全てのプロセスは、このロックを見つけると、失敗となる。作業コピーを目覚めさせる為には、svn client に対し、作業を終了させる旨、指示する必要がある。単純に次のコマンドを実行しよう。

svn cleanup working-copy

commit しようとしているんですが、Subversion が、僕の作業コピーは古い、って言ってくるんだけど?

この現象を引き起こす3つの可能性がある。

  1. 失敗したコミットの残骸が、作業コピーに残っている。

    新しいリビジョンがサーバへと追加され、クライアントがpost-commit 管理タスク(ローカルなテキストベースコピーの更新中を含む)を実行している間に、あなたのコミットが、まずい状況になったのかもしれない。 これは様々な理由で起こる可能性があり、(稀には)データベースのバックエンドの問題によって、または、(より一般的には)まさにマズいタイミングでネットワークが切断した等が考えられる。

    この現象が発生した場合、あなたが今コミットしようとしているその変更は、既にコミットされている可能性がある。 'svn log -rHEAD' を使って、「失敗したと考えられている」あなたのコミットが、実際には成功しているかどうかを確認してみよう。 もしコミットが成功していたならば、'svn revert' を使ってローカルな変更を元に戻し、その後'svn update'を行って、サーバから変更を取得しよう('svn update'だけが、ローカルコピーを最新にする、という事に注意。revert はそれを行わないよ)。

  2. 混在リビジョン

    Subversion でコミットを行うと、クライアントは、そのコミットが関与したノードのリビジョン番号だけを変化させる。 作業コピーの中にある全てのノードを変化させるわけではない。 これは、最後にコミットした時期に応じて、単一の作業コピー内に於いても、ファイルやサブディレクトリが異なるリビジョンになるかもしれない、ということだ。ある種の操作(例えばディレクトリの属性変更)では、もしリポジトリ内に、より新しいバージョンのノードが存在する場合には、データの喪失を防ぐため、コミットが拒否される。 詳細は、Version Control with SubversionMixed revisions have limitationsを参照の事。

    この問題は、作業コピー内で 'svn update' を実行することにより解消することが出来る。

  3. 実際に古いのでは? つまり、あなたがファイルのコピーを最後に更新してから、既に誰かがそのファイルを変更していて、そのファイルに対して変更をコミットしようとしているのではないだろうか? これも 'svn update' で解決できるよ。

あるプロジェクトへパッチを寄贈しました。そのパッチは新規ファイルを含んでいます。で、今、svn updateが動作しないのですが...。

新しいファイルをパッチへ含める為に、svn diffコマンドで生成されるパッチに、その新規ファイルが含まれるように、恐らくあなたは、svn addコマンドを実行したのだと思う。 もしそのパッチがコードベースへとコミットされ、その後svn updateを実行すると、あなたは、次のようなエラーメッセージを目にするはずだ。"svn: Failed to add file 'my.new.file': object of the same name already exists".

このエラーメッセージが表示される理由は、未だ自身の作業コピー内に、ファイルのローカルコピーが残されているためだ。 この問題を解決する手順は次の通り。

  1. svn revertコマンドを実行して、Subversion 内での追加準備状態を解除する。
  2. 該当ファイルを削除するか、または、作業コピー外へと移動させる。
  3. これで svn update コマンドを実行できるようになったはずだ。

リポジトリから取得した新しいファイルと、あなたのオリジナルのファイルと比較してみるのも良いだろう。

ディストリビューションバイナリをビルドして、Subversion をチェックアウトしようとしたら、「Unrecognized URL scheme」って、エラーが表示されたんだけど、これって、どうなったの?

Subversion はリポジトリへのアクセスにプラグインシステムを採用していて、現在、次の3つのプラグインがある。 ra_local は、リーカルリポジトリへのアクセスするためのもの、ra_davはWebDAV 経由でリポジトリへアクセスするためのもの、そして、ra_svn は svnserve サーバ経由で、ローカルまたはリモートのリポジトリへアクセスするためのものだ。 Subversion を使って何らかの操作を行おうとすると、プログラムはそのURLスキームに応じて、プラグインを動的にロードしようとする。 'file://'URLでは ra_localをロードしようとするし、'http://' URLでは ra_dav をロードしようとする、といった具合だ。

あなたが目にしたエラーは、動的リンカ/ローダがロードするプラグインを見つけられなかった、ということ。 これは通常、Subversion を共有ライブラリと共にビルドした上で、'make install' を事前に実行せずに、実行させようとした時に発生する。別の可能性としては、make install は実行したんだけど、動的リンカ/ローダが認識できない場所に、ライブラリがインストールされた、というもの。 Linuxでは、リンカ/ローダにライブラリを見つけさせるためには、そのライブラリディレクトリを/etc/ld.so.sonf へ追加し、ldconfig を実行しなければならない。もし、こうしたくない、または root 権限をもっていない場合には、LD_LIBRARY_PATH環境変数へそのライブラリディレクトリを指定することでも可能だ。

リポジトリを見つけるとき、または開こうとするときにエラーが出るんだけど、リポジトリのURLが正しいことは分かってる。何が悪いの?

こちらのfaqを参照。

`configure' を実行したら、subs-1.sed line 38: Unterminated `s' commandというエラーが出ました。何が問題?

多分、あなたのシステムには古い /usr/local/bin/apr-config/usr/local/bin/apu-configが残っている。 これらを取り除き、一緒にビルドしようとしている apr/apr-util/ が完全に最新のものであることを確認した上で、もう一度試してみよう。

Windows の上で、MSVC++ 6.0 を使って Subversion を buildしているんだけど、上手く行かない。どうしたらよい?

恐らく、最新のプラットフォームSDKを入手する必要がある。 VC++6.0に同梱されている版は、最近の使用には適していない。

Windowsのドライブレターを file:URLで使える?

こんな感じ。

svn import file:///d:/some/path/to/repos/on/d/drive

詳細は Subversion Book のRepository URLsをどうぞ。

VS.NET/ASP.NET では .svn というディレクトリ名では問題があるように思えます。どうしたら良いでしょう?

VS.Net は ASP.Net と呼ばれるサブシステムをもっていて、これは、IISを通じたリモート公開を行うためにWebDAVを利用する。 このサブシステムは、「.」で始まるどのようなパス名も受け付けない。 これはリモートに Subversion の作業コピーをリモート公開しようとするときに問題となる。 なぜならば、「.svn」サブディレクトリが存在するからだ。エラーメッセージとしては、「unable to read project information」といったものが、表示される。

これを迂回するには、SVN_ASP_DONT_NET_HACK環境変数へ適当な値を設定しよう。 これは Windows クライアントに対し、作業コピー内では、ディレクトリの名前として「_svn」を使うように指示するためのものだ。 詳細は、Subversion 1.3 のリリースノートに書かれた関連セクションを参照のこと。 また、この質問では、管理ディレクトリ名をカスタマイズする他の方法に関して説明している。

ネットワーク越しに Subversion リポジトリへ書き込み操作を行うと問題が生じます。

例えば、あるユーザがレポートしてくれたんだけど、ローカルアクセスでは問題なく動作する import が、

  $ mkdir test
  $ touch test/testfile
  $ svn import test file:///var/svn/test -m "Initial import"
  Adding         test/testfile
  Transmitting file data .
  Committed revision 1.
リモートホストからでは動作しない。
  $ svn import http://svn.sabi.net/test testfile -m "import"
  nicholas's password: xxxxxxx

  svn_error: #21110 : <Activity not found>

  The specified activity does not exist.

我々は、httpd プロセスが REPOS/dev ディレクトリへ書き込みできないときにこの現象が生じることを確認している。 パーミションを確認し、Apacheがdav/ ディレクトリ(や、勿論 db/ へ)書き込み出来ることを確認して欲しい。

WindowsXP上で使っているんだけど、Subversion サーバが、たまに、壊れたデータを送出しているみたい。こんなことって、本当にあるの?

Window XP Service Pack 1 をインストールする必要があるね。

Subversion のクライアントとサーバの間を流れるネットワーク上のやり取りをトレースしたいのですが、どんな方法が最良でしょうか?

hacking.html#net-traceを参照のこと。

どうして svn revert では、明示的にターゲットを指定しなければならないの? どうして、再帰処理がデフォルトじゃないの? こういった挙動は、他のほとんどのサブコマンドと異なっているよね。

簡単に言えば「それがあなたの為だから」。

Subversion はあなたのデータを守ることに対して大変に高い優先度を設定している。 これは、単にバージョン管理されたデータに対してだけではない。 既にバージョン管理されているデータに対する改変や、バージョンコントロールシステムへ追加されることが指示されているファイルに対しても、慎重に取り扱われる。

svn revertコマンドに対し、たとえターゲットが '.' だけだったとしても、明示的なターゲット指定を必要としたのは、これを達成するための一つの手段だ。 この要求は(再帰処理を行いたい場合には、--recursive(-R)フラグを指定する必要がある、という要求も含めて)、あなたが実行しようしている内容を、しっかりと認識して欲しいからだ。 ひとたびファイルが元に戻されてしまえば、ローカルで行なわれた変更は永遠に失われてしまうことになるのだから。

Apache を起動したら、mod_dav_svn に「bad database version」と文句を言われた。 どうも db-4.X ではなく、db-3.X を見つけたらしい。

あなたの apr-util は DB-3 とリンクされていて、svn は DB-4とリンクされている。 残念ながら、これらのDBシンボルは違わないんだ。 mod_dav_svn が Apache のプロセス空間へロードされると、結局 apr-util の DB-3 に対してシンボル名を解決することになる。

確実な解決方法は、apr-util を DB-4 に対してコンパイルすること。 次の適切なスイッチを apr-util か apache の configure 実行時に引き渡せばよい。 「--with-dbm=db4 --with-berkeley-db=/the/db/prefix」

Red Hat 9 上では、「Function not implemented」というエラーが出て、なにも動かない。どうすれば直ります?

これは、Sunversion 自体の問題ではないんだけど、Subversion ユーザが出くわす問題だ。

Red Hat9 と Fedora は、NPTL(the Native Posix Threads Library)をサポートしたカーネルを前提としている Berkeley DB と共に配布されている。

RedHat が提供しているカーネルにはこのサポートが組み込まれているけれど、もしあなたが自分でカーネルをコンパイルする場合には、NPTLサポートを組み込まないかもしれない。 この場合、こんな感じのエラーが表示されることになるだろう。

svn: Berkeley DB error
svn: Berkeley DB error while creating environment for filesystem tester/db:
Function not implemented

この問題は、次にあげる何れかの解決方法で修正可能だ。

  • Berkeley DB を、あなたのカーネル用に再ビルドする。
  • Red Hat 9 カーネルを使う。
  • あなたが使っているカーネルへ、NPTL パッチを適用する。
  • NPTLサポートが組み込まれた最近(2.5.x)のカーネルを使う。
  • LD_ASSUME_KERNEL環境変数が2.2.5にセットされているかを確認し、もし設定されている場合には、Subversion(Apache)を起動する前にその設定を解除する(多分、この変数は Red Hat 9 上で Wine または Winex を実行するために設定したのだろう)。

Berkeley DBのNPTLバージョンを使う為には、NPTLをサポートした glibc ライブラリも一緒に使う必要がある。これは大抵 i686 版を意味するだろう。 詳細は、https://svn.haxx.se/users/archive-2004-03/0488.shtmlを参照のこと。

Apache(ra_dav)経由で、ファイルをコミット、またはインポートすると、SVN log で "(no author)"って表示されるのは、どうして?

リポジトリに対して、Apache 経由での匿名書き込みを許可している場合、Apache サーバは決して SVN クライアントにユーザ名を求めないし、認証無しでの書き込み処理を許可する。 その為、Subversionは誰か操作を行っているのか分からず、ログはこんな感じになる。

$ svn log
------------------------------------------------------------------------
rev 24:  (no author) | 2003-07-29 19:28:35 +0200 (Tue, 29 Jul 2003)

Apacheに対してアクセス制限を行う為の設定方法は、Subversion bookを参照のこと。

Windows上で、時々「Access Denied」エラーに遭遇します。ランダムで表示されるように見えるんだけど、なぜ?

これは、ファイルシステムの変更を監視している、様々な Windowsのサービス(アンチウイルスソフトウェアやインデキシングサービス、COM+イベント通知サービス)によって引き起こされる。 これは、実際には Subversion のバグではない為、修正するのが困難だ。 現状の調査結果のまとめがここにある。 多くの人々にとって、この問題の発生頻度を削減するための回避策が、revision 7598で実装された。 もし、これよりも以前の版を使っているならば、最新の版へアップデートしてみて欲しい。

FreeBSD上で、ある種の操作(特に svnadmin create)が時々ハングアップするのは、なぜ?

これは、通常、システムにエントロピーが不足している為に生じる。 多分、ハードディスクやネットワーク割り込みといったソースからエントロピーを集めるよう、システムを設定する必要がある。 この変更を行う方法は、システムのマニュアルページ、特に random(4)と rndcontrol(8) を参考にしてほしい。

Webブラウザからリポジトリを見られるようにしているんだけど、'svn checkout' が、「301 Moved Permanently」というエラーになる。何が悪いの?

httpd.conf の設定ミスが原因。大抵、このエラーは、Subversionの仮想「location」を、2つの異なるスコープ内で同時に存在するよう、定義してしまっている場合に発生する。

例えば、リポジトリを<Location /www/foo>として公開していて、一方 DocumentRoot/wwwとして設定している場合、問題が生じる。 /www/foo/barへのリクエストが発生した場合、Apache は/foo/barという名前を持つ実際のファイルをDocumentRootの中から探せばいいのか、mod_dav_svn に対して/www/fooリポジトリの中から/barというファイルを取得してくるように指示すればいいのか分からない。 通常、前者が勝つことになり、結果、「Moved Permanently」 エラーとなる。

解決策としては、リポジトリの<Location>を、通常の Web 共有として既に公開されている領域とオーバーラップしないようにするか、もしくはその中へ収めるべきだ。

または、リポジトリ URL と同名のオブジェクトを、Web ルートへ置くことでも構わない。 例えば、あなたの Web サーバのドキュメントルートが /var/www にあり、Subversion のリポジトリが/home/svn/repoに位置していると想定しよう。 従って、リポジトリをhttp://localhost/myrepoで提供するように Apache を設定すればよい。 もし、その後に/var/www/myrepoディレクトリを作った場合には、301 エラーを引き起こすことになるだろう。

HTTPダイジェスト認証が動作しないのはなぜ?

これは、恐らく、Apache HTTPサーバ(バージョン2.0.48以前)の既知のバグだ。 パッチをhttps://bz.apache.org/bugzilla/show_bug.cgi?id=25040から取得することができる。 併せて、あなたの状況が、https://issues.apache.org/jira/browse/SVN-1608に書かれている内容と一致するかどうかを調べて見た方が良いだろう。

AIX 上で xlc を使ってコンパイルしてるんですが、コンパイルエラーになります。何が問題でしょうか?

コンフィギュレーション時とビルド時に、CFLAGS 環境変数へ-qlanglvl=extended を設定して、xlc を少し融通の利くようにしてあげよう。 これで、エラー無しにコンパイルできるようになる筈だ。 詳細は、https://svn.haxx.se/dev/archive-2004-01/0922.shtmlならびに、関連スレッドを参照のこと。

あるディレクトリを(-N オプションをつけて)非再帰的にチェックアウトしましたが、今は、サブディレクトリにも「登場」して欲しいと思っています。 しかし、svn up subdirが動作しないのです。

issue 695を参照の事。 svn checkout -Nの現在の実装は、少し壊れている。 このコマンドの実行結果は、不足エントリのある作業コピー、ということになるんだけど、その「不完全性」には気づかない。 どうやら、CVSユーザのある種の人々は、このパラダイムへ幾分依存しているようなんだけど、Subversion の開発者は、そうではない。 現状では、あなたの手続きを変更する以外、回避策は存在しない。 リポジトリの個別のサブディレクトリ群をチェックアウトし、手動で作業コピーへ重ねてあげよう。

Win32 の上で、Apache と一緒に mod_dav_svn を使おうとしているのですが、そんなモジュールは見つからない、というエラーになります。 mod_dav_svn.so ファイルは、\Apache\modules内に、正しく存在しているのですが...。

この件に関するエラーメッセージは、少し誤解を招いている。恐らく Apache は、mod_dav_svn.soが依存しているDLLを読み込むことが出来ないのだろう。 Apache をサービスとして実行している場合には、通常のユーザと同じPATHを有していないのかもしれない。 libdb4*.dllintl3_svn.dlllibeay32.dllそしてssleay32.dllApache\binApache\modulesの中に存在することを確認し、存在しない場合には Subversion のインストールされたディレクトリからコピーしよう。

もし、それでもまだ問題が解決しない場合には、mod_dav_svn.soに対してDependency Walkerのようなツールを使用し、未解決な依存性が他に存在しないか確認して調べてみよう。

どうしてリポジトリのフックが動作しないの?

フックは、外部プログラムを呼び出すことを期待されているんだけど、その呼び出しが、全然生じていないよう感じだ。

Subversion はフックスクリプトを起動する前に、全ての環境変数を取り除く。その中には、Unixでは $PATHが、Windows では %PATH% が含まれる。結果、スクリプトでは、絶対パス名の記述された他のプログラムだけを実行可能だ。

Debugging tips:

もしあなたが Linux や Unixを使っているならば、以下の手順に従って、そのスクリプトを「手動で」実行してみよう。

  1. 「su」 や 「sudo」、または、似たようなコマンドを使って、通常そのスクリプトを実行するであろうユーザへとなろう。 例えば、Apache を使っている場合には、httpdwwww-dataかもしれない。 または、svnserve を使っていて、また、特別なSubversion用のユーザが用意されている場合には、svnのようなユーザなのかもしれない。 これによって、スクリプトに潜むパーミション問題を切り分けられるだろう。
  2. そのスクリプトを、「env」 プログラムを使い、空の環境で起動動してみよう。 以下は、post-commit フックを実行する例だ。
                      $ env - ./post-commit /var/lib/svn-repos 1234
    
    「env」に対する最初の引数は、ダッシュであることに注意。これは、確実に環境を空にするためのものだ。
  3. コンソールに出たエラーを確認しよう。

どうして、僕の --diff-cmd は '-u' に関して文句を言うのでしょう? --extensions を使って上書きしているんですが、それが機能しません。

外部(external)の diff コマンドを使うとき、Subversion は、やや複雑なコマンドラインを組み立てる。 最初は --diff-cmd で指定された値。次に来るのは、--extensions で指定された値(もし --extensions が空ならば、無視される)、または、--extensions が指定されていない場合(または''が指定された場合)には '-u'。 3番目と4番目には、Subversion は -L と最初のファイルラベル(例えば、"project_issues.html (revision 11209)")を引き渡す。 5番目と6番目には、別の '-L' と2番目のラベル。 7番目と8番目には、1番目と2番目のファイル名(例えば、「.svn/text-base/project_issues.html.svn-base」と「.svn/tmp/project_issues.html.tmp」)。

もし、あなたの愛用している diff コマンドが、これらの引数をサポートしていない場合、引数群を無視し、最後のファイル名だけを取り扱う、小さなラッパースクリプトを作る必要があるかもしれない。

警告: Subversion は、外部の diff プログラムを、受信したファイルを変更する為には期待していないことに注意して欲しい。 そうした場合、作業コピーをごちゃ混ぜにしてしまうだろう。

詳細は、issue#2044を参照のこと。

うぎゃー! 僕の Subversion クライアントが、パスワードを平文でディスク上にキャッシュしているのを見つけちゃった! うわぁ!

はい、落ち着いて。まずは、深呼吸を1回。

Windows 2000以降の場合、svn 1.2 以上の版は、data の暗号化にWindowsの標準的なAPI を使っている。 この為、該当ユーザだけが、キャッシュされたパスワードを解くことができる。

Mac OS Xの場合、svn 1.4 以上の版では、あなたの svn パスワードを暗号化し、保存する為に、システムの Keychain 機能を使っている。

Subversion 1.6 では、UNIX/Linuxに於いてこの件へ取り組むつもりだ。 GNOME KeyringとKWallteのサポートが実装されつつあり、共に、パスワードを暗号化した上でディスクへ格納する手助けとなる。 これらのプログラムは、コンパイル時ならびに、実行時に必要だ。 もし存在しない場合には、クライアントは、平文でパスワードを保存しようと、フォールバックするけれど、でも、決して最初に許可を得ることなく、パスワードを平文でキャッシュしないように変更されている。

Subversion1.5以前の場合、UNIX/Linuxでは、パスワードは、~/.subversion/auth/ へ平文で格納されることになる。 しかし、注意してもらいたいのは、そのキャッシュされたパスワードが格納されているディレクトリ(大抵 ~/.subversion/auth)のパーミションは、700に設定されていて、即ち、あなただけが読みだし可能となっている。

とはいえ、もしあなたが本当に気に病んでいるならば、パスワードのキャッシュ機構を、完全に off にすることができる。svn 1.0 クライアントの場合、ランタイム設定ファイルへ 'store-auth-creds = no' と書くだけだ。svn 1.1 以上のクライアントの場合、より狭い範囲にのみ適用される 'store-passwords = no' を使うことができる(つまり、サーバ証明は、まだキャッシュされる)。 パスワードキャッシングに関するより詳細な説明は、Nightly Build 版Subversion bookの第6章、「Client Credentials Caching」を参照のこと。

最後に、CVS は長期に渡り、パスワードを .cvspass ファイルへ保存している、ということを指摘しておこう。 .cvspass に書かれたパスワードは、暗号化されているように見えるけど、実際には、ただ非常に簡単な、本質的には rot13 同等のアルゴリズムでスクランブルされているだけだ。 これは簡単にクラックされ得る。 スクランブルの有益性は、ただ、ユーザ(例えば root)が、予期せずパスワードを目にしてしまうのを防ぐために過ぎない。 Subversion に於いては、この点に対して深く気にしている人は存在しない。 もし、あなたが興味を持っているならば、dev@リストへパッチを送って欲しい。

「svn: bdb: call implies an access method which is inconsistent with previous calls」ってエラーメッセージが表示されました。どうやったら直せる?

Berkeley DB 4.1 は、やや不安定な点のあることが分かっている。 4.0や4.2の方がベターだ。このエラーメッセージは、4.1が時に壊れてしまうことを示す、唯一の兆候である。

問題は、Berkeley DB をバックエンドに使った Subversion リポジトリ構成しているテーブル内の、あるデータベースフォーマットフィールドが壊れつつある、ということだ。 理由は不明だが、ほとんど常に'copies'テーブルで発生し、'btree' タイプから'recno'タイプへと変更となっている。 シンプルな回復方法は以下の通り。 もしこの方法が成功しなかったら、Subversion Usersメイリングリストへ問い合わせてみよう。

  • 他のプロセスが、リポジトリへアクセスしようとしていないことを確認する。
  • まず、tarや、zipファイルなどに対して、リポジトリをバックアップする。
  • リポジトリのdbサブディレクトリへ移動する。
  • rm __db.* log.*
  • db_dump -p -r copies > copies.dump
  • copies.dump を編集する。先頭近くのセクションで、「type=recno」を 「type=btree」へと変更し、「re_len=」で始まる行を削除する。
  • rm copies
  • db_load copies < copies.dump
  • svnadmin dump .. > ../../my-recovered.svndump
  • 新しいリポジトリを作成し、先ほど生成した dump ファイルを再読込させ、任意のカスタムフックや設定ファイルなどをコピーする。 新しいリポジトリの最新リビジョン番号が、あなたの期待している番号と同じであることを確認しよう。

僕のリポジトリで hotbackup できないよ! svnadmin が 2Gb を越えるファイルで失敗するんだ。

APRに於ける0.9ブランチの初期のバージョン(これは Apache 2.0.x とSubversion 1.xで使われているんだけど)では、大きなファイル(2Gb+)のコピーがサポートされていない。 'svnadmin hotcopy' 問題を解決する修正が行われ、APR 0.9.5+ とApaache 2.0.50+ に取り込まれている。 この修正は全てのプラットフォームで動作するわけではないけれど、Linux 上では動作するよ。

まさに今 commit したファイルのログエントリが見られないんだけど、どうして?

あるリポジトリに対して 'svn checkout' を実行し、作業コピーのリビジョンは7(即ち r7)になっていると仮定しよう。 また、その中には、foo.cという名前のファイルが含まれているものとする。 あなたはこのファイルを変更し、無事にコミットを終えた。この時点で、2つのことが起きている。

  • リポジトリは、サーバ上では r8 へと進んでいる。
  • あなたの作業コピーでは、foo.cファイルだけが r8 へと進んでいる。作業コピーの残りは、r7のままだ。

あなたが今手にしているものは、混在リビジョン作業コピーとして知られているものだ。 1つのファイルはr8だが、他の残りのファイルに関しては、それらがコミットされるまで、または、'svn update'が実行されるまで、r7のまま残されている。

   $ svn -v status
   7        7 nesscg       .
   8        8 nesscg       foo.c
   $

もし 'svn log' をコマンドを、引数を全く指定せずに実行した場合、カレントディレクトリ(上記のリストでは '.'という名前になっている)のログ情報が表示される。 ディレクトリ自身は、まだ r7だから、あなたは r8 のログ情報を目にすることが出来ない。

最新のログを見るためには、以下の何れかを実行しよう。

  1. 'svn log -rHEAD'を実行する。
  2. 'svn log URL' を実行する。URLには、リポジトリの URL を指定すること。
  3. 'svn log foo.c' のように実行して、該当ファイル自体のログ情報を要求する。
  4. 作業コピーをアップデートして、つまり全てを r8 にしてから、'svn log'を実行する。

Berkeley DB 4.3 以降にアップグレードしたら、リポジトリエラーが発生するようになった。

Berkeley DB 4.3 より前の版では、svnadmin recoverは Berkeley DB リポジトリをその場でアップグレードするように動作していた。 しかし、Version 4.3 での Berkeley DB の動作変更に伴い、今では、これは失敗してしまう。

リポジトリをその場で Berkeley DB 4.3 以降へアップグレードするには、以下の手順に従おう。

  • リポジトリにアクセスしているプロセスが存在しないことを確認しよう(Apache や svnserve を止め、file:// 経由でのアクセスや、svnlook、svnadmin などを制限する)。
  • 古いsvnadminバイナリ(つまり、古い Berkeley DB がリンクされたバイナリ)を使って、以下を実行しよう。
    1. 以下の様にしてリポジトリを復旧する: 'svnadmin recover /path/to/repository'
    2. リポジトリをバックアップする
    3. 使っていない全てのログを削除する。これは、次のコマンドで確認できる 'svnadmin list-unused-dblogs /path/to/repeository'
    4. シェアードメモリファイルを削除する。このファイルは、リポジトリのdb/ディレクトリにあり、__db.00* といった形式をしている。

これにより、リポジトリを Berkeley DB 4.3 から利用することが可能だ。

MacOS X 10.4(Tiger)上で稼動しているリポジトリから、http://経由でチェックアウトすると、時々、恐らく不整合エラーと思われる現象に遭遇するんだけど、なんで?

注意: これは、Apache 2.0.x でリポジトリが提供されていることを想定している。

APR 0.9.6 には、Tiger 上で稼動させると生じるバグがあり、64Kb より大きなファイルをチェックアウトしようとすると発症する。 チェックアウト失敗の結果は、しばしば、意味不明なメッセージを伴っている。あなたがクライアント側で目にするかもしれない幾つかのメッセージを以下に示そう(エラー詳細は異なっているかもしれない):

   svn: Invalid diff stream: [tgt] insn 1 starts beyond the target view position
   svn: Unexpected end of svndiff input
   svn: REPORT request failed on '/path/to/repository'
   svn: REPORT of '/path/to/repository/!svn/vcc/default': Chunk delimiter was invalid

Apache の error_log 中にも、次のようなエラーが書き込まれているかもしれない。

   [error] Provider encountered an error while streaming a REPORT response.  [500, #0]
   [error] A failure occurred while driving the update report editor [500, #190004]

このバグの存在を確認するには(あなたがリポジトリを提供しているマシンへアクセスできると仮定しているけど)、file:// URL を使って、チェックアウトを試してみることだ。 これはApacheを経由せずに、直接ファイルシステムへアクセスすることになる。 もし、チェックアウトの結果が完全に上手く行った場合、おそらくこれが原因である可能性が高い。

現在のベストな解は、APR1.2.0+へアップグレードすることだ。

代案としては、Apache の configure 実行前に以下の環境変数を設定した上で、Apache と Subversion とをそれぞれソースから再構築しても良いだろう。

   setenv ac_cv_func_poll no

または、Bourne シェル記法ではこんな感じ。

   ac_cv_func_poll=no; export ac_cv_func_poll

APR / APRUTILを別々にビルドした(つまり、Apache のtarball に付属している版を使わなかった)場合、APRの configure を実行する前にこの環境変数を設定しなければならない。 というのも、そこが問題の潜んでいる場所だから。

Debian GNU/Linux 上で、Subversion を作業コピーのソースから構築できません。 最後のリンク段階で、エラーになってしまいます。 何が悪い?

もし、Subversion trunk ソースのビルド時、最後のリンク段階で次の様なエラーが表示されるなら、

   /usr/local/apache2/lib/libaprutil-0.so.0: undefined reference to `db_create'
   /usr/local/apache2/lib/libaprutil-0.so.0: undefined reference to `db_strerror'

おそらく、あなたは Debian GNU/Linux システムを使っていて、'libtool' をアップグレードをする必要があるからだろう(また、Debian のパッケージャーは、'libtool' を少しいじる必要があって、これが Subversion のビルドで幾つかの問題を引き起こしているのかも、とも聞いた。 とはいえ、これは又聞きにすぎない。 私は、この FAQエントリを書く前に、詳細を確認している時間がとれなかったんだ。 ともかく、本件に関して詳細な議論の行われた、https://svn.haxx.se/dev/archive-2006-02/1214.shtmlとそのスレッドを確認して欲しい)。

何れにせよ、2005/11/15 時点の newly-dist-upgraded 'testing'ディストリビューションである Debian GNU/Linux システム上でこの問題に遭遇した時には、唯一の解法は、libtool 1.5.20を、通常の「./configure && make &&sudo make install」手順に従ってソースから構築することだった。 その後、私の Subversion 作業コピーツリーで 'make clean' を実行し、'./autogen.sh', './configure','make'とやって、全てが上手く行くようになった。

この事象に関する別のレポートとしては、https://svn.haxx.se/dev/archive-2003-01/1125.shtmlがあるけど、ここで述べられた解法は、このスレッドの中では言及されていないことに注意して欲しい。

FreeBSD を使っていて、suvserve を実行しているんだけど、3690番ポートで listen していないみたい。

簡潔な答え: svnserver--listen-host=0.0.0.0オプションをつけて実行しよう。

ちょっとだけ長い答え: FreeBSD デーモンは、デフォルトでは tcp6 しか listen しない。このオプションは、tcp4 でも listen するように指示する。

ディレクトリを追加したいんだけど、Subversion に「既にバージョン管理下におかれています」と言われて、できないんだ。

あなたが登録しようとしているディレクトリには、既に.svnサブディレクトリが存在している。 確かにこれは作業コピーなんだけど、でもこれは、あなたがディレクトリを追加しようとしているのとは異なったリポジトリから取得されたものだ。 これは多分、(svn copyではなく)OSの「copy」コマンドを使って、サブディレクトリをこの作業コピー内にコピーした、または、他の作業コピーをこの中へコピーした為に起こったのだろう。

簡単でキタナイ解法は、あなたの追加しようとしているディレクトリ内にある、全ての.svnディレクトリを削除することだ。 これで、「add」コマンドが動作するようになるだろう。 もしあなたが Unixを使っているならば、次のコマンドで、dir配下にある.svnディレクトリを削除することが出来る。

  find dir -type d -name .svn -exec rm -rf {} \;

とは言え、もしこのコピーが同じリポジトリからきたものならば、本当は、そのコピーを消去、もしくは移動させてから、svn copyを使って、正しくコピーするべきだと思う。 これは、履歴を維持することも出来るし、リポジトリ使用量を削減することも出来る。

もしこのコピーが異なるリポジトリからのものだったなら、「何故このコピーを行ったのか」と言う点を自問してみるべきだ。 また、このディレクトリを追加することで、望んでいないディレクトリのコピーがリポジトリへと追加されてしまうことのないよう、注意しよう。

svnserve 経由で、非公開リポジトリにアクセスすると、時々凄く遅くなる。

これは、大抵、APRが /dev/random を使うようにコンパイルされていて、サーバが十分なエントロピーを収集できなかった時に発生する。 もし Subversion が、そのサーバ上で APR を使う唯一のアプリケーションであるならば、configure--with-devrandom=/dev/urandomオプションを指定してAPRを再コンパイルしても問題はないだろう。 一方、APRを他のプロセスでも使っているシステムの上では、これは行うべきではない。 他のサービスの安全を損なう可能性がある。

SSL上で、大量のデータを伴う Subversion 操作を行っていると、SSL negotiation failed: SSL error: decryption failed or bad record macというエラーが表示されるのですが。

これは、OpenSSL 0.9.8 の発生し得る問題だ。古いバージョンへダウングレードする(または、恐らく新しいバージョンへアップグレードする)ことで、この問題を解決できることが知られている。

「This client is too old」というエラーメッセージが出た。

あなたは、古いバージョン(pre-1.4)の Subversion コマンドラインクライアントとSubclipseの両方を使っている。 あなたは、最近Subclipse をアップグレードし、それ以後、コマンドラインクライアントが次のメッセージを表示するようになった。

svn: This client is too old to work with working copy
'/path/to/your/working/copy'; please get a newer Subversion client

これは Subversion の作業コピーフォーマットが非互換なものへと変更された為に生じている。 新版の Subclipse はあなたの作業コピーをバージョンアップし、その為、あなたのコマンドラインプログラム(こちらは旧版)は、それを読めなくなってしまった(この問題は、Subclipse 特有ではない。 この問題は、あなたが1.4以降のコマンドラインクライアントを、より古い版のコマンドラインクライアントと一緒に使った場合にも起こり得る)。 解法は簡単で、あなたのコマンドラインクライアントを1.4以降の版へとアップグレードすることだ。

svn switchが時たま上手く動作しないのはなぜ?

バージョン管理されていない(また、もしかしたら ignore されている)アイテムが作業コピーにあるような場合、svn switchはエラーになる。 切り替え処理は停止し、作業コピーは半分切り替わった状態のまま取り残される。

不運な事に、もし間違った修正方法を採用した場合、作業コピーは利用不可能になってしまう。 このような事態に陥った場合、時折、ユーザは、svn cleanupするようにと指示される。 しかし、svn cleanupも失敗するかもしれない。 issue #2025を参照して欲しい。

ユーザは手動で、問題を引き起こしたディレクトリやファイルを取り除き、その後svn cleanupを実行して、切り替え処理を継続させることで、この状況から復活させることが可能だ。

素のクリーンなチェックアウトした状態からの切り替えは、エラーになることなく、常に上手く動作することに注意して欲しい。 あなたが開発プロセスの一部としてsvn switchを使っている場合、機能させるためには3つの方法がある。

  1. 切り替え前に、(ignoreされている物も含み)バージョン管理されていないファイルを、完全にクリーンにする。
    警告! これはバージョン管理されていない全てのディレクトリやファイルを消し去ってしまう。 消去対象のファイルを必要としていないことを「十分に」確認するように。
    
    # 確認した上で、バージョン管理されていないファイルを消去
    svn status --no-ignore | grep '^[I?]' | sed 's/^[I?]//'
    svn status --no-ignore | grep '^[I?]' | sed 's/^[I?]//' | xargs rm -rf
    
  2. 素のクリーンなチェックアウトを維持する。更新を行ってからそのコピーを作っておき、もし他のブランチへの切り替えが必要になった場合には、そのコピーの方を切り替える。
  3. デンジャラスに生きる :)。 クリーンアップすることなしに、ブランチ間を切り替える。「しかし」もし切り替えエラーに遭遇した場合には、あなたは、適切なリカバリための方法を知っていなければならない。 エラーの報告された、バージョン管理されていないファイルやディレクトリを消去する。 それから必要に応じて「svn cleanup」を実行し、切り替えを再開する。 全てのバージョン管理されてないファイルを消去するまで、この手順を何度も繰り返す必要があるだろう。

幾つかの例が、ここ issue 2505にある。 問題は、svn client が切り替え処理を安全に、且つ、バージョン管理されていない如何なる物も消去することなしに行おうという点にある。

このような問題を示すために、ここで2つの典型的な例を示そう。 ここではカバーされていない、他の svn switch エラーもあるけれど、それらは、素のチェックアウトから切り替えることで回避できる。

  1. もしブランチ間で、ディレクトリが移動されたり、または名前の変更がなされている場合、バージョン管理されていない如何なるものも、問題を引き起こすだろう。 この場合、次のようなエラーが表示される。
    
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Won't delete locally modified directory '<dir>'
    svn: Left locally modified or unversioned files
    

    バージョン管理されてない全てのファイルを除去し、切り替えを継続させることで、この状況から回復できる。

  2. もし、一時的なビルドファイルが追加や消去されている場合、そうした(主にビルド後などに生じる)バージョン管理されていないファイルを含むリポジトリの切り替えは失敗し、次のようなエラーとなる。
    
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Won't delete locally modified directory '<dir>'
    svn: Left locally modified or unversioned files
    

    この場合、単にバージョン管理されていないアイテム群を取り除くだけでは回復できないだろう。 cleanupは失敗に終わるが、しかし、svn switch は「svn cleanup」を実行するよう指示してくる。

    
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Directory '<dir>/.svn' containing working copy admin area is missing
    wc/$ svn cleanup
    svn: '<dir>' is not a working copy directory
    wc/$ svn switch $SVNROOT/$project/branches/$ticket-xxx
    svn: Working copy '.' locked
    svn: run 'svn cleanup' to remove locks (type 'svn help cleanup' for details)
    

    このディレクトリ(と、同様のエラーを繰り返し「switch」を妨げる他の全てのバージョン管理されていないファイル)を消去した上で切り替えを継続することで、回復できるだろう。

TortoiseSVN クリーンアップエラーは、ちょっと違っている。こんな感じだ。


Subversion reported an error while doing a cleanup!
<dir>/<anotherdir> is not a working copy directory

ここで述べた各事例に於いて、「svn switch」が失敗した場合には、作業コピー半分切り替わった状態のままになってしまう。 「svn status」では、切り替わったアイテム(トップディレクトリと異なっている)には「S」を付けて、また、問題のあるディレクトリには「!」を付けて、また、問題のあるファイルには「~」を付けて(ロックを示す L が付くかもしれない)示してくれる。 こんな感じだ。


wc/$ svn status 
!      .
!      <dir>
    S  <switched_things>
~      <dir>/<thing_that_is_now_unversioned>

Windowsでコマンドラインクライアントをアップデートすると、「システムは指定されたパスを見つけられません」とのエラーが表示され、作業コピーが壊れているのかも、と教えてくれる。 でも、TortoiseSVNのアップデートは上手く行く。何が起こっているの?

Naming a File(ファイルの名前付け)に関する WindowsAPI ドキュメントを注意深い解読により、これが生じた原因に関する、最も一般的な理由を解き明かすことが出来る。 手短に言えば、Windowsパス関数群のUnicodeバージョンを使っていて、且つ、相対パス指定ではなく絶対バス指定を使っている場合に限り、非常に長いパス名を指定することができる。 幸いにも、Subversion が使っているApache Portable Runtime(APR)ライブラリは、絶対パス名(C:\WorkingCopy\file.txtなど)を、Windows API が要求している形式(\\?\C:\WorkingCopy\file.txt)へ透過的に変換することが可能であり、また逆変換も可能だ。 残念な点は、この長いパス名の恩恵は、絶対パス名を使ったときにしか受けられない、ということだ。

もしパス名の長さが、あなたの直面している問題の唯一の原因であるように思えるならば、相対パスではなく(また、何も指定しないのではなく)、絶対ターゲットパス名を Subversion のコマンドラインクライアントへ指定してみよう。 言い替えれば、次のように指定したり、


C:\> svn up WorkingCopy

また、


C:\> cd C:\WorkingCopy
C:\WorkingCopy> svn up

とする変わりに、


C:\> svn update C:\WorkingCopy

とする、ということだ。 もし、問題が消え去ったならば、おめでとう! あなたは Windows のパス長制限にぶちあたっていたわけで、そして今、その回避方法を理解したわけだ。

どうしてこの問題は、TortoiseSVN では発生しないんだろう? それは、TortoiseSVN は Subversion API に対して、常に絶対パス名を引き渡しているからだ。

では、なぜ、Subversion コマンドラインクライアントは、常に入力を絶対パスへと変換し、それを使う、という風にしないんだろう? Subversion 開発者達はある原則に従っている。その原則とは、ユーザ体験の観点から、ツールの出力としてパスを表示する場合には、入力として渡されたパスの記法に合わせるべきだ、というものだ。 また、ある相対パスを絶対パスへと変換することは簡単な作業なのだか、逆変換は、複雑性で溢れている(言い替えれば、我々の優先度リストの上位には位置していない、困難な問題だということだ)。

「This client is too old to work with working copy '...'(...作業コピーに対して、このクライアントは古すぎます)」というエラーメッセージが表示されました。 Subversionをアップグレードすることなく、これを解決したいんですが。

時々、作業コピーのメタデータフォーマットは、マイナーリリース間で互換性を持たずに変更になる。例えば、Subversion 1.4.4で作られた作業コピーを有しているとして、でも、ある日、Subversion 1.5.0 を試してみることにした。 その後、1.4.4へ戻そうとするものの、でもそれは機能しない。 上記のエラーが表示されるだけだ。

これは、1.5.0 があなたの作業コピーフォーマットを、ある新しい機能(今回の例では、チェンジリスト、keep-localフラグ、そして、可変深度ディレクトリ)をサポートするべく、アップグレードしたためだ。 1.4.4 はこれらの新機能に関しては何も知らないが、少なくとも、作業コピーのフォーマットが、自分の扱うことが出来ない、何やら上位の版へとアップグレードされている、ということだけは認識することが出来る。

1.5.0 では、正当な理由で作業コピーをアップグレードした。 というのは、1.4.4 は、これらの新機能について知らないから、もし 1.4.4 が作業コピーのメタデータに触れたならば、重要な情報が消失し、場合によっては破壊してしまうかも知れない、ということに気がついたからだ(例えば、issue#2961を参照の事)。

しかし、この自動アップグレードという振る舞いは、あなたが、ただ新しい Subversion のリリースを、本格的にインストールするのではなく、ただ試してみたいだけ、という場合には、煩わしいものだろう。 この為、我々は安全に作業コピーをダウングレードさせるスクリプトを配布している。

http://svn.collab.net/repos/svn/trunk/tools/client-side/change-svn-wc-format.py

--help」オプションを付けて、スクリプトを実行することで、使い方が表示される。 Subversion の将来の版がリリースされた場合、起こりうるダウングレードのシナリオと、その影響とを記して、このFAQエントリを最新状態に保つように努力するつもりだ。

Neon ライブラリを 64-bit Linux 上でビルドしたら、"relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object"というエラーが表示されたよ。

Neon ライブラリは Subversion サーバとクライアントとを HTTP を介して接続するために使われるのだけれど、通常、静的ライブラリとしてビルドされる。 しかしこれは、その後で、別の動的ライブラリと結合される。 これにより、64-bit AMD システム上では、ビルドプロセスの最中に次のようなエラーを引き起こす。


subversion-1.4.6/neon/src/.libs/libneon.a(ne_request.o): relocation R_X86_64_32
against `a local symbol' can not be used when making a shared object;
recompile with -fPIC
/home/jrandom/subversion/subversion-1.4.6/neon/src/.libs/libneon.a: could not
read symbols: Bad value

これに関しては開発者向けリスト上で話題になった。

解決策は、Subversion の configure スクリプトへ「--enable-shared」オプションを付与することだ。

Developer questions:

リグレッションテストをRAMディスク上で走らせる方法は?

Subversion のテストデータをRAMディスク上に置いた場合、テストの実行速度を劇的に改善することができる。 Linuxシステム上では、以下のコマンドにより、RAM ディスクを好きなタイミングでmount出来る。

mount -t tmpfs tmpfs /path/to/src/subversion/tests/cmdline/svn-test-work -o uid=$USER,mode=770,size=32m

または、もっと永続性のある解法が希望ならば、次のような行を、/etc/fstabファイルへ追加しよう。

tmpfs /path/to/src/svn/subversion/tests/cmdline/svn-test-work tmpfs defaults,user,noauto,exec,size=32m

テストの実行に必要となるRAMディスクの最低サイズは、おおよそ、700MBだ。 しかし、テストターゲットへクリーンアップ用のフラグを付与することで、(上のコンフィギュレーションの例で見たように)必要となるスペース容量を、即ちメモリ使用量を、大幅に削減することが可能だ。 クリーンアップは、I/O処理の増加を意味するが、テストデータはメモリ上にある為、パフォーマンスの低下にはつながらないだろう。 こんな感じだ。

make check CLEANUP=true

RAM ディスクの利用に関する、オリジナルの信用できる議論は、https://svn.haxx.se/dev/archive-2003-02/0068.shtmlを参照のこと。

動的な Subversion バイナリを、インストールすることなしにデバッガ上で稼動させるには?

Unix系システムに於いては、make installを実行する前の状態では、Subversion ソースツリー内にある動的に構築された「実行形式」と言うのは、実のところ、再リンクを行い実際のバイナリを実行させる為のlibtoolによって生成されたシェルスクリプトである。 以下で見るように、これはデバッグ作業を複雑なものにする。

subversion$ gdb subversion/svn/svn
... "/path/to/subversion/subversion/svn/svn": not in executable format: File format not recognized

これは、configure の実行時 --disable-shared引数を使って、静的結合されたバイナリを作ることで回避することができるし、また、これらをインストールして、デバッガにインストールした版を指定することでも回避できる。 しかし、多くの場合、ソースツリーのただ中でデバッグできることが、必要だったり便利だったりする。

そこで、デバッガ内で実バイナリを実行できるように、シェルスクリプトの最後のexec文を編集しよう。 gdb を使うならば、exec "$progdir/$progname"exec gdb --args "$progdir/$progname"に置き換える、ということだ。

このトリックは、libtoolが生成したシェルスクリプトに対してホワイトボックステストを実行する場合にも、大変に有益だよ。

Subversion バイナリに対してデバッガを実行したいんだけど、コンパイラがソースをインライン展開して消し去ってしまわないようにするためには?

デフォルトの場合、gcc はしばしばプライベート変数や関数を、適切な操作へとインライン展開することにより、最適化した上で除去する。これは、コードをデバッガで追っているときには、面倒なステップとなる。

unix系のシステムでは、make時に最適化を行わせないようにする事で、回避可能だ。

subversion$ make EXTRA_CFLAGS=-O0

(これは「ダッシュ、オー、ゼロ」だよ)。また、configure実行時に、次のようにすることで、この変更をより永続性のあるものへとすることが出来る。

subversion$ ./configure --enable-debug

実運用向けのインストール時には、Subversion をソースからインストールする前に、余分な引数を与えずに makeconfigureを再実行して、この操作を元に戻すことを忘れないように。

References:

Subversionが使っている全ての HTTP メソッドは?

Subversion クライアントは、mod_dav_svn サーバモジュールに対して、WebDAV/DeltaV プロトコルのサブセットを話す。端的な回答は次の通り。

     OPTIONS, PROPFIND, GET, REPORT,
     MKACTIVITY, PROPPATCH, PUT, CHECKOUT, MKCOL,
     MOVE, COPY, DELETE, LOCK, UNLOCK, MERGE

プロトコルの詳細は、ここに記載されている。

http://svn.collab.net/repos/svn/trunk/notes/webdav-protocol

「bikeshed」ってなに?

See Poul-Henning Kamp's post to freebsd-hackers: https://www.freebsd.org/doc/en_US.ISO8859-1/books/faq/misc.html#BIKESHED-PAINTING.

「Subvesion」ってどうやって発音するの?

Jim Blandy、彼は Subversion の命名とリポジトリデザインを行ったんだけど、「Subversion」を「Subversion」と発音している。

「baton」ってなに?

Subversion のソースコードを通して、幾つもの「baton」オブジェクトへの参照が存在する。 これは、関数に対してコンテキストを提供するただのvoid*データ構造だ。他のAPIでは、これらはしばしば、void *ctxvoid *userdataと呼ばれるが、Subversion の開発者は、この構造を「batons」と称している。 というのも、これらは相当数、引き回されることになるからだ。

リポジトリが「Wedged」になった、っていうけど、それってどういう意味?

wedged リポジトリとは:

Subversion リポジトリは、2つの異なる内部パーツから構成される。 ワーキング区画と、ストレージ区画だ。 Wedged リポジトリとは、ワーキング区画には何らかの理由でアクセスすることができないが、ストレージ区画は問題のないリポジトリのことを言う。 従って Wedged リポジトリでは、データの損失は生じていない。 但し、リポジトリへアクセス出来るようにする為には、ワーキング区画を修正する必要がある。 その方法は、このエントリを参照のこと。

corrupted リポジトリとは:

corrupted な Subversion リポジトリとは、ストレージ区画がダメージを受けているリポジトリのことで、従って、リポジトリ内に於いて、一定量のデータ損失が生じている。

The Jargon File の 'wedged'の定義を併せて参照すると良いだろう。