SVN revertコマンド徹底解説 – 変更の取り消し方
バージョン管理システムは、ソフトウェア開発やドキュメント作成において不可欠なツールです。中でもSubversion(SVN)は、長きにわたり多くのプロジェクトで利用されてきました。バージョン管理システムの最大の利点は、変更履歴を追跡し、いつでも過去の状態に戻したり、特定の変更を取り消したりできる点にあります。
開発を進める中で、私たちは様々な変更をコードやドキュメントに加えます。しかし、時には行った変更が意図したものでなかったり、実験的な試みがうまくいかず、その変更を破棄して元の状態に戻したいと考えることがあります。このようなシチュエーションで活躍するのが、SVNの revert コマンドです。
本記事では、SVNの revert コマンドに焦点を当て、その基本的な使い方から詳細なオプション、適用できる変更の種類、使用上の注意点、そして関連する他のコマンドとの違いまで、徹底的に解説します。この記事を読むことで、svn revert コマンドを安全かつ効果的に活用し、日々の開発作業をよりスムーズに進められるようになることを目指します。
1. はじめに:SVNと変更を取り消す必要性
Subversion(SVN)は、集中型バージョン管理システム(Centralized Version Control System)として広く利用されています。リポジトリと呼ばれる中央サーバーに変更履歴が一元管理されており、各開発者はリポジトリから最新のファイルを「チェックアウト」して自身のコンピューター(ワーキングコピー)で作業を行います。作業中に行った変更は、最終的にリポジトリに「コミット」することで履歴として永続化され、他の開発者と共有されます。
開発プロセスは試行錯誤の連続です。新しい機能を実装したり、バグを修正したりする中で、様々な変更をコードに加えます。しかし、以下のような状況は決して珍しくありません。
- 実験的な変更がうまくいかなかった: 新しいアルゴリズムを試したが期待通りの結果が得られなかった、一時的にデバッグ用のコードを埋め込んだが不要になった、など。
- 間違ったファイルを編集してしまった: 意図しないファイルに誤って変更を加えてしまった。
- 設計変更や仕様変更があった: 開発途中で要件が変更され、それまでに行っていた作業の一部または全てが不要になった。
- コンフリクトを解消できない: 他の開発者の変更と自分の変更が衝突(コンフリクト)し、どのようにマージしても問題が解決しないため、一旦自分の変更を破棄してリポジトリの最新版に合わせたい。
- 単に不要な変更を破棄したい:
svn addしたばかりのファイルをやっぱりバージョン管理対象にしたくない、一時的に追加したデバッグ出力などを消したい、など。
これらの状況において、ワーキングコピー上の不要な変更を効率的かつ安全に取り消す手段が必要です。SVNにおいて、この目的のために設計されたコマンドが svn revert です。
svn revert コマンドは、ワーキングコピー上で行われた、まだリポジトリにコミットされていないローカルな変更を破棄し、そのファイルやディレクトリを最後にリポジトリから取得した状態(通常はBASEリビジョンまたはHEADリビジョンの状態)に戻す役割を果たします。
重要な点として、svn revert はあくまでワーキングコピー上の未コミットの変更に対して機能します。一度リポジトリにコミットされた変更を取り消す場合は、別の手順(通常は svn merge を使用した「リバートコミット」または手動での取り消しと再コミット)が必要になります。この違いは revert を理解する上で非常に重要です。
この記事では、まず svn revert の基本的な使い方から始め、どのような種類の変更を取り消せるのか、そして様々なオプションを使ってより柔軟に revert を実行する方法を解説します。その後、コマンドを使用する上での重要な注意点やベストプラクティス、さらには関連する他のSVNコマンドとの比較を通じて、svn revert コマンドの全体像を明らかにしていきます。
2. SVNの基本概念と revert の位置づけ
svn revert コマンドを正しく理解するためには、SVNの基本的な概念を改めて確認しておきましょう。
- リポジトリ (Repository): プロジェクトの全てのファイルとその変更履歴が一元的に管理されている場所です。通常、サーバー上に置かれます。
- ワーキングコピー (Working Copy): リポジトリから特定の時点(通常は最新)のファイル一式をチェックアウトしてきた、ローカルコンピューター上の作業領域です。開発者はこのワーキングコピーでファイルの編集、追加、削除などの作業を行います。
- リビジョン (Revision): リポジトリ全体のスナップショット(特定の時点の状態)を表す番号です。コミットが行われるたびに新しいリビジョンが生成され、リビジョン番号は増加します。
- BASE リビジョン: ワーキングコピー内のファイルが最後にリポジトリから更新またはチェックアウトされた時点のリビジョンです。各ファイルの
.svn/ディレクトリ内部に、このBASEリビジョンのコピーが保持されています。 - HEAD リビジョン: リポジトリの最新のリビジョンです。
開発者がワーキングコピーでファイルを編集したり、新しいファイルを追加したり、既存のファイルを削除したりすると、ワーキングコピーの状態はリポジトリのBASEリビジョンから「変更」された状態になります。これらの変更は、svn status コマンドで確認できます。
svn status コマンドの出力例:
$ svn status
M path/to/modified_file.txt
A path/to/added_file.c
D path/to/deleted_file.java
A + path/to/added_and_locked_file.dat
? path/to/unversioned_file.log
この例では、modified_file.txt は内容が変更され (M)、added_file.c は追加され (A)、deleted_file.java は削除対象とされ (D) ています。added_and_locked_file.dat は追加され (A) かつロックされています (+)。unversioned_file.log はバージョン管理下にない (?) ファイルです。
これらの「変更」(M, A, D, R (replaced), C (conflicted), !, ~ など)は、まだ svn commit されていません。svn revert コマンドは、まさにこの svn status コマンドで表示される種類の、ワーキングコピー上の未コミットの変更 を取り消すために使用されます。
svn revert が実行されると、SVNはワーキングコピー内の対象ファイルやディレクトリについて、ローカルで行われた変更を破棄し、内部に保持しているBASEリビジョンの状態に戻します。これにより、ワーキングコピーは最後にリポジトリから取得した状態と一致するようになります。
したがって、svn revert はローカルで行った作業をなかったことにするためのコマンドであり、リポジトリの履歴自体を変更するものではありません。リポジトリに変更を加えるのは svn commit コマンドの役割です。
3. svn revert コマンドの基本
svn revert コマンドの最も基本的な使い方は、引数に取り消したい変更を含むファイルまたはディレクトリのパスを指定することです。
3.1. 基本構文
bash
svn revert PATH [PATH...]
ここで PATH は、revertしたいファイルまたはディレクトリへのパスです。複数のパスを指定することも可能です。
3.2. ファイルの変更を取り消す例
最もよくあるケースは、ファイルを編集したが、その変更を破棄したい場合です。
-
まず、適当なファイルを作成し、
svn addしてコミットします。bash
$ echo "Initial content" > my_file.txt
$ svn add my_file.txt
A my_file.txt
$ svn commit -m "Add my_file.txt"
Adding my_file.txt
Transmitting file data ...
Committed revision 10. -
my_file.txtの内容を変更します。bash
$ echo "Modified content" >> my_file.txt -
svn statusで変更を確認します。bash
$ svn status
M my_file.txtMはファイルが変更されていることを示しています。 -
変更を破棄するために
svn revertコマンドを実行します。bash
$ svn revert my_file.txt
Reverted 'my_file.txt' -
再び
svn statusで確認すると、変更がなくなっていることがわかります。bash
$ svn status
$何も表示されないのは、ワーキングコピーに未コミットの変更がないことを意味します。
-
ファイルの内容を確認すると、コミットした時の状態に戻っていることがわかります。
bash
$ cat my_file.txt
Initial content
このように、ファイルを編集した後の svn revert filename は、そのファイルのローカルな変更を破棄し、最後にリポジトリから取得した状態に戻します。
3.3. 複数のファイルをまとめて取り消す
複数のファイルに変更を加えた場合、それらを一度にrevertすることも可能です。
bash
$ svn status
M file1.txt
M file2.c
A new_script.sh
これらの変更をまとめて取り消すには、それぞれのパスを引数に指定します。
bash
$ svn revert file1.txt file2.c new_script.sh
Reverted 'file1.txt'
Reverted 'file2.c'
Reverted 'new_script.sh'
または、対象となるファイルが全て同じディレクトリにある場合は、ディレクトリを指定することもできます(ただしデフォルトでは再帰的ではないので注意が必要です。後述のオプション -R がよく使われます)。
3.4. ディレクトリを指定して取り消す
ディレクトリを revert の対象として指定した場合、そのディレクトリ自体(プロパティの変更など)およびデフォルトではその直下のファイルとサブディレクトリ(のプロパティや追加/削除など)の変更が取り消されます。ただし、デフォルトではサブディレクトリ内のファイル内容はrevertされません。通常、ディレクトリ内の全ての未コミットの変更を取り消したい場合は、再帰オプション -R を付けて実行します。
bash
$ svn status
M my_dir/file_in_dir.txt
A my_dir/new_file_in_dir.c
ディレクトリ my_dir 全体の変更(およびその中のファイル)を取り消したい場合:
“`bash
-R オプションなし(デフォルト)
$ svn revert my_dir
Reverted ‘my_dir’ # ディレクトリ自体のプロパティ変更などがrevertされる
“`
この -R なしのrevertでは、my_dir/file_in_dir.txt や my_dir/new_file_in_dir.c の変更は取り消されません。
ディレクトリ内の全ての未コミットの変更(サブディレクトリやその中のファイルも含めて)を取り消すには、-R オプションを使用します。
“`bash
-R オプションあり
$ svn revert -R my_dir
Reverted ‘my_dir’
Reverted ‘my_dir/file_in_dir.txt’
Reverted ‘my_dir/new_file_in_dir.c’
“`
ワーキングコピー全体の未コミットの変更を全て取り消したい場合は、ワーキングコピーのルートディレクトリで以下のコマンドを実行します。
bash
$ svn revert -R .
これは非常に強力なコマンドであり、ワーキングコピー上の全ての未コミットの変更を完全に破棄します。実行前には必ず svn status で変更内容を確認し、本当に全て破棄して良いか慎重に判断する必要があります。
3.5. svn add しただけのファイルを取り消す
svn add コマンドは、ファイルをバージョン管理下に置く予定であることをSVNに知らせますが、実際のリポジトリへの追加はコミット時に行われます。svn add したものの、まだコミットしていないファイルをバージョン管理下に置くのをやめたい場合も、svn revert を使用します。
-
ファイルを新規作成し、
svn addします。bash
$ echo "Temporary file" > temp.txt
$ svn add temp.txt
A temp.txt -
svn statusで確認します。bash
$ svn status
A temp.txtAは追加予定であることを示します。 -
追加を取り消します。
bash
$ svn revert temp.txt
Reverted 'temp.txt' -
svn statusで確認すると、temp.txtがバージョン管理対象ではなくなったことがわかります。bash
$ svn status
? temp.txt?はバージョン管理下にないファイルであることを示します。svn revertはsvn addの効果を取り消しただけであり、ファイル自体はワーキングコピーに残ります。ファイルを物理的に削除したい場合は、別途rmなどのOSコマンドを使用する必要があります。
3.6. svn delete しただけのファイルを取り消す
svn delete コマンドは、ファイルをリポジトリから削除する予定であることをSVNに知らせますが、実際のリポジトリからの削除はコミット時に行われます。svn delete したものの、まだコミットしていないファイルを削除対象とするのをやめたい場合も、svn revert を使用します。
-
既存のバージョン管理下にあるファイルを用意します。
bash
$ svn status my_file.txt
$ cat my_file.txt
Initial content -
ファイルを
svn deleteします。bash
$ svn delete my_file.txt
D my_file.txt -
svn statusで確認します。bash
$ svn status
D my_file.txtDは削除予定であることを示します。ファイルはワーキングコピーから物理的に削除されています。 -
削除を取り消します。
bash
$ svn revert my_file.txt
Reverted 'my_file.txt' -
svn statusで確認すると、削除が取り消され、ファイルが復活していることがわかります。bash
$ svn status
$ファイルの内容も、
svn deleteする直前の状態(つまり最後にコミットされた状態)に戻っています。bash
$ cat my_file.txt
Initial content
このように、svn revert は svn delete の効果も取り消し、ファイルを復活させることができます。
3.7. svn move / svn rename したファイルを取り消す
svn move または svn rename コマンドは、ファイルをバージョン管理下で移動または名前変更するもので、内部的には svn copy と svn delete の組み合わせとして扱われます。これもコミット前の変更として revert の対象となります。
-
既存のファイルを
svn moveまたはsvn renameします。bash
$ svn status my_file.txt
$ svn move my_file.txt new_file.txt
A new_file.txt
D my_file.txt -
svn statusで確認します。bash
$ svn status
A new_file.txt
D my_file.txt元のファイルが削除予定 (
D)、新しい名前のファイルが追加予定 (A) と表示されます。 -
名前変更を取り消します。revertの対象パスとしては、古いパスまたは新しいパスのどちらかを指定できますが、通常は古いパスを指定するのが直感的です。
bash
$ svn revert my_file.txt
Reverted 'my_file.txt'または
bash
$ svn revert new_file.txt
Reverted 'new_file.txt'どちらを指定しても、SVNは名前変更の操作全体を取り消します。
-
svn statusで確認します。bash
$ svn status
$元のファイル名
my_file.txtでファイルが復活しています。
このように、svn revert はファイルの名前変更や移動操作も取り消すことができます。
3.8. プロパティの変更を取り消す
SVNでは、ファイルやディレクトリに対してバージョン管理されるプロパティ(例えば svn:ignore、svn:keywords、svn:mime-type など)を設定できます。これらのプロパティに対する変更も、コミット前であれば svn revert で取り消すことが可能です。
-
ファイルのプロパティを変更します。
bash
$ svn propset svn:keywords "Author Date Id" my_file.txt
property 'svn:keywords' set on 'my_file.txt' -
svn statusで確認します。bash
$ svn status
M my_file.txtファイル自体は変更していなくても、プロパティが変更されていると
Mマークが表示されることがあります(またはC列にPが表示されるなど)。正確にはsvn status --show-item=props my_file.txtで確認できます。bash
$ svn status --show-item=props my_file.txt
PPはプロパティが変更されていることを示します。 -
プロパティの変更を取り消します。
bash
$ svn revert my_file.txt
Reverted 'my_file.txt' -
svn statusで確認すると、プロパティの変更がなくなっていることがわかります。bash
$ svn status --show-item=props my_file.txt
$ファイル内容の変更とプロパティの変更が両方ある場合、
svn revertは両方とも取り消します。ファイル内容だけ、またはプロパティだけを選択的にrevertしたい場合は、一旦svn diffなどで変更を抽出し、手動で適用し直すなどの工夫が必要になる場合があります。しかし、通常はファイルやディレクトリを指定してrevertすれば、そのパスに対する全てのローカルな変更(内容、プロパティ、追加/削除ステータスなど)が取り消されます。
4. svn revert の主要なオプション
svn revert コマンドには、より柔軟な操作を可能にするためのいくつかのオプションがあります。
4.1. -R (–recursive)
前述のように、ディレクトリに対して svn revert を実行した場合、デフォルトではそのディレクトリ自体と直下のアイテムのプロパティ変更などが対象となりますが、サブディレクトリ内のファイル内容の変更などはrevertされません。-R または --recursive オプションを付けることで、指定したディレクトリ以下の全ての未コミットの変更を再帰的にrevertできます。
bash
$ svn revert -R my_directory
これはワーキングコピー全体の変更を取り消す際によく使われます。
bash
$ svn revert -R . # 現在のディレクトリ以下の全ての変更を取り消す
4.2. --depth ARG
--depth オプションを使用すると、revert操作の再帰の深さを制御できます。これは -R オプションのより詳細な制御版と考えることができます。ARG には以下のいずれかの値を指定します。
empty: 指定したパス自体のみを対象とし、その中のアイテムは含めません。files: 指定したパス自体とその直下のファイルのみを対象とします。サブディレクトリは含めません。immediates: 指定したパス自体とその直下のアイテム(ファイルとディレクトリ)のみを対象とします。サブディレクトリの中は含めません。infinity: 指定したパス以下全てのアイテムを対象とします(-Rと同じ挙動です)。
例:my_directory の直下のファイルのみをrevertしたい場合。
bash
$ svn revert --depth files my_directory
これは、my_directory/file1.txt や my_directory/file2.c はrevertしますが、my_directory/subdirectory/another_file.txt の変更はrevertしません。
特定のディレクトリ内の変更は残したいが、それ以外の変更はrevertしたい、といった複雑な状況では、対象から除外したいディレクトリに対して --depth empty を指定してから、親ディレクトリに対して -R を実行するなど、複数のコマンドを組み合わせる必要があるかもしれません。しかし、一般的には -R (--depth infinity) か、特定のファイルパスを指定する方法がほとんどです。
4.3. --targets FILENAME
revertしたいファイルが多数あり、それらをコマンドライン引数として全て指定するのが大変な場合、対象ファイルのリストをファイルに記述し、--targets オプションでそのファイルを指定することができます。リストファイルでは、1行につき1つのファイルまたはディレクトリパスを記述します。
-
revertしたいファイルのリストを作成します。
bash
$ cat revert_list.txt
path/to/file1.txt
path/to/directory_a
path/to/file2.c -
--targetsオプションを使ってrevertを実行します。bash
$ svn revert --targets revert_list.txt
Reverted 'path/to/file1.txt'
Reverted 'path/to/directory_a' # ディレクトリなので -R なしなら直下のみ
Reverted 'path/to/file2.c'
--targets オプションを使用した場合でも、ディレクトリパスがリストに含まれていれば、デフォルトの再帰深度が適用されます。リスト内のディレクトリパスに対しても再帰的にrevertしたい場合は、-R オプションを併用します。
bash
$ svn revert -R --targets revert_list.txt
Reverted 'path/to/file1.txt'
Reverted 'path/to/directory_a'
Reverted 'path/to/directory_a/file_in_subdir.java'
Reverted 'path/to/file2.c'
このオプションは、大量のファイルをスクリプトで処理する場合などに非常に便利です。
4.4. --changelist CHGLIST_NAME
SVNでは、svn changelist コマンドを使って、関連する未コミットの変更(ファイルやディレクトリ)をグループ化し、「チェンジリスト」として管理できます。--changelist オプションを使用すると、特定のチェンジリストに含まれるアイテムのみをrevertすることができます。
-
いくつかのファイルをチェンジリストに追加します。
bash
$ svn status
M file_a.txt
M file_b.c
M file_c.hbash
$ svn changelist my-feature file_a.txt file_c.h
Path 'file_a.txt' is now a member of changelist 'my-feature'.
Path 'file_c.h' is now a member of changelist 'my-feature'.“`bash
$ svn status
— Changelist ‘my-feature’:
M file_a.txt
M file_c.h
M file_b.c
“` -
チェンジリスト
my-featureに含まれる変更のみをrevertします。bash
$ svn revert --changelist my-feature . # '.' は現在のディレクトリ以下の全てのチェンジリスト対象を探す
Reverted 'file_a.txt'
Reverted 'file_c.h' -
svn statusで確認します。bash
$ svn status
M file_b.cfile_b.cの変更はそのまま残り、チェンジリストに含まれていたfile_a.txtとfile_c.hの変更のみがrevertされました。
このオプションは、複数の独立した作業を同時に行っているワーキングコピーで、特定の作業に関連する変更だけを破棄したい場合に役立ちます。
4.5. --quiet (-q)
通常、svn revert を実行すると、revertされたファイルやディレクトリのパスが1行ずつ表示されます。--quiet オプションを付けると、成功メッセージやrevertされたパスの表示が抑制されます。
bash
$ svn revert -q my_file.txt
$ # 何も出力されない
スクリプト内で svn revert を実行する際など、余分な出力を避けたい場合に便利です。エラーが発生した場合は通常通り表示されます。
4.6. --verbose (-v)
--verbose オプションは、成功メッセージをより詳細に表示します。あまり頻繁には使用されませんが、revert操作が期待通りに行われたかを確認したい場合に役立つことがあります。ただし、revertされたパスのリスト表示自体はデフォルトの挙動で行われるため、-q の逆というよりは、より詳細な情報(例えばプロパティ変更のrevertなども明示するなど)を提供することを意図している場合がありますが、現在のSVNの挙動ではデフォルト出力と大きな違いがないことが多いです。
4.7. --force
--force オプションは、通常revertできない状況(例えば、ファイルがローカルでロックされている場合など)でもrevertを強制的に実行しようとします。
注意: --force オプションは慎重に使用する必要があります。特に、ファイルがローカルプロセスによって使用中であったり、SVNの内部状態とワーキングコピーの状態が不整合を起こしているような場合に強制すると、ワーキングコピーの状態をさらに不安定にする可能性があります。通常は --force なしでrevertが成功しない理由を確認し、適切に対処する(例えば、プロセスを終了する、svn cleanup を実行するなど)方が安全です。
5. svn revert が取り消せる変更の種類
すでに基本的な使い方の中で触れましたが、svn revert が取り消せる未コミットの変更の種類を改めて整理し、svn status の出力と関連付けて確認しましょう。
svn status の出力の最初の列は、ファイルやディレクトリの現在の状態を示します。svn revert は、以下の状態にあるアイテムのローカルな変更を取り消すことができます。
M: Modified (変更) – ファイルの内容が変更されている、またはプロパティが変更されている状態。revertすると、ファイル内容およびプロパティはBASEリビジョンの状態に戻ります。A: Added (追加) –svn addコマンドでバージョン管理対象に追加されたが、まだコミットされていないファイルまたはディレクトリ。revertすると、追加のマークが取り消され、アイテムはバージョン管理下のファイル (?) または単なるディレクトリ (?) に戻ります。ファイル自体は物理的に残ります。D: Deleted (削除) –svn deleteコマンドで削除対象とされたが、まだコミットされていないファイルまたはディレクトリ。revertすると、削除のマークが取り消され、アイテムはワーキングコピーに復活し、BASEリビジョンの状態に戻ります。R: Replaced (置換) – ファイルがsvn deleteされ、同じパスに新しいファイルがsvn addされた状態(例えば、svn moveの結果など)。revertすると、削除と追加の両方の操作が取り消され、元のファイルがBASEリビジョンの状態で復活します。C: Conflicted (競合) –svn updateやsvn mergeの際に、ローカルの変更とリポジトリからの変更が衝突し、手動でのマージが必要な状態。revertすると、ローカルの変更が破棄され、コンフリクトが解消されます。ファイルの内容はリポジトリのバージョン(通常はBASEリビジョンまたは更新/マージ元リビジョン)に戻ります。コンフリクトマーカー (<<<<<<<など) も削除されます。!: Missing (欠落) – ワーキングコピーからファイルが物理的に削除されたにも関わらず、SVNに対してsvn deleteコマンドが実行されていない状態。このようなアイテムは通常、svn cleanupで解決されるべきですが、svn revertの対象となることもあります。しかし、通常はsvn cleanupの方が適切です。~: Obstructed (妨害) – バージョン管理下のファイル/ディレクトリと同じパスに、異なる種類のアイテム(例えば、バージョン管理下でファイルだった場所にディレクトリがある、またはその逆)が存在する状態。これも通常は手動での修正やsvn cleanupが必要です。
一方、svn revert の対象とならない(または直接的に解決しない)主な状態は以下の通りです。
?: Unversioned (バージョン管理対象外) –svn addされておらず、SVNが認識していないファイルやディレクトリ。これらはSVNの管理下にないため、svn revertコマンドで操作することはできません。物理的に削除するにはOSのコマンド (rmなど) を使用します。I: Ignored (無視) –svn:ignoreプロパティやグローバル無視設定によって無視されるように設定されているファイルやディレクトリ。これらもバージョン管理下にないため、svn revertの対象外です。X: External (外部定義) –svn:externalsプロパティでリンクされている外部リポジトリまたはその中のパス。外部定義自体のプロパティ変更はrevertの対象になりえますが、外部定義によってチェックアウトされたワーキングコピー内の変更は、その外部ワーキングコピー内で別途svn revertする必要があります。L: Locked (ロック済み) –svn lockコマンドで排他ロックがかけられているファイルやディレクトリ。revertコマンド自体はロックを解除しません。ロックを解除するにはsvn unlockコマンドを使用する必要があります。ただし、ロックされたファイルのローカルな変更はrevertで取り消すことができます。
コンフリクト時の revert
コンフリクト (C) は、svn revert が特に有効なシチュエーションの一つです。svn update や svn merge でコンフリクトが発生した場合、通常はコンフリクトマーカーが挿入されたファイルを編集して手動で解消します。しかし、ローカルの変更が不要であったり、マージが複雑すぎてすぐに解決できない場合など、一旦ローカルの変更を完全に破棄してリポジトリのバージョンに合わせたいことがあります。
bash
$ svn status
C conflicted_file.txt
このコンフリクトをローカルの変更を捨てて解消する場合、svn revert コマンドが使えます。
bash
$ svn revert conflicted_file.txt
Reverted 'conflicted_file.txt'
これにより、conflicted_file.txt の内容はコンフリクト発生元のリポジトリのバージョンに戻り、コンフリクトマーカーも削除されます。svn status を実行すると、conflicted_file.txt のステータスが消えているはずです。
コンフリクト解消には svn resolve コマンドも使われますが、svn resolve --accept BASE はローカルの変更を破棄してBASEリビジョンを受け入れるという点で svn revert と似た効果を持ちます(ただし、revert はコンフリクトのステータス自体も解除しますが、resolve はコンフリクト解消済みというマークを付けるだけで、ファイルの内容自体は --accept オプションで指定した通りになります)。多くの場合、コンフリクトしているファイルのローカルの変更を完全に破棄したいのであれば、svn revert が最も手っ取り早い方法です。
6. svn revert を使うべきシチュエーション
これまでの説明を踏まえ、具体的にどのような状況で svn revert コマンドを使用するのが適切かを見てみましょう。
- 不用意に行った、または不要になった変更の破棄:
- ファイルを編集し始めたが、やはりこの方法は良くないと思い直した。
- 一時的なデバッグログ出力やテスト用のコードを書き加えたが、コミットする前に削除したい。
- 機能を実装しようとしたが、途中で別の方法に切り替えることになり、それまでの変更が不要になった。
- 実験的なブランチでの作業結果の破棄:
- 新しいアイデアを試すために一時的なブランチ(または単に既存ブランチのワーキングコピー)で作業していたが、その試みがうまくいかず、全ての変更を捨ててクリーンな状態に戻したい。
- 間違って変更してしまったファイルの修正:
- 開くべきファイルとは別のファイルを開いてしまい、誤って内容を変更してしまった。
svn add/svn delete/svn moveを取り消したい:- 誤って不要なファイルを
svn addしてしまった。 - 誤って必要なファイルを
svn deleteしてしまった。 - ファイルの移動や名前変更を行ったが、元に戻したい。
- 誤って不要なファイルを
- 大量の未コミット変更を一括で破棄したい:
- ワーキングコピーがごちゃごちゃになり、何を変更したか分からなくなった。一旦全ての変更を捨てて、リポジトリの最新状態からやり直したい。
svn statusが大量のファイルを表示しており、これらを全て破棄したい。
- コンフリクト解消の方針としてローカル変更の破棄を選択する:
svn updateやsvn mergeでコンフリクトが発生したが、自分のローカルの変更を保持するよりも、リポジトリのバージョンをそのまま受け入れたい。
- SVNのコマンド操作を間違えた:
- 例えば
svn propsetで間違った値を設定してしまった、など。
- 例えば
これらのシチュエーションでは、svn revert が問題解決の強力な手段となります。しかし、その強力さゆえに、誤った使い方をすると意図しないデータの損失を招く可能性があることを理解しておく必要があります。
7. svn revert を使う上での注意点とベストプラクティス
svn revert コマンドは非常に便利ですが、ワーキングコピー上の未コミットの変更を永久に破棄するという性質から、使用には十分な注意が必要です。一度revertした変更は、基本的に元に戻すことができません。
7.1. revert はローカル変更を永久に破棄する
最も重要な注意点は、svn revert が実行されると、対象のファイルやディレクトリに対するワーキングコピー上の未コミットの変更が失われるということです。これらの変更はSVNの履歴にはまだ記録されていません。そのため、revertする前にこれらの変更のコピーをどこかに保存しておかない限り、後からその変更を取り戻すことは非常に困難です。
7.2. 実行前に必ず svn status で確認する
svn revert を実行する前には、必ず svn status コマンドを実行し、現在ワーキングコピーにどのような変更があるか、そしてrevertしようとしているパスが意図したものであるかを確認してください。特にディレクトリ全体やワーキングコピー全体をrevertする場合は、この確認は必須です。
“`bash
$ svn status
出力内容を慎重に確認する
$ svn revert path/to/some_file.txt # 確認したファイルだけrevert
“`
あるいは、ワーキングコピー全体をrevertする場合は、対象が全て正しいか確認します。
bash
$ svn status # 全ての変更を確認
$ svn revert -R . # 全て破棄して良いか最終確認してから実行
7.3. 可能であればバックアップを取る
非常に重要で複雑な変更を破棄するか迷っている場合や、万が一に備えたい場合は、revert対象のファイルやディレクトリを一時的に別の場所にコピーするなどしてバックアップを取っておくことを検討してください。これにより、revert後にやはりあの変更が必要だったという事態になっても、バックアップから復元することができます。
7.4. 対象パスを正確に指定する
特定のファイルやディレクトリの変更のみをrevertしたい場合は、対象パスを正確に指定してください。ワイルドカード(* など)の使用は、意図しないファイルまでrevertしてしまう可能性があるため、慎重に行うか避ける方が安全です。特にシェルによってはワイルドカードが展開されてからSVNに渡されるため、予想外の挙動をすることがあります。
7.5. ディレクトリの再帰revert (-R .) は最終手段と考える
ワーキングコピーのルートディレクトリで svn revert -R . を実行することは、ワーキングコピー全体の全ての未コミット変更を破棄する非常に強力な操作です。これは「まっさらな状態からやり直したい」という場合に有効ですが、少しでも残しておきたい変更がある場合は絶対に行わないでください。この操作は、文字通り、そのワーキングコピーで行ってきた全てのローカルな作業をなかったことにします。
7.6. コミット済みの変更は revert できないことを理解する
繰り返しになりますが、svn revert は未コミットのローカルな変更のみを取り消します。一度 svn commit でリポジトリにプッシュされた変更は、svn revert では取り消せません。コミット済みの変更を取り消すには、その変更を取り消すための新しい変更(例えば、問題のコミットで導入されたコードを削除する、または svn merge -c -r RevA:RevB path を使ってリバートコミットを作成するなど)をワーキングコピーで行い、それを新たにコミットする必要があります。
7.7. コンフリクト解消における revert の活用
コンフリクトが発生した際に、ローカルの変更を破棄してリポジトリのバージョンを採用するという方針を採る場合、svn revert は非常に有効な手段です。コンフリクトしているファイルを revert することで、コンフリクトマーカーも同時に削除され、ファイルはリポジトリのバージョンに戻ります。これは手動マージよりも簡単ですが、もちろんローカルの変更は失われます。
7.8. svn cleanup が必要な場合
SVNの操作中に中断されたり、何らかのエラーが発生したりすると、ワーキングコピーがロックされた状態になることがあります。この状態で svn revert を含む多くのSVNコマンドを実行しようとすると、「ワーキングコピーがロックされています」といったエラーメッセージが表示されることがあります。このような場合は、まず svn cleanup コマンドを実行してワーキングコピーのロックを解除する必要があります。
bash
$ svn cleanup [PATH]
通常はワーキングコピーのルートディレクトリで実行すれば十分です。cleanup 完了後に改めて svn revert を試みてください。
8. 関連コマンドとの比較
svn revert と似たような効果を持つように見える、あるいは関連して使われる他のSVNコマンドとの違いを明確にしておきましょう。
8.1. svn status
- 役割: ワーキングコピー上の未コミットの変更やバージョン管理下の状態を確認する。
revertとの関係:revertを実行する前に、どのような変更があるかを確認するために必須のコマンドです。revert実行後にも、変更が意図通りに取り消されたかを確認するために使用します。
8.2. svn diff
- 役割: ワーキングコピー上の変更内容を、BASEリビジョンや他のリビジョンと比較して詳細に表示する。
revertとの関係:revertする前に、破棄しようとしている変更が具体的にどのような内容かを確認するために使用します。これにより、誤って重要な変更を破棄するリスクを減らせます。
8.3. svn update
- 役割: リポジトリから最新の変更や指定したリビジョンの変更を取得し、ワーキングコピーに適用する。
revertとの違い:revertはローカルの未コミット変更を破棄し、ワーキングコピーをBASEリビジョン(またはチェックアウト/アップデート時の状態)に戻します。リポジトリとの通信は通常必要ありません。updateはリポジトリから変更を取得し、ローカルのワーキングコピーに適用します。ネットワーク通信が必要です。svn update -r HEADはリポジトリの最新状態をワーキングコピーに反映しますが、ローカルの未コミット変更は可能な限り維持しようとします(コンフリクトが発生する場合もあります)。svn update -r BASEはリポジトリのBASEリビジョンの状態をワーキングコピーに反映しますが、ローカルの未コミット変更がある場合は、その変更がリポジトリのBASE状態に「パッチ」として適用されるような挙動になり、結果が複雑になることがあります。純粋にローカルの変更を破棄して最後に取得したリポジトリの状態に戻したい場合は、svn revertの方が意図が明確で安全です。
8.4. svn checkout / svn export
- 役割: リポジトリから新しいワーキングコピー (
checkout) またはバージョン管理情報を含まないクリーンなコピー (export) を取得する。 revertとの違い:revertは既存のワーキングコピー内の変更を修正します。checkout/exportは、全く新しい(またはクリーンな)コピーを最初から作成します。- ワーキングコピー全体の全ての変更を破棄する究極の方法として、既存のワーキングコピーを削除し、改めて
svn checkoutし直すという手もあります。これはsvn revert -R .と似た効果を持ちますが、.svnディレクトリを作り直すという点でより確実なクリーンアップになることがあります。ただし、時間とディスク容量がかかります。
8.5. コミット済み変更を取り消すコマンド (例: svn merge -c -r OldRev:NewRev path)
- 役割: リポジトリに既にコミットされた変更を「取り消す」ための新しいコミットを作成する。
revertとの違い:revertは未コミットのローカル変更を取り消す。svn merge -c -r ...などはコミット済みの変更を取り消すための操作を行う。具体的には、指定したリビジョンで導入された変更内容と逆の変更内容をワーキングコピーに適用し、それを新しいリビジョンとしてコミットします。これにより、リポジトリの履歴上で特定の変更が「打ち消される」ことになります。
これらのコマンドはそれぞれ異なる目的を持っています。svn revert はあくまで「ワーキングコピーの未コミット変更を破棄する」ためのコマンドであるということをしっかり理解しておくことが重要です。
9. 高度なトピック
9.1. svn status の各ステータスと revert の挙動
svn status の出力は、revert がどのように作用するかを理解する上で非常に役立ちます。
svn status ステータス |
状態の説明 | svn revert 後の状態 |
備考 |
|---|---|---|---|
M (content) |
ファイルの内容が変更されている | BASEリビジョンの内容に戻る | .svn/text-base に保存されている元の内容で上書きされる。 |
M (props) |
ファイル/ディレクトリのプロパティが変更されている | BASEリビジョンのプロパティに戻る | プロパティの変更も取り消される。 |
A |
svn add されたが未コミットのファイル/ディレクトリ |
? (Unversioned) 状態に戻る。 |
アイテム自体はワーキングコピーに残る。 |
D |
svn delete されたが未コミットのファイル/ディレクトリ |
アイテムがワーキングコピーに復活し、BASEリビジョンの状態に戻る。svn status の表示から消える。 |
削除されたファイルの内容も復活する。 |
R |
svn delete 後に同名で svn add (置き換え/移動/名前変更の結果) |
元のファイル名/パスでアイテムが復活し、BASEリビジョンの状態に戻る。svn status の表示から消える。 |
移動元パスまたは移動先パスを指定してrevertできる。 |
C |
コンフリクトが発生している | ローカルの変更が破棄され、コンフリクトが解消される。ファイルはリポジトリのバージョンに戻る。svn status の表示から消える。 |
コンフリクトマーカーも削除される。 |
! |
バージョン管理下だが、ワーキングコピーに存在しない (Missing) |
通常 svn cleanup で解決されるべき状態。revert で解決できることもあるが、推奨されない。 |
|
~ |
バージョン管理下だが、ワーキングコピーに異なる種類のアイテムがある (Obstructed) |
通常 svn cleanup または手動での修正で解決されるべき状態。revert で解決できることもあるが、推奨されない。 |
|
? |
バージョン管理対象外 (Unversioned) |
revert の対象外。 |
OSのコマンドで削除する必要がある。 |
I |
無視対象 (Ignored) |
revert の対象外。 |
|
X |
外部定義 (External) |
外部定義パス自体のプロパティ変更などはrevert対象になりうるが、外部定義でチェックアウトされたワーキングコピー内の変更はrevertしない(別途その中で行う)。 |
9.2. Sparse Working Copies における revert
Sparse working copies は、リポジトリ全体ではなく、その一部のみをチェックアウトしたワーキングコピーです。特定のディレクトリやファイルのみを取得し、他の部分はチェックアウトしない、あるいは取得しても中身は取得しない (--depth empty などで) といった設定が可能です。
Sparse working copies で svn revert -R . のように再帰的なrevertを実行した場合、revertされるのはワーキングコピーに実際に存在するアイテムのみです。チェックアウトされていない(例えば --depth empty で取得されているディレクトリ内のアイテムなど)はrevertの対象になりません。revertはワーキングコピーのローカルな状態を変更するコマンドなので、ローカルに存在しないものは操作できないためです。
また、sparse working copies で svn update --set-depth infinity directory_a のようにして後から特定のディレクトリを完全に取得するように設定を変更した場合、そのディレクトリ内のアイテムはローカル変更がない状態(または既存のローカル変更とマージされた状態)で追加されます。この後でそのディレクトリをrevertすると、その時点でのBASEリビジョンに戻ります。
10. よくある質問 (FAQ)
Q: svn revert で誤って変更を取り消してしまいました!元に戻せますか?
A: 残念ながら、svn revert で破棄された未コミットのローカル変更は、特別な対策(revert前に手動でコピーを保存しておく、ワーキングコピーのファイルシステムの過去の状態を復元できるような高度なシステムを利用するなど)をしていない限り、基本的に元に戻すことはできません。svn revert はローカルのワーキングコピーの状態を変更するコマンドであり、リポジトリに履歴として残っていない変更を扱うためです。これが、svn revert を使う前に svn status や svn diff で変更内容を確認し、必要であればバックアップを取っておくことが強く推奨される理由です。
Q: 特定の変更だけを選択的にrevertしたい場合はどうすればいいですか?
A:
* ファイル単位/ディレクトリ単位でrevert: svn revert path/to/file.txt や svn revert -R path/to/directory のように、パスを指定してrevertします。これは最も一般的な方法です。
* ファイル内の変更の一部だけrevert: svn revert はファイル全体をBASEリビジョンの状態に戻します。ファイル内の特定の変更ラインだけを取り消したい場合は、svn diff コマンドで現在の変更内容を確認し、その差分の中から必要な部分だけを手動でファイルに適用し直し、不要な部分を削除する必要があります。または、svn diff の出力を一時ファイルに保存し、そこから必要な部分を切り貼りするという方法も考えられます。これは手作業になるため、変更量が多い場合は手間がかかります。
* 特定のチェンジリストの変更だけrevert: 複数の作業をチェンジリストで管理している場合は、svn revert --changelist my-changelist . のようにオプション --changelist を使うことができます。
Q: ディレクトリ全体をrevertしたら、svn add したファイルも消えますか?
A: はい、-R オプション付きでディレクトリをrevertした場合、そのディレクトリ内(サブディレクトリも含む)で svn add されていたファイルやディレクトリは、追加のマークが取り消され、バージョン管理対象外 (? ステータス) に戻ります。物理的なファイル自体はワーキングコピーに残りますが、SVNからは未管理ファイルとして扱われるようになります。完全に削除したい場合は、別途OSのコマンド (rm など) を実行する必要があります。
Q: コンフリクトしているファイルをrevertしたらどうなりますか?
A: コンフリクトしているファイルに対して svn revert を実行すると、ローカルの変更が破棄され、ファイルの内容はコンフリクト発生元のリポジトリのバージョンに戻ります。コンフリクトマーカー (<<<<<<< など) も削除されます。ファイルはコンフリクトしていない状態になり、svn status から C ステータスが消えます。これはコンフリクトを手動で解消する代わりに、リポジトリのバージョンを採用するという解決策を実行したことになります。
Q: svn revert と svn update -r BASE の違いは何ですか?
A:
* svn revert: ワーキングコピー上のローカルな未コミット変更を破棄し、そのアイテムを最後にリポジトリから取得した時点(通常はBASEリビジョン)の状態に戻します。主にローカルの作業を「取り消す」ために使われます。ネットワーク接続は通常不要です。
* svn update -r BASE: リポジトリのBASEリビジョンの状態をワーキングコピーに取得し、適用します。もしワーキングコピーに未コミットの変更がある場合、その変更はリポジトリのBASE状態に「マージ」されるような挙動になります。結果としてローカル変更が保持されるかコンフリクトするかなど、挙動が少し複雑になることがあります。リポジトリとのネットワーク接続が必要です。
純粋にローカルの未コミット変更だけを破棄したい場合は、svn revert を使うのが最も意図が明確で安全です。svn update -r BASE は、例えばワーキングコピー全体を特定の過去のリビジョン(この場合はBASE)の状態にリポジトリから更新したい場合に使うべきです。
Q: svn revert で「svn: E155010: The node… was not found」のようなエラーが出ます。
A: このエラーは通常、ワーキングコピーのメタデータ(.svn ディレクトリ内の情報)と実際のファイルシステムの状態との間に不整合がある場合に発生します。例えば、SVNコマンドを使わずにファイルを移動したり削除したりした場合に起こり得ます。このような不整合を解消するには、まず svn cleanup コマンドを実行してみてください。cleanup がワーキングコピーを修復した後で、改めて svn revert を試みてください。それでも解決しない場合は、ワーキングコピーの一部または全体を改めてチェックアウトし直す必要があるかもしれません。
11. まとめ
svn revert コマンドは、Subversionを使った開発において、ワーキングコピー上の未コミットのローカルな変更を効率的に破棄するための非常に有用なツールです。ファイル内容の編集、追加、削除、移動、プロパティ変更など、様々な種類の未コミット変更を取り消すことができます。
その基本的な使い方は svn revert PATH [PATH...] とシンプルですが、再帰的な操作を可能にする -R オプション、再帰深度を制御する --depth オプション、対象ファイルをリストで指定する --targets オプション、チェンジリストで指定する --changelist オプションなど、様々なオプションを組み合わせることで、より柔軟なrevert操作が可能です。
特に、開発途中で不要になった実験的な変更を破棄したい場合や、svn add / svn delete などの操作を取り消したい場合、あるいはコンフリクト解消の方針としてローカルの変更を破棄したい場合に、svn revert は活躍します。
しかし、svn revert は一度実行するとローカルの未コミット変更を永久に破棄してしまうという、取り返しのつかない操作であるということを常に意識しておく必要があります。そのため、コマンドを実行する前には必ず svn status や svn diff で変更内容を十分に確認し、対象パスを間違えていないか慎重にチェックすることが極めて重要です。また、特に重要な変更をrevertする場合は、念のため手動でバックアップを取っておくという対策も有効です。
svn revert を正しく理解し、その強力さと危険性を認識した上で慎重に使用することで、開発ワークフローを効率化し、クリーンなワーキングコピーの状態を維持することができます。この記事が、svn revert コマンドを使いこなすための一助となれば幸いです。バージョン管理システムを最大限に活用し、よりスムーズで安全な開発を目指しましょう。