今さら聞けない svn add の基本と使い方


今さら聞けない svn add の基本と使い方:バージョン管理の第一歩を徹底解説

バージョン管理システムは、ソフトウェア開発をはじめとする様々なプロジェクトにおいて、ファイルの変更履歴を管理し、複数人での共同作業を円滑に進めるための必須ツールです。中でも、Subversion (以下、svn) は、歴史が長く、現在でも多くの現場で利用されています。

Gitのような分散型バージョン管理システムが主流となりつつありますが、集中型であるsvnにも独自の強みがあり、根強いユーザーがいます。特に、既存のプロジェクトがsvnで管理されている場合、svnの基本的な操作は避けて通れません。

svnのコマンドの中でも、新しいファイルやディレクトリをバージョン管理の対象に加えるためのコマンドが svn add です。このコマンドは、svnを使ったバージョン管理の第一歩とも言える非常に重要なものですが、「今さら聞けない」と感じている方もいらっしゃるかもしれません。

この記事では、svnの基本的な概念に触れつつ、svn add コマンドに焦点を当て、その目的、基本的な使い方から、様々なオプション、関連するコマンド、よくある疑問やトラブルシューティングまで、徹底的に詳細に解説します。この記事を読めば、svn add に関するあなたの疑問はきっと解消されるでしょう。

1. なぜ今さら Subversion (svn) なのか?

まず、なぜ今でもsvnが使われているのか、簡単にその背景に触れておきましょう。

1.1. バージョン管理システムとは

バージョン管理システムは、ファイルやディレクトリの変更履歴を記録し、管理するためのシステムです。これにより、以下のようなメリットが得られます。

  • 変更履歴の追跡: いつ、誰が、何をどのように変更したかを正確に記録できます。
  • 過去の状態への復元: 必要に応じて、過去の任意の状態にファイルを戻すことができます。
  • 複数人での共同作業: 同じファイルを同時に編集しても、変更を安全に統合できます。
  • 差分の確認: ファイルの変更内容を、過去の状態と比較して確認できます。

1.2. 集中型バージョン管理システム (CVCS) と分散型バージョン管理システム (DVCS)

バージョン管理システムには、主に集中型と分散型があります。

  • 集中型 (CVCS): リポジトリ(変更履歴の集中管理場所)が一つ存在し、各ユーザーはリポジトリからファイルを取得し、変更をリポジトリに反映させます。Subversion はこの集中型に分類されます。
    • メリット: 管理が容易(サーバーが一箇所)、アクセス権限の管理がしやすい、プロジェクト全体の状態把握が比較的容易。
    • デメリット: サーバーが停止すると作業が困難になる、ネットワーク接続が必須(オフラインでのコミットができない)、ブランチやタグの操作が比較的重い。
  • 分散型 (DVCS): 各ユーザーがリポジトリ全体の複製をローカルに持ちます。コミットはまずローカルリポジトリに対して行われ、その後必要に応じて他のリポジトリ(通常は共有のセントラルリポジトリ)と同期します。Git はこの分散型に分類されます。
    • メリット: オフラインでの作業が可能、コミットやブランチ/タグの操作が高速、ローカルでの試行錯誤が容易。
    • デメリット: リポジトリが各所に分散するため管理がやや複雑になる場合がある、大規模なバイナリファイルの扱いに注意が必要な場合がある。

1.3. Subversion (svn) が使われ続ける理由

Gitなどの分散型システムが主流になった現在でも、svnが利用され続けているのは、以下のような理由が挙げられます。

  • 歴史的な経緯: 長年使われてきたシステムであり、既存の多くのプロジェクトがsvnで管理されているため、移行コストが高い。
  • シンプルさ: 集中型であるため、概念が比較的シンプルで理解しやすいと感じるユーザーもいる。特に、ローカルリポジトリの管理を意識する必要がない点は、初心者にとって扱いやすい場合がある。
  • 管理の容易さ: サーバーが集中しているため、管理者にとっては権限管理などが一元的に行いやすい。
  • 特定のワークフローへの適合: プロジェクトの性質や組織の文化によっては、集中型のワークフローが適している場合がある。

あなたがsvnプロジェクトに関わることになった以上、svnの基本操作を習得することは必須です。そして、新しいファイルやディレクトリをバージョン管理下に加える最初のステップが svn add コマンドです。

2. Subversionの基本的な流れと svn add の位置づけ

svn add コマンドを理解するためには、svnの基本的なワークフローを把握しておくことが重要です。

2.1. svnの主要な構成要素

  • リポジトリ (Repository): プロジェクトの全てのファイルとその変更履歴が保管される中央の保管庫です。通常、サーバー上に配置されます。
  • ワーキングコピー (Working Copy): リポジトリの特定のリビジョン(バージョン)のファイル一式を、ローカルコンピュータにチェックアウト(取得)したものです。このワーキングコピー内でファイルの編集作業を行います。
  • リビジョン (Revision): リポジトリ全体のスナップショット(ある時点での状態)を識別する番号です。コミットが行われるたびにリビジョン番号は増加します。

