CVS/Subversionを使ったバージョン管理(前編:バージョン管理の基礎)

 ソフトウェアを開発する際、ソースコードや各種リソースの管理に役立つのがバージョン管理システムだ。バージョン管理システムはソースコード管理システムなどとも呼ばれ、大規模な開発を行う際には必須と言っても過言ではない。また、大規模な開発だけでなく小規模な開発や個人による開発においても、ファイルの変更履歴の記録やバックアップといった用途に活用できる。

 本特集ではバージョン管理システムの基本的な考え方や用語を解説するとともに、オープンソースソフトウェア/フリーソフトウェア開発において多く利用されているバージョン管理システムである、SubversionおよびCVSを使ったバージョン管理方法について説明する。前編となる本記事では、まずバージョン管理システムの基本的な考え方と、用語について解説する。

バージョン管理システムのメリット

 バージョン管理システムとは、その名のとおりプログラムのソースコードや各種リソースを管理するためのシステムだ。代表的なものとしてはCVSやSubversion、Git、Mercurial、Visual SourceSafeなどがある。バージョン管理システムは以下のような機能を備えており、特に複数人/複数拠点間で連携してソフトウェア開発を行う際に有効である。

  • ディレクトリ構造によるファイルの保存
  • ファイルに加えられた変更履歴の保存/管理
  • 排他的編集を行うためのロック機構
  • 複数人が同時に同一のファイルに変更を加えた際の競合解決
  • ネットワーク経由でのアクセス
  • 差分による効率的なファイル転送

 なお、バージョン管理システムは中央集権型と分散型の2つに分けられる。中央集権型は1つのサーバーで変更履歴が管理され、そのサーバーに対して後述するチェックアウトやコミットといったアクセスを行うもので、代表的なものにCVSやSubversionがある。一方、分散型のバージョン管理システムではローカルで変更履歴が管理されるもので、代表的なものにGitやMercurialがある。本記事ではCVSおよびSubversionを例にバージョン管理システムの利用法を説明しているが、基本的な考え方はほかのバージョン管理システムでも同じである。

バージョン管理システムの仕組み

 バージョン管理システムを使用した開発では、(1)「リポジトリ」と呼ばれるファイルや管理情報などを保存する場所から作業用のディレクトリにファイルを取り出し、(2)取り出したファイルに修正を加え、(3)変更を加えたファイル(もしくは変更差分)をリポジトリに送信する、といったステップで開発作業を進めていく(図1)。

図1
図1 リポジトリとチェックアウト、コミット

 リポジトリから作業用ディレクトリにファイルを取り出す作業は「チェックアウト」と呼ばれ、また作業用ディレクトリに取り出したファイルは「ワーキングコピー」、もしくは「ローカルコピー」などと呼ばれる。また、ワーキングコピーに加えた変更点をリポジトリに保存する作業は「コミット」もしくは「チェックイン」などと呼ばれている。

 上記のようなリポジトリに対する操作は、専用のクライアントを介して行う。CVSの場合「cvs」、Subversionの場合「svn」という、コマンドラインで操作するクライアントが一般的だが、WindowsのエクスプローラからCVS/Subversionリポジトリにアクセスできる「TortoiseCVS」や「TortoiseSVN」というツールや、GUIのクライアントもある。

ここまでの用語まとめ
・リポジトリ
バージョン管理を行っているファイルや管理情報を保存する場所
・チェックアウト
リポジトリから編集・閲覧用にファイルを取り出す作業。cvs/svnでは「checkout」コマンドで行える
・ワーキングコピー、ローカルコピー
リポジトリから編集・閲覧用にチェックアウトしたファイルのこと
・コミット、チェックイン
ワーキングコピーに加えた変更をリポジトリに保存させる作業。cvs/svnでは「commit」コマンドで行える

リポジトリの構造とインポート

 使用するバージョン管理システムごとにファイルの管理方法は異なるが、どのバージョン管理ツールでも共通なのが、ファイルを階層構造で管理する点だ。開発に使用するツールによっても異なるが、ソースファイルや各種リソースファイルは関連するものごとにディレクトリを分けておくのが一般的だ。バージョン管理ツールは、このディレクトリ階層を保ったままファイルを管理することができる。一般に、開発に必要なファイルを含むトップディレクトリからの階層構造(ツリー)のことを「モジュール」もしくは「プロジェクト」などと呼ぶ(図2)。1つのリポジトリには複数のモジュール(プロジェクト)を格納可能で、リポジトリへのファイル登録やチェックアウトは基本的にモジュール単位で行うことになる。

図2
図2 リポジトリの構造

 バージョン管理システムを使用した開発で、最初に行うのがリポジトリにモジュールを登録する作業だ。この作業は「インポート」などと呼ばれる。ファイルをインポートすると、リポジトリにはファイルの内容に加え、ファイルの作成者や以後の変更履歴など、ファイルを管理するための情報が作成され、ファイルとともに保存される。

