Xcode + Subversion でプロジェクトの異なる 2 バージョンを平行管理する
SPECIAL
異なる 2 バージョンを平行して管理する
以前に Xcode + Subversion でソースコードの版管理を行う で、Xcode を Subversion で版管理する方法について記しました。
今回は Subversion で、あるプロジェクトで 2 つのバージョンを平行開発するにあたって必要になりそうな操作についてを、いろいろと調べて行ってみたいと思います。
ここでは、プロジェクト名を "Project" として、そのプロジェクトのバージョンとして "Project-1xx" と "Project-2xx" という 2 つを平行して開発して行く環境を考えてみたいと思います。
この時、原則として "Project-2xx" を主体にコードの編集を行い、必要に応じてその変更を "Project-1xx" に反映させるという形を取りたいと思います。
Subversion のリポジトリは "file:////svn/test.svn/xcode/" として、そこに "Project-1xx" と "Project-2xx" それぞれのプロジェクトが取り込まれているとしておきます。
チェックアウトされているワーキングフォルダーは "/work" とします。
Project 2xx のリビジョン番号を確認する
メインで開発を行っている "Project-2xx" のリビジョン番号を確認するには、ターミナルから次のような感じで行います。
svn log file:////svn/test.svn/xcode/Project-2xx/
このようにすることで、最新のものから順に、当時入力したコメント付きで、リビジョン番号が表示されます。
なお、次のように "--verbose" オプションを付けることで、どのリビジョンでどのファイルがどう扱われたかを確認することもできました。
svn log --verbose file:////svn/test.svn/xcode/Project-2xx/
ところで、上記の操作をカレントディレクトリから行えば "svn log" だけでもリビジョン番号を確認することができますが、ときどき、得られる情報が古い場合もあるようでした。
明らかにコミットしたはずのリビジョンが存在しない場合には、タイミングを見て "svn up" を実行して、作業コピーを最新の状態に更新する必要があるかもしれません。
または、xcode で全てコミットした後に "プロジェクト全体を更新" を実行しておくと、ローカルの作業コピーからも最新のリビジョン番号を確認することができるようになるようでした。
そんな理由から、"コミット" の後にはセットで "更新" を実行しておくと安心かもしれないです。
Project-2xx の更新差分を取得する
メインで開発を行っている "Project-2xx" の更新差分を取得するには、次のようなコマンドをターミナルで実行します。
このコマンドは "Project-2xx" のワーキングパスである "/work/Project-2xx" 上で実行します。
svn diff -r 38:40
このようにすることで、リビジョン 38 から 40 までの、2 つのリビジョンの間で更新された内容が、差分として画面に出力されます。
これを、リダイレクトなどを使用してテキストファイルに落としておけば、上記の例では、リビジョン 38 をリビジョン 40 に更新するためのパッチを作成することが可能です。
Project-1xx に差分を適用する
差分からパッチを作らなくても、Subversion を使って直接、あるプロジェクトの差分を別のプロジェクトへ適用することができるようになっていました。
たとえば "Project-1xx" に、"Project-1xx" のリビジョン 38 から 40 までに変更した内容を適用したい場合には、次のようにします。
このコマンドを、差分を適用したいプロジェクト "Project-1xx" のワーキングパス "/work/Project-1xx" 上で実行します。
svn merge -r 38:40 file:////svn/test.svn/xcode/Project-2xx/
このようにすることで、"file:////svn/test.svn/xcode/Project-2xx" リポジトリから "-r" オプションで指定した範囲のリビジョンで実施された変更を、現在のカレントディレクトリにあるソースコードに適用されます。
コンフリクト(編集の衝突)が検出されなければ、これであっという間に、"Project-2xx" で実施された修正が "Project-1xx" に適用されます。
コンフリクトが検出された場合には、以前に Xcode + Subversion でソースコードの版管理を行う でも触れたように、何らかの方法で衝突を手作業で回避してあげる必要があります。
衝突したファイルが Objective-C ソースコードのようなテキストファイルであれば、とりあえず、ターミナルでは "p" を選択してひとまず保留とした上で、Xcode を使用して、そのファイルに直接追記された差分を確認しながら、修正するのが簡単なように思います。
修正が終わったら、ターミナルから次のような感じで、衝突が検出されたそのファイルの修正が終わったことを Subversion に通知します。
svn resolved ProjectAppDelegate.m
コンフリクト(衝突)しているファイルを確認する
どのファイルがコンフリクトしているかを確認するには、確認したいプロジェクトのディレクトリー内で、次のコマンドを実行します。
svn status
このようにすることで、たとえば "Project-1xx" ディレクトリー上でこれを実行した場合には、"Project-1xx" に関するファイルの作業コピーの更新内容が一覧表示されます。
この中で、ファイル名の近くに "C" という記載があるファイルが、コンフリクトが検出されているファイルになります。
バージョン管理操作でエラーとなってしまう場合
バージョン管理の状態を整える
ファイルやフォルダーの保存場所の大幅な変更があると、差分適用後にバージョン管理処理でエラーになってしまう場合があるようでした。
このとき、あるディレクトリーが見つからないとかコミットできないとか言われる場合は、バージョン管理の対象になっているファイルやフォルダーが、現在どのような状態として扱われているかを確認してみると、何かヒントがつかめるかもしれません。
状態を確認するには、確認したいプロジェクトのディレクトリー内で、次のコマンドを実行します。
svn status
このようにすることで、たとえば "Project-1xx" ディレクトリー上でこれを実行した場合には、"Project-1xx" に関するファイルの作業コピーの更新内容が一覧表示されます。
この中で、ファイル名の近くに "C" という記載があるファイルが、コンフリクトが検出されているファイルになります。
他にも、フォルダーやファイルがあるが扱いが不明といったものには、先頭に "?" が記載されていたりします。
こういったフォルダーの扱いは、"svn add 当該フォルダー" としてバージョン管理対象として扱ったり、"svn delete 当該フォルダー" としてバージョン管理対象外として扱ったりすることで、バージョン管理の状態を正しい状態にして行きます。
また "!" がついていて "> local delete, incoming delete upon update" というようなメッセージが付加されているような場合にも、それが意図して削除したファイルであれば "svn revert 当該ファイル" などとして、ローカルの作業フォルダから切り捨てるなどの対応が行えます。
このようにして、作業コピーにおけるバージョン管理の扱われ方を整えて行くことで、バージョン管理の操作ができるようになってくると思います。
プロジェクトファイルに対する操作でエラーになる
たとえば、変更を適用した "Project-1xx" で、Xcode からそれをコミットした時に "Project-2xx.xcodeproj" がコンフリクトしているというメッセージが表示されてしまう場合には、それぞれのプロジェクトで別の名前のプロジェクトとしている場合には、次のようにしてそれを解消します。
svn revert Project-2xx.xcodeproj
このようにすると、これまで "svn status" で "local delete, incoming edit upon merge" と表示されていた別の方のプロジェクトファイルが、今回のプロジェクトのソース管理対象から外すことができます。
このようにして、Xcode からプロジェクト全体をコミットとき "'Project-1xx'" is out of date" というメッセージが表示されてしまう場合がありました。
この場合は、対象となるディレクトリ上で、次のようなコマンドを実行します。
svn up
このようにして、いったんリポジトリ上の変更点を作業コピーに反映させることで、解消させることができるようでした。
Failed to add directory
フォルダー階層などがそれぞれのバージョン間で大きく変わり、既存のディレクトリを追加したり削除したりしているうちに、プロジェクト全体のコミットをしようとしたときに、次のようなエラーが発生してしまうことがありました。
"Failed to add directory ディレクトリ名: a versioned directory of the same name already exists"
このような場合は、その該当ディレクトリーのバックアップを取った上で、それを削除して、該当ディレクトリーを元の状態に戻し、Subversion を更新して、バックアップしておいたファイルを元の場所にコピーするという流れを取ると直るようです。
具体的には、例えば "DIRECTORY" というディレクトリーでエラーが発生した場合は、次のような流れになると思います。
cp DIRECTORY /tmp/DIRECTORY.backup
rm -rf DIRECTORY
svn revert DIRECTORY
svn up
cp -rf /tmp/DIRECTORY.backup/* DIRECTORY/
ポイントとしては "svn revert" でローカルの作業コピーを破棄した上で、"svn up" によってリポジトリに記録された変更点を作業コピーに反映させて矛盾を解消するという感じでしょうか。
ローカルの作業コピーを破棄して更新する都合、別の場所へ一時的に退避しておくことが必要のようです。