2.2. svnの基本的なワークフロー

一般的なsvnのワークフローは以下のようになります。

  1. チェックアウト (Checkout): リポジトリからワーキングコピーをローカルに取得します。
    bash
    svn checkout URL [PATH]
  2. 更新 (Update): 他の人がリポジトリにコミットした変更を、自分のワーキングコピーに取り込みます。
    bash
    svn update [PATH]
  3. 編集 (Edit): ワーキングコピー内のファイルを編集します。ここで新しいファイルを作成したり、既存のファイルを変更したりします。
  4. 追加 (Add): 新しく作成したファイルやディレクトリを、次にコミットする変更として予約します。 このステップで svn add コマンドを使います。
    bash
    svn add PATH...
  5. 削除/移動/コピー (Delete/Move/Copy): ファイルやディレクトリを削除、移動、コピーする場合、これらの操作もsvnコマンドで行うことで、履歴が正しく管理されます。
    bash
    svn delete PATH...
    svn move SOURCE DEST
    svn copy SOURCE DEST
  6. ステータスの確認 (Status): ワーキングコピーでどのような変更が行われたか(変更されたファイル、追加されたファイル、削除されたファイルなど)を確認します。
    bash
    svn status [PATH...]
  7. 差分の確認 (Diff): ワーキングコピーでの変更内容を、オリジナルの状態と比較して確認します。
    bash
    svn diff [PATH...]
  8. コミット (Commit): ワーキングコピーで行った変更(ファイルの編集、追加、削除、移動など)をリポジトリに反映させます。これにより、新しいリビジョンが作成されます。
    bash
    svn commit -m "コミットメッセージ" [PATH...]

2.3. svn add の役割

上記のワークフローの中で、svn add は「追加 (Add)」のステップを担当します。

あなたがローカルのワーキングコピー内で新しいファイルやディレクトリを作成しただけでは、それはまだsvnの管理対象ではありません。svn コマンドにとっては、単に「ワーキングコピー内の管理対象外のファイル」と認識されます。

svn add コマンドを実行することで、svnに対して「このファイル/ディレクトリを、次のコミットでリポジトリに追加したい」という意図を伝えます。これにより、そのファイル/ディレクトリはバージョン管理下に加えるための予約が行われた状態になります。

重要なのは、svn add を実行しただけでは、まだリポジトリには何も変更が反映されないということです。変更をリポジトリに反映させるためには、次のステップである svn commit コマンドを実行する必要があります。

たとえるなら、svn add は買い物カゴに商品を入れるようなものです。カゴに入れただけではまだ購入は確定していません。レジ(svn commit)で精算して初めて自分のものになります。

3. svn add コマンドの基本

それでは、svn add コマンドの基本的な使い方を見ていきましょう。

3.1. 目的と構文

  • 目的: 新しいファイルまたはディレクトリを、バージョン管理下に加えるための予約をします。
  • 構文:
    bash
    svn add PATH...

    PATH には、バージョン管理下に加えたいファイルまたはディレクトリのパスを指定します。複数のパスを同時に指定することも可能です。

3.2. svn add 実行時の挙動

svn add コマンドを実行すると、主に以下の処理が行われます。

  1. 追加予約: 指定されたファイルやディレクトリが、ローカルのワーキングコピー内で「追加予約された」状態になります。
  2. ステータス変更: そのファイルやディレクトリのステータスが A (Added) と表示されるようになります。これは svn status コマンドで確認できます。
  3. .svn ディレクトリの更新: svnが内部的に管理している情報(通常、各ディレクトリにある .svn サブディレクトリ内に格納されています)が更新され、このファイル/ディレクトリが次回のコミットで追加される予定であることが記録されます。
  4. リポジトリへの未反映: 繰り返しになりますが、この時点ではリポジトリ自体にはまだ何も変更は送られていません。 変更はローカルのワーキングコピー内に留まります。

3.3. 具体的な使い方(単一ファイル)

例えば、ワーキングコピーのディレクトリ myproject/src/ の中に、新しく hello.c というファイルを作成したとします。

myproject/
├── .svn/
└── src/
└── main.c (既存ファイル, バージョン管理下)

ここに hello.c を新規作成しました。

myproject/
├── .svn/
└── src/
├── main.c
└── hello.c (新規ファイル)

この hello.c をバージョン管理下に加えたい場合、以下のコマンドを実行します。

bash
cd myproject/
svn add src/hello.c

コマンド実行後、特にエラーが出なければ成功です。

3.4. svn status での確認

svn add src/hello.c を実行した後、svn status コマンドでワーキングコピーの状態を確認してみましょう。

bash
svn status

以下のような出力が表示されるはずです。

A src/hello.c

この A は “Added” を意味します。つまり、src/hello.c というファイルがバージョン管理下に追加されることが予約された状態であることを示しています。

もし svn add を実行する前に svn status を実行していたら、以下のような出力が表示されていたでしょう。