ここまでの用語まとめ
・ツリー
開発に必要なファイルや、それらを含むディレクトリをまとめてこう呼ぶ
・モジュール、プロジェクト
関連するファイルやリソースをまとめて管理する単位。バージョン管理システムによっては明確には定義されておらず、ディレクトリと同義の場合もある
・インポート
開発に必要なファイル一式をリポジトリに登録する作業。cvs/svnでは「import」コマンドで行える

チェックアウトとコミット、更新

 リポジトリに格納されているファイルをチェックアウトすると、通常はファイルとともにその管理情報がワーキングコピーとして作業ディレクトリに保存され、これを元にファイルの管理が行われる。チェックアウトしたファイルは、バージョン管理システムを使わない場合とまったく同様に、エディタや統合開発環境(IDE)などで自由に編集できる。通常管理情報はソースファイルやリソースファイルとは異なるファイル/ディレクトリに保存されるからだ。

 ファイルに加えた変更は、コミットを行うことでリポジトリに保存される。コミットは通常モジュール単位で行い、ワーキングコピーの管理情報を元に、変更が加えられたファイルの情報がリポジトリに送信される。通常、コミットを行う際は変更点や伝達事項といったメモも記録しておける。

 なお、ファイルの変更履歴は「リビジョン」と呼ばれる管理番号で管理される。通常、コミットを行うごとに付加されたリビジョンは増加していく。

 複数人で開発を行っている場合や、複数の拠点で開発を行っている場合、ワーキングコピーのリビジョンがリポジトリにあるファイルのリビジョンよりも低い場合がある。この場合、「アップデート」(更新)を行うことで、ワーキングコピーをリポジトリにある最新ファイルのものと同期できる。

ここまでの用語まとめ
・リビジョン
ファイル/リポジトリの管理番号。バージョン番号のようなもので、CVSの場合ファイルごと、Subversionの場合リポジトリごとに付けられる。通常ファイル/リポジトリに修正を加えてコミットすると、リビジョンが1つ上がる(数値が1増える)
・アップデート、更新
リポジトリに加えられた変更をワーキングコピーに反映させる作業。cvs/svnでは「update」コマンドで行える

コンフリクトとその解決

 単独で開発を行っている場合はあまり問題にはなりにくいが、複数人で開発を行っている場合などは、同一のファイルに異なる変更が加えられてしまうという問題が発生する可能性がある。この状態を「コンフリクト」(競合)と呼ぶ。バージョン管理システムによっては、コンフリクトを自動的に解決してくれるものもある。ただし、同一の個所に異なる変更が加えられている場合など、自動的にコンフリクトの解決を行えない場合もある。この場合、手動で適用する変更を選択するなどして、コンフリクトを解決しなければならない。

 バージョン管理システムによっては、1つのファイルに対して同時に1人しか変更を加えられないよう、「ロック」を行う機能を持つものがある。ロックされたファイルは、編集を行った人が変更をコミットし、「アンロック」を行うまで他の人は変更できない。

ここまでの用語まとめ
・コンフリクト、競合
リポジトリにあるファイルと、ワーキングコピーとで異なる変更が加えられてしまっている状態
・ロック
指定したファイルを他の人が編集できないようにすること
・アンロック
ロックを解除すること

リポジトリの分岐

 開発を進めていくに従って、「リリース時など、特定のリビジョンのファイル群を簡単に取り出せるようにしたい」や、「開発中のモジュールを複製して、メインの開発ツリーとは異なる変更を加えたい」といった要望が出ることがある。バージョン管理システムは、これらを実現する機能も備えている。

 特定のリビジョンのファイル群を簡単に取り出せるようにしたい場合、指定したリビジョンのファイル群に「タグ(tag)」と呼ばれる名前を付けておけばよい。タグ名を指定して、そのリビジョンのファイルを取り出すことができるようになる。

 また、開発中のモジュールを複製し、複数の開発ツリーを作ることを「ブランチを作る」などと呼び、複製されたそれぞれのツリーを「ブランチ(brunch)」と呼ぶ。それぞれのブランチはそれぞれ独立したものとして扱われ、1つのブランチに適用した変更は、ほかのブランチには影響を及ぼさない。また、複数のブランチに対し、それぞれに加えた変更点を1つにまとめることを「マージ」と呼ぶ。

 なお、ブランチに対して本流の開発ツリーは「トランク(trunk)」や「ヘッド(HEAD)」などと呼ばれることがある。

ここまでの用語まとめ
・トランク(trunk)/ヘッド(HEAD)
本流の開発ツリーをこう呼ぶ
・ブランチ(branch)
本流の開発ツリーとは異なる変更を加えるためのツリー
・タグ(tag)
リポジトリで管理しているファイル群の特定のリビジョンを保存する機能、もしくはその特定のリビジョンに付けられる名称。たとえばファイルのリリース時などに、分かりやすい名前を付けてその状態を保存しておくために使われる
・マージ
複数のブランチを1つにまとめること。それぞれのブランチに加えられた変更点をまとめ、競合する変更がある場合はどの変更を採用するか選択する、といった作業が発生する

中編に続く)