はじめに
Subversionは楽観的ロックを採用しているため、複数人が同時に同じファイルを編集できます。初心者の方は、そんなことをしても大丈夫なのかと不安になるかもしれませんね。しかし実際には、悲観的ロック(同時編集不可)よりもうまくいくことのほうが多いのです。それは、コミットの際にファイルが変更済みであったとしても、マージにより解決できるからです。
この記事では、Subversionにおけるマージとコンフリクト(競合)について、解説と合わせてチュートリアルを行っていきます。複数人でSubversionを使うなら、マージは避けられません。ここでしっかりと学習しておきましょう。
マージとは?
マージとは、同一の2つのファイルを統合することです。作業コピーを取得した時は最新だったファイルも、いつの間にか他の人のコミットで変更されていることがあります。その場合には、リポジトリのファイルの変更点を取り込んで統合する必要があります。また、分岐した2つのブランチを統合する際も同様です。
マージが発生するタイミング
作業コピーを更新した時
updateコマンド実行時にリポジトリのファイルが更新(コミット)されている場合、作業コピーのファイルとマージが行われます。ファイルが古い(リビジョンが最新でない)状態ではコミットができませんので、必ず作業コピーを更新してからコミットする必要があります。
ブランチをマージした時
分岐した2つのブランチを統合する場合、対象のブランチのファイルがマージされます。実際には対象のブランチの差分が作業コピーに対して適用されるため、マージによってブランチが1つになるわけではありません。Gitとはマージの概念が異なっているため注意が必要です。
後ほど、この2つの状況をシミュレートしてチュートリアルを行います。
マージではコンフリクトが起こる可能性がある
マージの際に変更箇所が重複していなければ、Subversionが自動的に2つのファイルを統合してくれます。しかし、ときにはコンフリクト(競合)が起きる場合もあります。そうなると自動的には統合できませんので、手作業でコンフリクトを解消する必要があります。意味的に正しくなるように変更点を統合しなければいけません。
コミット時のマージとコンフリクトの解消
Subversionのインストール
チュートリアルに入る前に、まだSubversionを導入していない方は下記の公式サイトからパッケージをダウンロードして、インストールしておいてください。
新しいリポジトリの作成
それではチュートリアルのために、新しいリポジトリを作成しましょう。コマンドライン(コンソール)から次のコマンドを入力してください。リポジトリ名は「tuto-repo」とします。なお、カレントディレクトリは事前に移動しておきます。
svnadmin create tuto-repo
これで新しいリポジトリが作成できました。
作業コピーの取得(Xさん)
このチュートリアルでは意図的にコンフリクトを発生させるために、XさんとYさんの2人のユーザーをシミュレートします。まずは、Xさんの作業コピーを「work-x」ディレクトリに取得しましょう。なお、パスは適宜読み替えてください。
mkdir work-x
cd work-x
svn checkout file:///C:/Users/Test/Desktop/tuto-repo
ファイルの追加とコミット
次に、マージの対象となるファイルを追加してコミットしておきましょう。下記の内容の「schedule.txt」ファイルを、先ほど取得した作業コピーのディレクトリに作成してください。
4/12 プロジェクト開始
5/20 テスト
6/15 リリース
ファイルを保存したら、コミットしておきます。
cd tuto-repo
svn add schedule.txt
svn commit -m スケジュールの追加
作業コピーの取得(Yさん)
それでは次にYさんとして作業コピーを取得しましょう。ディレクトリ名は「work-y」とします。
cd ../..
mkdir work-y
cd work-y
svn checkout file:///C:/Users/Test/Desktop/tuto-repo
Yさんによるファイルの変更
次に、YさんがXさんに知らせずにファイルを変更するとします。先ほどの「schedule.txt」ファイルの最後の行を次のように変更してください。
6/10 リリース
ファイルを保存したら、コミットしておきましょう。
cd tuto-repo
svn commit -m スケジュールを変更しました
Xさんによるファイルの変更
それでは再度、Xさんに戻ってファイルを変更してみましょう。なにも知らないXさんは、Yさんと同じく「schedule.txt」の最後の行を次のように変更しようとします。
6/20 リリース
ファイルを保存したら、この状態でコミットしてみましょう。さて、何が起こるでしょうか?
cd ../../work-x/tuto-repo
svn commit -m スケジュールを変更しました
ファイルのリビジョンが最新ではない、と怒られてしまいましたね。この場合、コミットする前に作業コピーを最新にする必要があります。updateコマンドを使って、作業コピーを更新しましょう。
svn update
するとリポジトリのファイルとマージが行われます。しかし変更点が重複しているため、コンフリクトが発生してしまいます。「(p) postpone」を選択してコマンドを終了しておきましょう。同時に作業コピーのディレクトリに、「schedule.txt.mine」「schedule.txt.r1」「schedule.txt.r2」という3つのファイルが作成されます。これは変更前のファイルおよび競合している両者のファイルです。
ここで「schedule.txt」を開いてみましょう。なにやら妙な変更がされていますね。
4/12 プロジェクト開始
5/20 テスト
<<<<<<< .mine
6/20 リリース=======
6/10 リリース>>>>>>> .r2
これは、どの部分が競合しているかを示すマーカーテキストです。このファイルを正常な状態に修正することでコンフリクトを解消します。話し合いの結果、次のように修正することにしました。
4/12 プロジェクト開始
5/20 テスト
6/17 リリース
ファイルを修正したら、保存しておきましょう。さて、コミットしたいところですが、その前に「resolved」コマンドを使って、コンフリクトで作成された不要なファイルを削除する必要があります。
svn resolved schedule.txt
すると、先ほど自動的に作成された3つのファイルが削除されます。これでコミットする準備が整いました。
それではコミットしましょう。
svn commit -m スケジュールを変更しました
今度は、うまくコミットできましたね。これがマージとコンフリクトの基本になります。しっかりと覚えておきましょう。
ブランチのマージ
新しいリポジトリの作成とファイルのインポート
それでは、今度はブランチのマージをためしてみましょう。新しいリポジトリを作成し、「trunk」ディレクトリにファイルをインポートします。リポジトリ名は「tuto-repo2」です。インポートするファイルには先ほどの「schedule.txt」を使います。
cd ../..
svnadmin create tuto-repo2
svn import work-x/tuto-repo/schedule.txt file:///C:/Users/Test/Desktop/tuto-repo2/trunk/schedule.txt -m ファイルのインポート
ブランチの作成
次にマージの対象となるブランチを作成します。ブランチ名は「new-branch」です。
svn mkdir file:///C:/Users/Test/Desktop/tuto-repo2/branches -m branchesの作成
svn copy file:///C:/Users/Test/Desktop/tuto-repo2/trunk file:///C:/Users/Test/Desktop/tuto-repo2/branches/new-branch -m 新しいブランチの作成
ブランチのファイルの変更
それではブランチをチェックアウトして、ファイルを変更してみましょう。作業ツリーのディレクトリ名は「work」とします。
mkdir work
cd work
svn checkout file:///C:/Users/Test/Desktop/tuto-repo2
続けて「new-branch」ディレクトリにある「schedule.txt」ファイルの最後の行に下記のテキストを追加します。
7/20 定期メンテナンス
ファイルを保存したら、コミットしましょう。
svn commit -m スケジュールを追加しました
ブランチのマージ
それでは「trunk」に「new-branch」をマージして、ブランチの変更点を取り込んでみましょう。「merge」コマンドで作業コピーに変更差分を反映してからコミットします。
svn merge file:///C:/Users/Test/Desktop/tuto-repo2/trunk file:///C:/Users/Test/Desktop/tuto-repo2/branches/new-branch trunk
これで「trunk」ディレクトリの「schedule.txt」にブランチの変更が反映されました。ファイルを開いて確認してみましょう。なお、変更反映の際にマージが行われるため、コンフリクトが発生する可能性があります。その場合には、先ほどと同じ手順でコンフリクトを解消する必要があります。
それでは、コミットをしてマージを完了させましょう。
svn commit -m new-branchとマージしました
コミットがマージによって行われたものか分かりやすくするために、コミットメッセージに明記しておきましょう。マージ後に、ブランチが役目を終えて不要になったら、「delete」コマンドを使ってブランチのディレクトリごと削除してしまいます。ブランチが増えすぎると管理が難しくなってしまいますので、不要になったブランチは忘れずに削除してください。
まとめ
マージとコンフリクトについて理解できましたか?ほとんどのマージはコンフリクトなしに解決できるはずです。あまり頻繁にコンフリクトが起きるようであれば、もっとチームメンバーとコミュニケーションをとり、なるべく同じ箇所を編集しないようにしましょう。また、定期的にupdateコマンドを実行することも重要です。作業コピーのファイルが古くなるほどコンフリクトが起きやすくなります。ファイルのリビジョンを最新に保ちましょう。
参考資料
社内サーバにリモートリポジトリを作るのも一つですが、「開発にまつわる面倒事」をこの際全部、tracpath(トラックパス)に任せてみませんか?
バージョン管理サービス・プロジェクト管理サービスの「tracpath(トラックパス)」では、
ユーザー5名、リポジトリ数3つまで、無料で利用可能です。
さっそく実務でも使って見ましょう。
自らも開発を行う会社が作ったからこそ、開発チームの「作る情熱」を支える、やるべきことに集中出来るサービスになっています。
エンタープライズ利用が前提のASPサービスなので、セキュリティも強固です。