? src/hello.c

この ? は “Not versioned” を意味します。つまり、ワーキングコピー内に存在するが、svnの管理下に置かれていないファイルやディレクトリであることを示しています。

svn add コマンドは、この ? ステータスのファイルを A ステータスに変更する役割を果たします。

3.5. svn addsvn commit の違い(重要)

svn初心者が最も混同しやすい点の一つが、svn addsvn commit の違いです。

  • svn add: 新しいファイル/ディレクトリをローカルのワーキングコピー内で、バージョン管理下への追加を予約するコマンドです。この時点ではリポジトリには何も変更されません。
  • svn commit: ワーキングコピーで行った変更(svn add で予約した追加、編集、削除、移動など)をリポジトリに反映させるコマンドです。このコマンドによって初めて、新しいファイルがリポジトリに登録され、他の人もそのファイルを取得できるようになります。

したがって、新しいファイルを追加する際は、以下の2段階の操作が必要です。

  1. svn add で追加を予約する。
  2. svn commit で予約した追加をリポジトリに反映させる。

svn add を忘れて svn commit しようとしても、新しく作成したファイルはコミットされません。svn commit は、あくまで「バージョン管理下のファイルに対する変更」を反映するコマンドだからです。新しく作成したファイルは、svn add を実行するまではバージョン管理下ではないため、コミットの対象になりません。

4. svn add の様々な使い方とオプション

svn add にはいくつかの使い方や、挙動を制御するオプションがあります。

4.1. 複数ファイルの追加

複数の新しいファイルを同時に追加予約したい場合、svn add コマンドに複数のパスをスペース区切りで指定します。

例えば、src/ ディレクトリに utils.cutils.h という2つの新しいファイルを作成した場合。

bash
svn add src/utils.c src/utils.h

svn status を確認すると、両方のファイルが A ステータスになっているはずです。

bash
svn status

A src/utils.c
A src/utils.h

4.2. ディレクトリの追加

新しいディレクトリを作成し、そのディレクトリごとバージョン管理下に加えたい場合も、svn add コマンドを使用します。

例えば、myproject/tests/ という新しいディレクトリを作成し、その中にテストファイル test_hello.c を作成したとします。

myproject/
├── .svn/
├── src/
│ ├── main.c
│ └── hello.c
└── tests/ (新規ディレクトリ)
└── test_hello.c (新規ファイル)

ここで、tests/ ディレクトリをバージョン管理下に加えたい場合。

bash
cd myproject/
svn add tests/

このコマンドを実行すると、tests/ ディレクトリだけでなく、そのディレクトリ内にすでに存在する管理対象外のファイル (test_hello.c) も含めて、再帰的に追加予約されます

svn status を確認してみましょう。

bash
svn status

A tests
A tests/test_hello.c

このように、ディレクトリ自身と、その中にあるファイル(またはサブディレクトリ)が同時に追加予約されるのが svn add のデフォルトの挙動です。これは非常に便利で、新しい機能のために複数のファイルとディレクトリを一度に追加したい場合などに役立ちます。

4.3. 非再帰的な追加 (--non-recursive / -N)

場合によっては、「ディレクトリ自体はバージョン管理下に入れたいが、その中にある既存のファイルやサブディレクトリはまだ追加したくない」ということがあります。例えば、新しいディレクトリ構造だけを先にコミットしておきたい場合などです。

このような場合、--non-recursive または短縮形の -N オプションを使用します。

例えば、先ほどの tests/ ディレクトリを、中身の test_hello.c はまだ追加せずにディレクトリだけ追加予約したい場合。

“`bash
cd myproject/
svn add –non-recursive tests/

または

svn add -N tests/
“`

このコマンド実行後、svn status を確認してみましょう。

bash
svn status

A tests
? tests/test_hello.c

出力からわかるように、tests ディレクトリは A (Added) ステータスになりましたが、その中の test_hello.c? (Not versioned) のままです。ディレクトリだけが非再帰的に追加予約されたことになります。

--non-recursive オプションは、ディレクトリに対してのみ意味を持ちます。ファイルに対して指定しても効果はありません(ファイルは常に単体で追加されるため、再帰/非再帰の概念がないからです)。

4.4. 追加するファイルのパターンを指定する (--depthsvn:ignore との関連)

svn add コマンド自体には、特定のパターンに一致するファイル(例: *.log*.tmp)を自動的に除外して追加する直接的なオプションはありません。しかし、関連する機能やワークフローで、意図しないファイルがバージョン管理下に加えられるのを防ぐことができます。

4.4.1. --depth オプション

--depth オプションは、svn add コマンドだけでなく、svn update, svn checkout, svn status など、様々な再帰的な操作コマンドで使用されます。これは、操作の対象とする深さを指定するためのオプションです。

svn add コマンドで使用する場合、ディレクトリの追加予約の深さを制御できます。

  • svn add --depth empty mydir/: mydir/ ディレクトリ自体のみを追加予約します(内容は含まない)。これは --non-recursive と似た効果になりますが、--depth はより細かい制御が可能です。
  • svn add --depth files mydir/: mydir/ ディレクトリと、その直下にあるファイルのみを追加予約します(サブディレクトリやその内容は含まない)。
  • svn add --depth immediate mydir/: mydir/ ディレクトリと、その直下にあるファイルおよびサブディレクトリ自体を追加予約します(サブディレクトリ内の内容は含まない)。
  • svn add --depth infinity mydir/: mydir/ ディレクトリと、その中の全てのファイルおよびサブディレクトリを再帰的に追加予約します(これが --recursive またはオプションなしのデフォルト動作です)。

例として、以下のような構造で、mydir/ ディレクトリを files の深さで追加予約する場合を考えます。

myproject/
└── mydir/ (新規ディレクトリ)
├── file1.txt (新規ファイル)
├── file2.log (新規ファイル)
└── subdir/ (新規ディレクトリ)
└── file3.txt (新規ファイル)

bash
cd myproject/
svn add --depth files mydir/

svn status を確認すると、以下のようになるはずです。

bash
svn status

A mydir
A mydir/file1.txt
? mydir/file2.log (拡張子が異なるがファイルなので追加される)
? mydir/subdir (サブディレクトリは追加されない)
? mydir/subdir/file3.txt (サブディレクトリ内のファイルも追加されない)

注意点として、--depth files は「その深さにあるファイル」を追加予約する指定であり、ファイル名のパターンによるフィルタリングは行いません。上記の例で file2.logA になっているのはそのためです。パターンによる除外は、次に説明する svn:ignore プロパティの役割です。

4.4.2. svn:ignore プロパティの活用

特定のファイルやディレクトリをバージョン管理の対象から恒久的に除外したい場合、svn:ignore プロパティを使用します。これは、svn status? と表示されるリストから、指定されたパターンに一致するものを非表示にしたり、svn add コマンドの実行時に誤って追加してしまうのを防ぐのに役立ちます。(厳密には、svn add * のようなワイルドカードを使った場合に、svn:ignore の設定を考慮するかどうかはクライアントの実装に依存しますが、一般的には考慮されます)。

例えば、コンパイル生成物 (*.o, *.exe) やログファイル (*.log)、一時ファイル (*.tmp) などは、通常バージョン管理する必要がありません。これらを間違って svn add してしまわないように、svn:ignore を設定しておくと便利です。

svn:ignore プロパティは、無視したいファイルやディレクトリが存在するディレクトリに対して設定します。

例: myproject/src/ ディレクトリにある *.log ファイルを無視したい場合。

  1. 無視するパターンをファイル (ignore_patterns.txt など) に記述するか、直接コマンドラインで指定します。
    *.log
    temp_*
  2. そのパターンを src/ ディレクトリに svn propset コマンドで設定します。
    bash
    cd myproject/
    # ファイルから設定する場合
    svn propset svn:ignore -F ignore_patterns.txt src/
    # コマンドラインで直接設定する場合(改行区切り)
    svn propset svn:ignore "*.log"$'\n'"temp_*" src/

    MacやLinuxのBashでは $'\n' で改行を表現できます。Windowsのコマンドプロンプトでは、改行を含んだ文字列をペーストするなど工夫が必要です。複数行のパターンを扱う場合は、ファイルを指定するのが一般的です。
  3. svn propset コマンド自体がワーキングコピーの変更なので、これをリポジトリに反映させるためにコミットします。
    bash
    svn commit -m "Add svn:ignore property to src/" src/

これで、src/ ディレクトリ内に test.logtemp_output.txt といったファイルを作成しても、svn status コマンドで ? と表示されなくなり、svn add * src/ のようなコマンドでまとめて追加しようとした際にも誤って追加される可能性が低くなります。

もし、svn:ignore を設定する前に誤って svn add してしまい、ステータスが A になってしまった場合は、svn revert コマンドで追加予約を取り消すことができます。(後述の「追加予約の取り消し」を参照)。

4.5. バイナリファイルの追加

svn add コマンドは、テキストファイルでもバイナリファイルでも同じように使用できます。svnはファイルの MIME タイプを自動的に検出するか、必要に応じてプロパティ (svn:mime-type) を設定することで、バイナリファイルを適切に扱います。

バイナリファイル(画像ファイル、実行可能ファイル、圧縮ファイルなど)は、通常差分を取ることができません。svnはバイナリファイルの変更に対しては、ファイル全体を新しいバージョンとしてリポジトリに格納します。テキストファイルの差分管理に比べてリポジトリの容量を消費しやすい傾向があるため、非常に大きなバイナリファイルや頻繁に変更されるバイナリファイルを大量に管理する際には注意が必要です。

svn:executable プロパティを設定することで、実行可能ファイルとしてマークすることも可能です。(例: svn propset svn:executable ON your_script.sh

5. svn add 実行後の状態と次のステップ

svn add コマンドを実行した後のワーキングコピーの状態と、次に取るべきアクションについて解説します。

5.1. ワーキングコピーの状態を確認する (svn status)

前述の通り、svn add 実行後の最も重要な変化は、指定したファイルやディレクトリのステータスが A (Added) になることです。これは svn status コマンドで確認します。

bash
svn status

出力例:

M src/main.c # 既存ファイルで変更があったもの
A src/hello.c # svn add で追加予約したもの
A tests # svn add で追加予約したディレクトリ
A tests/test_hello.c # ディレクトリ追加時に再帰的に追加予約されたファイル
? build/output.log # ワーキングコピーにあるが未管理のファイル

svn add したファイルは A と表示されます。また、svn statussvn add されていない未管理のファイル(? ステータス)も同時に表示してくれます。

5.2. 追加予約を取り消す (svn revert)

「やっぱりこのファイルはバージョン管理下に加えなくていいや」「間違って追加予約してしまった」という場合、svn add による追加予約を取り消すことができます。これには svn revert コマンドを使用します。

bash
svn revert PATH...

例えば、src/hello.c の追加予約を取り消したい場合。

bash
svn revert src/hello.c

コマンド実行後、svn status を確認すると、src/hello.c のステータスが A から ? に戻っているはずです。

bash
svn status

M src/main.c
? src/hello.c # 追加予約が取り消された
A tests
A tests/test_hello.c
? build/output.log

svn revert は、svn add だけでなく、ファイルの内容変更 (M) や削除予約 (D) など、ローカルのワーキングコピーで行った様々な変更を取り消すために使用できる強力なコマンドです。svn revert は変更内容を破棄するため、使用する際は注意が必要です。ただし、svn addrevert は、ファイル自体を削除するわけではなく、あくまで「追加予約」を取り消すだけです。ファイル自体はワーキングコピーにそのまま残ります。

5.3. リポジトリに反映させる (svn commit)

svn add で追加予約したファイルやディレクトリを、いよいよリポジトリに反映させます。これには svn commit コマンドを使用します。

bash
svn commit -m "コミットメッセージ" [PATH...]

コミットメッセージ (-m オプションに続く文字列)は、そのコミットでどのような変更を行ったのかを簡潔に説明する重要な情報です。必ず分かりやすいメッセージを記述しましょう。

例えば、先ほど svn add した src/hello.ctests/ ディレクトリ(とその中身)をコミットする場合。

bash
cd myproject/
svn commit -m "Add hello.c and test directory for the new feature" src/hello.c tests/

パスを省略して svn commit -m "..." とだけ実行した場合、ワーキングコピー全体で行われた全ての変更(A, M, D ステータスなど)がコミット対象となります。特定のファイル/ディレクトリだけをコミットしたい場合は、パスを引数に指定します。

svn commit が成功すると、以下のような情報が表示されます。

Adding src/hello.c
Adding tests
Adding tests/test_hello.c
Transmitting file data ... done
Committing revision XXX.

XXX は新しく作成されたリビジョン番号です。

5.4. commit 後の状態

svn commit が成功すると、以下のようになります。

  • svn add で追加予約されていたファイルやディレクトリが、正式にリポジトリに登録されます。
  • ワーキングコピー内のそれらのファイルのステータスが A から消え、通常の状態に戻ります(svn status で何も表示されなくなります)。
  • 新しくコミットされたリビジョンが作成され、他のユーザーはそのリビジョンを svn update コマンドで取得できるようになります。
  • コミット対象外だった未管理ファイル(? ステータスのままだったファイル)は、コミット後も ? ステータスのままワーキングコピーに残ります。

6. 実践的なシナリオと応用

svn add がどのような場面で使われるか、いくつかの実践的なシナリオを見てみましょう。

6.1. 新しいプロジェクトを開始する際の初期コミット

新しいプロジェクトをsvnで管理し始める際、最初に行うのが初期コミットです。

  1. プロジェクトのルートディレクトリを作成し、その中に管理したいファイルやディレクトリを配置します。
    bash
    mkdir mynewproject
    cd mynewproject
    echo "Hello, world!" > main.c
    mkdir includes
    echo "#include <stdio.h>" > includes/header.h
  2. 空のリポジトリを作成するか、既存のリポジトリ内のパスを使用します。ここでは既存のリポジトリ svn://server/repo 内の mynewproject パスを使用するとします。
  3. ローカルのディレクトリを、リポジトリの特定のパスにインポート (import) します。インポートは、ローカルのディレクトリ構造を、一度にリポジトリの新しいパスにコピーし、バージョン管理下に置く操作です。この操作は、新規のファイルやディレクトリをリポジトリに追加する特別な commit と考えることができます。内部的には、インポート対象の全てのファイルとディレクトリが「追加」として扱われます。
    bash
    svn import . svn://server/repo/mynewproject -m "Initial import of mynewproject"

    この svn import コマンドは、ローカルディレクトリ (.) の内容をリモートのURL (svn://server/repo/mynewproject) に一括で追加(コミット)します。インポート元ディレクトリは、インポート後もローカルに残りますが、インポートされたファイル自体はバージョン管理下にはなりません。ワーキングコピーを作成するには、改めて svn checkout する必要があります。

  4. インポートが完了したら、ワーキングコピーを作成します。
    bash
    cd ..
    svn checkout svn://server/repo/mynewproject mynewproject_wc

svn import はプロジェクトの初期登録に使われることが一般的ですが、既存のワーキングコピー内で新しく大量のファイルやディレクトリを追加したい場合は、通常 svn add を使います。

6.2. 既存プロジェクトに新機能を追加する

既存のsvnプロジェクトに、新しいファイルやディレクトリを追加しながら機能開発を進めるのは最も一般的なシナリオです。

  1. 最新のリビジョンにワーキングコピーを更新します。
    bash
    svn update
  2. 新しい機能に必要なファイルやディレクトリを作成します。
    bash
    cd myproject/src/
    touch new_feature.c
    touch new_feature.h
    mkdir data
    echo "sample data" > data/sample.txt
  3. 作成した新しいファイルやディレクトリを svn add で追加予約します。ディレクトリごと追加すれば、中のファイルも同時に予約されます。
    bash
    svn add new_feature.c new_feature.h
    svn add data/
  4. svn status で追加予約されたことを確認します。
    bash
    svn status

    A src/new_feature.c
    A src/new_feature.h
    A src/data
    A src/data/sample.txt
  5. 必要に応じて、既存のファイルも修正します (svn add は不要)。
  6. svn diff で変更内容を確認します。
  7. 全ての変更(追加したファイル、編集したファイルなど)をコミットします。
    bash
    svn commit -m "Implement new feature and add related files/directory"

6.3. 誤って svn add してしまった場合のリカバリ

バージョン管理すべきでないファイル(例: 設定ファイル、ビルド生成物、個人用メモ)を誤って svn add してしまい、ステータスが A になってしまった場合。

  1. svn status で誤って A になっているファイルを確認します。
    bash
    svn status

    A my_personal_notes.txt # これを間違えて追加してしまった
    A build/output.log # これも間違えて追加してしまった
    M src/main.c
  2. これらのファイルの追加予約を svn revert で取り消します。
    bash
    svn revert my_personal_notes.txt build/output.log

    確認のプロンプトが表示される場合があります。y で確定します。
    Reverted 'my_personal_notes.txt'
    Reverted 'build/output.log'
  3. 再度 svn status で確認し、A から ? に戻っていることを確認します。
    bash
    svn status

    M src/main.c
    ? my_personal_notes.txt # ? に戻った
    ? build/output.log # ? に戻った

    これで、誤って追加予約したファイルがコミット対象から外されました。今後同様のミスを防ぐために、これらのファイルを無視するように svn:ignore プロパティを設定することを検討しましょう。

7. svn add と関連するコマンド

svn add は単独で使うだけでなく、他のsvnコマンドと組み合わせてバージョン管理ワークフローを構成します。ここでは、svn add と特に関連の深いコマンドを改めて整理します。

7.1. svn status

  • 役割: ワーキングコピーの状態を表示します。どのファイルが変更されたか (M)、追加予約されているか (A)、削除予約されているか (D)、競合しているか (C)、管理対象外か (?) などを一覧で確認できます。
  • svn add との関係: svn add コマンドの実行結果(ファイルが A ステータスになったこと)を確認するために必須のコマンドです。また、svn add すべきファイル(? ステータス)を見つけるためにも使います。

7.2. svn commit

  • 役割: ワーキングコピーで行われた変更(追加、編集、削除、移動など)をリポジトリに反映させ、新しいリビジョンを作成します。
  • svn add との関係: svn add で追加予約されたファイルは、svn commit を実行することで初めてリポジトリに登録されます。svn add はコミットのための準備であり、svn commit はその準備を完了させる最終ステップです。

7.3. svn revert

  • 役割: ワーキングコピーで行われたローカルな変更(ファイルの編集内容、追加予約、削除予約など)を取り消し、元の状態に戻します。
  • svn add との関係: 誤って svn add してしまったファイルの追加予約を取り消すために使用します。

7.4. svn delete

  • 役割: ファイルやディレクトリをバージョン管理下から削除するための予約をします。
  • svn add との関係: svn add が新規ファイルを管理下に入れるのに対し、svn delete は管理下のファイルを取り除く予約をします。どちらも svn commit で確定されます。ローカルでファイルを直接削除しただけでは、svnはそれを「管理下のファイルが見つからない」と認識し、! ステータスや D ステータスとして報告することがありますが、正式な削除予約は svn delete で行います。

7.5. svn copy / svn move

  • 役割: バージョン管理下にあるファイルやディレクトリをコピー (svn copy) または移動 (svn move) します。
  • svn add との関係: svn copysvn move コマンドは、内部的に「コピー元/移動元を削除予約」し、「コピー先/移動先を新しいファイルとして追加予約」するような操作を行います。これらのコマンドを使うことで、コピーや移動の履歴がsvnで正しく追跡されるようになります。ローカルでファイルシステム操作(cpmv)でコピー/移動した後で、元のファイルを svn delete し、新しいファイルを svn add するという手順でも同様の結果を得られますが、履歴を追跡する上では svn copysvn move を使うのが推奨されます。

7.6. svn info

  • 役割: ファイルやディレクトリに関する様々な情報を表示します(URL、リビジョン、作者、サイズなど)。
  • svn add との関係: svn add してまだコミットしていないファイルに対して svn info を実行すると、リポジトリ上の情報が存在しないため、表示される情報が限定されます(例えばリビジョンなどが表示されない)。これは、そのファイルがまだリポジトリに存在しない、ローカルな追加予約の状態であることを示唆します。

7.7. svn:ignore プロパティ

  • 役割: 特定のディレクトリ配下で、バージョン管理から除外したいファイルやディレクトリのパターンを指定します。
  • svn add との関係: svn:ignore を適切に設定しておくことで、svn status の表示がクリアになり、svn add * のような操作で誤って無視すべきファイルを追加してしまうリスクを減らせます。svn:ignore 自体はディレクトリのプロパティとして管理されるため、svn propset で設定し、その変更を svn commit でリポジトリに反映させる必要があります。

これらのコマンドを組み合わせることで、svnを使った効率的かつ安全なバージョン管理ワークフローが実現できます。

8. よくある疑問とトラブルシューティング

svn add を使う上で、初心者が遭遇しやすい疑問やトラブルについて解説します。

8.1. 「svn add したのにリポジトリに見えない、他の人が update しても取得できない」

  • 原因: svn add はローカルでの追加予約であり、リポジトリへの反映は行いません。リポジトリに反映させるには svn commit が必要です。
  • 解決策: svn status でファイルが A ステータスになっていることを確認した後、忘れずに svn commit -m "コミットメッセージ" を実行してください。コミットが成功すると、他の人が svn update でそのファイルを取得できるようになります。

8.2. 「追加しようとしたらエラーになった」

svn add 時にエラーになる原因はいくつか考えられます。

  • 「Entry ‘PATH’ is already under version control」: 指定したファイルまたはディレクトリは、すでにバージョン管理下にある(A, M, D などのステータスになっている)。既存のファイルを編集する場合は svn add は不要です。
  • 「Entry ‘PATH’ is not a working copy file」: 指定したパスがワーキングコピー内に存在しない、またはパスの指定が間違っている。現在のディレクトリやファイル名、パスを再度確認してください。
  • 親ディレクトリがバージョン管理下にない: svnでは、ファイルやサブディレクトリを追加する前に、その親ディレクトリがバージョン管理下にある必要があります。もし新しいディレクトリ構造を作成してファイルを追加した場合、ディレクトリごと svn add するか、先に親ディレクトリを svn add してから中のファイルを追加する必要があります。svn add newdir/newfile.txt と実行した場合、newdir/ がまだ管理下でなければエラーになることがあります。この場合は svn add newdir/ を実行してから svn add newdir/newfile.txt とするか、単に svn add newdir/ と実行して再帰的に追加するのが簡単です。
  • 権限がない: リポジトリに対してコミットする権限がない場合、svn add 自体はローカル操作なので成功しますが、その後の svn commit でエラーになります。しかし、クライアントの設定やリポジトリ側の設定によっては、svn add の段階で権限エラーに近いメッセージが出ることがないとは言えません。通常はコミット時の問題です。

8.3. 「ディレクトリを追加したら中のファイルも全部追加されてしまった」

  • 原因: svn add のデフォルトの挙動は再帰的 (--depth infinity) です。ディレクトリを指定して svn add すると、その中のファイルやサブディレクトリも全て追加予約されます。
  • 解決策:
    • ディレクトリだけを追加したい場合は、svn add --non-recursive directory/ または svn add -N directory/ を使用します。
    • 特定の深さまで追加したい場合は、--depth オプションを使用します。
    • もし既に再帰的に svn add してしまったが、一部のファイル/ディレクトリは追加したくなかった場合は、svn revert コマンドで不要なファイルの追加予約を取り消します。

8.4. 「特定のファイル(例: *.log)を追加しないようにしたい」

  • 原因: svn add コマンド自体にはパターンによる除外機能はありません。svn add * のようにワイルドカードを使用した場合、ワーキングコピー内の未管理ファイルが全て対象になる可能性があります。(クライアントの実装により svn:ignore を考慮する場合もあります)。
  • 解決策:
    • 最も推奨される方法は、対象のディレクトリに対して svn:ignore プロパティを設定することです。これにより、svn status で無視すべきファイルが表示されなくなり、svn add * のようなコマンドでも通常は追加されなくなります。
    • 既に svn add して A ステータスになってしまった場合は、svn revert で取り消します。
    • コミット時に特定のファイルを除外したい場合は、svn commit コマンドにコミットしたいファイルやディレクトリのパスを明示的に指定します(svn commit file1.c file2.h のように)。

8.5. 「svn add を大量に実行してしまった後で、一部だけ commit したい」

  • 原因: 複数のファイルやディレクトリを svn add した後、気が変わって一部だけを先にコミットしたくなった。
  • 解決策: svn commit コマンドは、引数としてコミットしたいファイルやディレクトリのパスを指定できます。パスを指定しなかった場合は、ワーキングコピー全体で行われた全ての変更(A, M, D ステータスなど)が対象となりますが、パスを指定すればそのパス配下の変更だけがコミットされます。
    “`bash
    # 全てコミットする場合
    svn commit -m “Commit all changes”

    特定のファイルだけコミットする場合

    svn commit -m “Commit only new_feature.c” src/new_feature.c

    特定のディレクトリ配下の変更だけコミットする場合

    svn commit -m “Commit changes in tests/” tests/
    ``
    コミットされなかったファイルやディレクトリは、引き続き
    AM` などのステータスのままワーキングコピーに残ります。

9. より高度な話題 (簡潔に)

svn add コマンド自体はシンプルですが、svnにはさらに多くの機能や概念があります。svn add に直接関連はしませんが、知っておくと役立つ可能性のある話題に簡単に触れておきます。

9.1. プロパティの追加 (svn propset)

svnでは、ファイルやディレクトリに対してメタデータとして「プロパティ」を設定できます。前述の svn:ignore もプロパティの一つです。他にも、svn:executable (実行権限)、svn:mime-type (MIMEタイプ)、svn:keywords (特定のキーワードを自動展開)、カスタムプロパティなどがあります。

これらのプロパティは、ファイルやディレクトリがバージョン管理下にあることに関連して設定されるため、svn add でファイルを追加予約した後や、コミット後に設定することがあります。プロパティの設定自体もワーキングコピーの変更として扱われるため、svn propset で設定後、svn commit でリポジトリに反映させる必要があります。

9.2. ロック (svn lock)

集中型であるsvnでは、排他制御のためにファイルのロック機能があります。あるファイルをロックすると、他のユーザーはそのファイルをコミットできなくなります。これは、バイナリファイルのようにマージが困難なファイルを複数人が同時に編集するのを防ぐのに役立ちます。

新しいファイルを追加する際には、svn add の時点ではロックは関係ありません。ファイルがリポジトリにコミットされ、バージョン管理下に置かれた後に、必要に応じて svn lock コマンドでロックします。ロックされたファイルは svn statusL ステータスとして表示されます。

9.3. フックスクリプト (Hook Scripts)

svnリポジトリでは、特定のアクション(コミットの前、コミットの後、リビジョンプロパティの変更など)が発生した際に自動的に実行されるスクリプトを設定できます。これらは「フックスクリプト」と呼ばれます。

例えば、pre-commit フックスクリプトは、コミットがリポジトリに受け付けられる前に実行され、コミットを拒否することができます。これにより、コミットメッセージのフォーマットをチェックしたり、コミットに含まれるファイルの内容を検証したり(例えば、デバッグコードが含まれていないかなど)、意図しないファイルが追加されていないか(例えば、svn:ignore されるべきファイルが svn add されていないか)をチェックするルールを設けることができます。

svn add 自体はローカルな操作なのでフックは実行されませんが、svn add されたファイルを含む svn commit が行われる際に、pre-commit フックがそのコミット内容全体を評価する可能性があります。

10. まとめ

この記事では、「今さら聞けない」と感じがちな svn add コマンドについて、その基本的な使い方から応用、関連コマンド、よくある疑問まで、詳細に解説しました。

svn add は、新しいファイルやディレクトリをSubversionのバージョン管理下に加えるための最初のステップです。これを実行することで、ローカルのワーキングコピー内で、そのファイルが「次回のコミットで追加される予定」という状態になります (A ステータス)。しかし、この時点ではまだリポジトリには何も反映されていません。リポジトリへの反映は、必ず svn commit コマンドで行う必要があります。

svn add のデフォルト動作はディレクトリに対して再帰的ですが、--non-recursive--depth オプションを使うことで、追加の深さを制御できます。また、バージョン管理すべきでないファイルが誤って追加されるのを防ぐためには、svn:ignore プロパティの適切な設定が非常に有効です。

もし誤って svn add してしまった場合は、慌てずに svn revert コマンドで追加予約を取り消すことができます。

svn addsvn status, svn commit, svn revert などの他の基本的なコマンドと密接に関連しており、これらのコマンドを理解し組み合わせて使うことで、svnでのバージョン管理ワークフローをスムーズに進めることができます。

この記事を通じて、あなたが svn add コマンドに自信を持って向き合えるようになり、svnでのファイル管理がより効率的に行えるようになることを願っています。バージョン管理は開発プロジェクトの基盤となる重要なスキルです。一歩ずつ着実に習得していきましょう。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール