バージョン管理

バージョン管理システム(あるいは リビジョン管理システム)は、 プロジェクト内のさまざまなファイルの変更履歴を管理するための テクノロジーや習慣を組み合わせたものです。 たとえば、ソースコードやドキュメント、 ウェブページなどがバージョン管理の対象となります。 もしこれまでにバージョン管理システムを使ったことがないのなら、 まずはバージョン管理システムを使ったことのある人を探して プロジェクトに引きずり込みましょう。いまどきのプロジェクトなら、 少なくともソースコードくらいはバージョン管理されていて当然です。 また、たかがバージョン管理程度のことすらできていないプロジェクトなど、 誰もまともに取り合ってくれないかもしれません。

バージョン管理がこれほどまで一般的になった理由は、 プロジェクトを運営していく上でいろいろな場面で役立つということです。 開発者どうしのコミュニケーション、リリース管理、バグ管理、 コードの安定性の確保、安心して新機能を実験できる環境、 各開発者の権限の管理など、 あらゆる場面でバージョン管理が利用できます。 バージョン管理システムは、これらの内容を一まとめにして管理します。 その中心となる機能が、変更管理です。 これは、プロジェクト内のファイルが変更されるたびに その変更についてのメタデータ(更新日や更新者など) を収集する仕組みです。 そして、あとからその変更の内容を再現できるようにするのです。 つまり、変更が発生した単位で情報を管理する仕組みといえます。

このセクションでは、バージョン管理システムのあらゆる機能を説明するわけにはいきません。 あまりにもさまざまな機能があるので、本書ではすべてを紹介することができないのです。 ここでは、使用するバージョン管理システムを選択して 実際に稼動させるところまでに絞って説明していきます。

バージョン管理に関する用語集

本書では、まだバージョン管理システムを使ったことがない人に対して その基本的な使い方を解説することはできません。 しかし、いくつかのキーワードを知っていなければ、 これ以降の議論についていけなくなるでしょう。 ここで説明するキーワードは、どのバージョン管理システムでも共通に使われるものです。 これらの言葉については、これ以降でもとくに説明せずに使用していきます。 たとえこの世にバージョン管理システムがなかったとしても、 変更の管理をどうするかという問題が消えてなくなることはありません。 この問題について語る際には、ここで取り上げたキーワードを知っていると便利です。

コミット

プロジェクトに変更を加えること。もう少しかしこまって言うと、 変更した内容をバージョン管理データベースに格納し、 そのプロジェクトが次に公開するリリースに反映されるようにすること。 "コミット" は、動詞としても名詞としても用いられます。 名詞として使った場合の意味は、"変更" とほぼ同じです。 たとえば次のように使用します。"Mac OS X 上でサーバがクラッシュするバグを修正してコミットした。 ジェイ、悪いけどこのコミットの内容をチェックしてくれないかな? もしかしたらメモリを確保する方法を間違っているかもしれないし"

ログメッセージ

各コミットに添付されたコメントで、 そのコミットの内容や目的を説明するもの。 ログメッセージは、そのプロジェクトのドキュメントの中で 最も重要なものです。これは、実際に変更したコードの内容を 人間が読んでわかりやすい言葉 ("機能追加"、"バグ対応"、 あるいはプロジェクトの進捗状況など) に変換する意味合いがあります。 このセクションの後半では、 ログメッセージを適切なメンバーに配信する方法を説明します。また、 6章コミュニケーション「しきたりの成文化」 では 各メンバーにいかにして有用なログメッセージを書いてもらうかを説明します。

アップデート

他のメンバーの変更 (コミット) をローカル環境に取り込むこと。 つまり、ローカル環境を "最新版" にすること。 これは非常に頻繁に行われる操作です。 ほとんどの開発者は、自分のコードを一日に何度もアップデートします。 それにより、自分の開発環境を他のメンバーとほぼ同じ状態に保つようにするのです。 また、もし何かバグを見つけたときに、 おそらくまだそれは修正されていないものであろうことを予想できるようにします。 たとえば次のように使用します。"ねぇ、このコードって、 いちばん最後のバイトを読んでいないように見えるんだけど……。 バグじゃない?" "うん。でもそれは先週修正したよ。 最新版にアップデートしたらバグはなくなるはずだ。"

リポジトリ

変更内容を格納するデータベース。 たとえば中央管理方式のバージョン管理システムでは、 マスタリポジトリがひとつだけ存在します。 すべての変更内容がここに格納されることになります。 分散管理方式の場合は、各開発者が個別にリポジトリを所有します。 他のリポジトリとの間のデータ交換が、任意のタイミングで発生します。 バージョン管理システムは、各変更の内容を記録しています。 リリース時期には、特定の時点の内容をリリース用として指定します。 中央管理方式と分散管理方式のどちらがよいかについて語りだすと、 終わりのない宗教戦争に巻き込まれてしまいます。 プロジェクトのメーリングリストでは、 できるだけこの問題には触れないようにしましょう。

チェックアウト

リポジトリからプロジェクトの内容を取得する処理。 チェックアウトを行うと、いわゆる「作業コピー」 (次の項を参照ください)と呼ばれるディレクトリツリーが作成されます。 このツリーに変更を加えた結果をコミットし、元のリポジトリに反映させます。 分散型のバージョン管理システムの中には、 作業コピーそのものがリポジトリでもあるというものもあります。 その変更内容を、他のリポジトリとの間でやりとりしたりする構造になっています。

作業コピー

開発者がローカル環境に保持するディレクトリツリーで、 この中にはプロジェクトのソースコードやウェブページ、 その他のドキュメントが格納されることになります。 作業コピーには、バージョン管理システムが使用するメタデータも含まれています。 このメタデータの中には、取得元のリポジトリの場所や現在の "リビジョン"(次の項を参照ください)などについての情報が格納されています。 一般に、個々の開発者は自分の作業コピーを取得してそこで開発を行います。 そして、変更した内容のテストを済ませたうえで それをコミットします。

リビジョンチェンジチェンジセット

"リビジョン" とは、指定したファイルやディレクトリの 特定の時点の状態のことです。 たとえば、あるプロジェクトのファイル F のリビジョンが 6 であった場合に、誰かがファイル F を変更してコミットすると、 F のリビジョンは 7 となります。 システムによっては、一度に行われたある特定の変更群を称して "リビジョン"、"チェンジ" あるいは "チェンジセット" とするものもあります。

バージョン管理システムによっては、 これらの用語を明確に定義しているものもあります。 しかし、一般的な考え方はどれも同じです。 一連の流れの中の特定の時点 (バグ修正が行われた箇所など) を指定する方法を用意しているわけです。 たとえば、次のように使用します。 "ああ、それなら彼女がリビジョン 10 で修正したよ。" あるいは "彼女は foo.c のリビジョン10でそれを修正したよ。"

特定のリビジョンを指定せずに話を進めている場合は、 一般に最新のリビジョンについて語っているものと考えていいでしょう。

差分

変更内容を表すテキスト。 変更があった箇所とその前後数行について、 変更前と変更後の状態を表示します。 元のコードになじみがある人なら、 差分を見ればどこをどう変更したのかがわかります。 時にはバグを見つけたりすることもできるでしょう。

タグ

指定したリビジョンを構成するファイルにつけるラベル。タグは、 プロジェクトの特筆すべき時点の状態を保護するために使用することが多くなります。 特筆すべき点とは、たとえば一般向けのリリースなどがあげられます。 リリースごとにタグをつけておけば、 そのリリースとまったく同じ内容のファイル群を バージョン管理システムから簡単に取得できるようになります。 タグの名前としてよく用いられるのは、 Release_1_0Delivery_00456 といったものです。

ブランチ

プロジェクトの一部でありバージョン管理下に存在するが、 他とは隔離されている部分。ブランチに対して適用した変更は その他の部分に対しては影響をおよぼしません。また逆も同様です。 ただし、明示的に "マージ" した場合は別です (以下を参照ください)。 ブランチは、"開発ライン" と呼ばれることもあります。 明示的にブランチを作成していない場合でも、 "メインブランチ" で開発を進めているものと考えます。このブランチのことは "メインライン" あるいは "トランク (trunk)" と呼ばれることもあります

ブランチを使用すると、複数の開発ラインを別々に管理できるようになります。 たとえば、本流の開発ラインとは別に実験的な開発用のブランチを作成し、 本流を不安定にさせる可能性があるような開発はそちらで行うということができます。 あるいは逆に、新しいリリース用の安定版ブランチを作成するといった使用法もあります。 この方式の場合、リリースが間近に迫っても、 通常の開発は本流ブランチ上で途切れなく続けられます。 一方、リリース用ブランチではリリース作業に入った段階でコミットを停止し、 リリース管理者が許可しない限りはコミットをしないようにします。 この方式を採用すると、リリース前にいったん開発を中断する必要がなくなります。 ブランチについての詳細は、本章の後半 にある 「ブランチの活用」 をご覧ください。

マージ (あるいはポート)

変更内容を、あるブランチから別のブランチに移動すること。 本流の変更内容を他のブランチに適用したり、その逆を行ったりすることも含みます。 実際のところ、ほとんどのマージ作業はこのパターンです。 本流以外の2つのブランチ間でのマージはほとんどありません。 この手のマージについては 「情報の一元管理」 をご覧ください。

"マージ" にはもうひとつの意味もあります。 ひとつのファイルに対して複数人が別々の箇所を変更したときに、 バージョン管理システムが行う処理のことです。 お互いの変更が相手の変更を邪魔することはないので、 手元で修正済みのファイルをアップデートすると、 相手の変更内容が自動的にマージされ(取り込まれ)ます。 これは、複数の人が同じファイルをハックしている場合によくあることです。 万一お互いが変更した箇所が重なっていた場合は、次に説明する "コンフリクト" 状態になります。

コンフリクト

ひとつのコードの同じ箇所を異なる人が変更しようとした際に起こる現象。 バージョン管理システムは、コンフリクトの発生を自動的に検出します。 そして、変更しようとしたユーザーに対してそれを通知します。 発生したコンフリクトを 解決 するのは、変更しようとした人たち自身の責任です。 解決したあとで、それをバージョン管理システムに通知します。

ロック

特定のファイルやディレクトリを、他人に変更されないように宣言する方法。 たとえば "ウェブページの変更内容をコミットしようとしたけどできない。 たぶん、Alfred が背景画像を修正する間、すべてのファイルをロックしているんだろう" というように使います。 中にはロック機能を持っていないバージョン管理システムもあります。 また、その機能を持っていたとしても、実際にそれが必要となることはあまりないでしょう。 いろんな人が同時に平行して開発を進めるというのが普通の状況なのであり、 ロックして他人を締め出すというのはこの理想に相反するものです。

コミットするにはロックが必要となるバージョン管理システムのことを、 「ロック - 修正 - ロック解除 (lock-modify-unlock) モデル」 といいます。一方、ロックが必要でない方式のことは 「コピー - 修正 - マージ (copy-modify-merge) モデル」 といいます。2つの方式について深く掘り下げて比較したすばらしい文書が http://svnbook.red-bean.com/svnbook-1.0/ch02s02.html日本語訳) にあります。一般に、オープンソース開発においては コピー - 修正 - マージ モデルの方が適しています。 本書で扱うバージョン管理システムは、すべてこの方式を採用しています。

バージョン管理システムの選択

本書の執筆時点では、 フリーソフトウェアの世界で最もよく使われているバージョン管理システムは Concurrent Versions System (CVS, http://www.cvshome.org/) と Subversion (SVN, http://subversion.tigris.org/) の2つです。

CVS には長い歴史があります。 ベテランの開発者はすでに CVS についてはよくご存知でしょう。 これまでにも CVS がいろいろな場面で役に立ってきたはずです。 CVS の時代があまりにも長く続いてきたので、 本当にそれが最適な選択肢だったのかどうかなんて聞くだけ野暮というものでしょう。 しかし、CVS には欠点もあります。 まず、複数のファイルを一括して変更したときに、それを追いかける簡単な手段がありません。 また、バージョン管理下にあるファイルの名前を変えたりコピーしたりすることができません (プロジェクトをいったん開始した後でコードツリーの構成を変更したい場合は、 泣きながら大変な作業をこなすことになるでしょう)。 そして、マージ機能はかなりお粗末なものです。 巨大なファイルやバイナリファイルの扱いも不得意です。 そして、大量のファイルを一括して操作しようとすると非常に時間がかかることがあります。

CVS のこれらの欠点は決して致命的なものではありませんが、 無視できるものでもありません。 ここ数年、新たに立ち上げられたプロジェクトでは Subversion を採用することが多くなってきました [18]。 これから新たにプロジェクトを立ち上げるのなら、Subversion をお勧めします。

一方、私が Subversion プロジェクトにかかわっていることもあり、 私の意見の客観性に疑問を持たれる方もいるかもしれません。 ここ数年、新たなオープンソースのバージョン管理システムがいくつか登場しています。 付録B フリーなバージョン管理システム に、 私が知っているものを挙げておきます。 このリストを見てもわかるように、バージョン管理システムにどれを採用するかを決めるには、 下手したら一生かかってしまうかも知れません。 もしかしたら、あなたには選択の余地がないかも知れません。 というのは、ホスティングサイトを使用する場合は ホスティングサイト側でバージョン管理システムが設定されているかもしれないからです。 もしあなたが自分で選択しなければならない立場になったのなら、 まず周りの意見をよく聞いてからどれかひとつを選択し、 そして動かしてみましょう。 最近のバージョン管理システムは、どれもそれなりに機能します。 どれを選んだとしても、致命的な被害を受けることはないでしょう。 もしまだ迷っているのなら、Subversion を使ってみましょう。 これは簡単に習得でき、少なくとも今後数年は標準的に使われることでしょう。

バージョン管理システムの使用法

この章で説明する内容は、特定のバージョン管理システムに固有のものではありません。 どのシステムを選択した場合にも適用できるはずです。 詳細は、各システムのドキュメントを調べるようにしましょう。

すべてをバージョン管理する

ソースコードだけでなく、ウェブページやドキュメント、FAQ、設計メモなどなど、 編集する可能性のあるものはすべてバージョン管理下におくようにしましょう。 これらは、同一リポジトリツリー内でソースコードの隣に置いておきます。 書き残した情報は、すべてバージョン管理する価値があります。 つまり、あらゆる情報は変化する可能性があるということです。 今後変わりようのない内容については、 バージョン管理ではなくアーカイブしなければなりません。 たとえば、メーリングリストに投稿されたメールの内容は、変わることがありません。 このようなものをバージョン管理しても無意味です (もちろん、それが巨大な文書の一部となる場合などは別ですが)。

すべてを同じ場所でバージョン管理する理由は、 そうしておけば作業に参加する人がひとつのことを覚えるだけですむようになるからです。 たとえば、最初はウェブページやドキュメントの修正から参加しはじめたメンバーが、 後にコードそのものの修正にも参加するようになるといったことがあります。 すべてを同じ仕組みでバージョン管理しておけば、 このような場合に新たにその使用法を学ぶ必要がなくなるのです。 また、新機能を追加すると同時にドキュメントも更新したり、 コードのブランチを作成すると同時にドキュメントのブランチも作成したり といった際にも便利です。

自動生成されるファイル はバージョン管理する必要がありません。 これらのファイルは純粋に編集可能なデータではなく、 別のファイルの内容をもとにして自動生成されるものだからです。 たとえば、ビルドシステムでよく用いられるファイル configure は、テンプレート configure.in の内容をもとにして自動生成されるものです。もし configure を変更したいのなら、configure.in を編集してから再生成するということになります。つまり、この場合で言う 「真に編集可能なファイル」は、テンプレートである configure.in だけということになります。バージョン管理するのはテンプレートだけにします。 生成した結果までバージョン管理してしまうと、 テンプレートを修正した際にファイルを再生成することを忘れてしまうかも知れません。 そうすると、ファイルの整合性が取れなくなってしまって混乱の元となります。 [19]

「編集可能なデータはすべてバージョン管理下におかなければならない」 という規則には、残念ながらひとつだけ例外があります。 それが バグ追跡システム です。 バグデータベースは編集可能なデータを大量に保持していますが、 技術的な理由により、このデータをバージョン管理することはできません (バグ追跡システムの中には、ちょっとしたバージョン管理機能を独自に実装しているものもあります。 しかし、これはプロジェクトのメインリポジトリとは独立したものとなります)。

ウェブで閲覧できるようにする

プロジェクトのリポジトリは、ウェブ上からも閲覧できるようにしなければなりません。 これは、ただ単に最新のリビジョンが見られればいいというレベルのものではありません。 前のリビジョンにさかのぼったりリビジョン間の差分を見たり、 変更時のログメッセージを見たりといった機能も含みます。

これは、そのプロジェクトのデータに関する便利な入り口となるので、 ブラウザビリティ(閲覧のしやすさ)が重要となります。 もしウェブブラウザ経由での閲覧ができなければ、 そのプロジェクトの特定のファイルを調べたい人 (あのバグ修正はどんな風に行われたのかな?など)はまず バージョン管理システムのクライアントソフトウェアを インストールするところから始めなければならなくなってしまいます。 ウェブで見られれば2分ですむことなのに、 それがないために30分がかりの作業になってしまうということになります。

ブラウザビリティの中には、特定のファイルの特定のリビジョンが特定の URL で見られること、そして特定のファイルの(その時点での) 最新リビジョンも特定の URL で見られることといった内容も含まれます。 こうしておくと、技術的な議論の際にその場所を示しやすくなるので便利です。 たとえば「バグ管理についてのガイドラインは、作業コピーにある www/hacking.html をご覧ください」という代わりに 「バグ管理についてのガイドラインは http://subversion.apache.org/docs/community-guide/ をご覧ください」と言えるのです。 これは、常に community-guides/index.html の最新リビジョンを指す URL です。URL を指定するほうが、 あいまい性を排除するという点でよいでしょう。

バージョン管理システムの中には、 リポジトリをウェブで閲覧するための仕組みが組み込まれているものもあります。 また、サードパーティのツールを使ってこの機能を実現しているものもあります。 サードパーティのツールとして有名なのは ViewVC (http://viewvc.org/)、 CVSWeb (http://www.freebsd.org/projects/cvsweb.html)、 そして WebSVN (http://websvn.tigris.org/) です。ViewVC は CVS と Subversion の両方に対応しています。 一方、CVSWeb は CVS 専用、WebSVN は Subversion 専用です。

コミットメール

コミットが行われるたびに、その内容をメールで送信するようにします。 メールには「だれが」「いつ」「どのファイルやディレクトリを」「どのように」 変更したのかを記述します。 このメールの送信先は独立したメーリングリストとし、 人間が投稿する普通のメーリングリストとは独立させましょう。 コミットメールを受け取りたいひとだけがそのメーリングリストに参加することになります。 開発者やプロジェクトに興味があるその他の人たちには、 このメーリングリストへの加入を勧めましょう。 今そのプロジェクトに何が起こっているのかをコードレベルで知るために、 このメーリングリストは最適な手段となります。 ピアレビューの技術的な有用性については改めて語るまでもありません (「きちんとしたコードレビューの習慣」 をご覧ください) が、コミットメールもコミュニティーにおいては有用なものとなります。 すべてのイベント(コミット)の内容が共有されることで、 他のメンバーがそれに反応したりといったことがしやすくなるのです。

コミットメールの設定方法は、使用するバージョン管理システムによって異なります。 しかし、通常はそれ用のスクリプトやパッケージが用意されているはずです。 もし見つからなければ、使用しているシステムのドキュメントで フック(hooks)、あるいは コミット後フック(post-commit hook) といったキーワードで探してみましょう。ちなみに CVS では loginfo フック(loginfo hook) と言うようです。 コミットがあるたびに自動で特定の作業をさせる際に使用するのが コミット後フックです。これは各コミットの直後に呼び出され、 そのコミットに関する情報を受け取って任意の作業を行うことができます。 そう。たとえばメールを送信したりなど。

用意されているメール送信の仕組みを使用していると、 そのデフォルトの動作をちょっと変更したくなってくるかもしれません。

  1. コミットメールシステムの中には、実際の差分そのものは本文に含めず、 それをウェブで見るための URL だけを記載するというものがあります。 もちろん URL は大事です。後から変更内容を確認するのにも便利ですしね。 でも、差分の内容そのものをメールの本文に含めておくことも 非常に 重要です。多くの人にとって、 メールを読むという作業は日常のルーチンワークとして組み込まれているでしょう。 変更の内容が直接メールに書かれていれば、 一連の流れの中で自然にコミットをレビューすることができます。 いちいちメールソフトを終了してブラウザに切り替える必要がなくなるのです。 変更を確認するには URL をクリックする必要があるとなれば、 ほとんどの人はクリックなどしてくれないでしょう。 だって、これまでずっとメールを読んでいたのに、 いきなり別の操作が必要となるのですから。 さらに、変更点をレビューした人がその内容について質問をしたいときに、 そのメールに「返信」すれば自動的に変更内容が得られるので便利です。 さもないと、ウェブページを開いて変更点を カット&ペーストするという大変な手間がかかってしまいます。

    (もちろん、新たにリポジトリにコードを追加したなどで変更点が大量にある場合は、 差分を省略して URL だけにするというのもわかります。 コミットメールのシステムの多くは、 何らかの制限値を設定してこの処理を自動化してくれるようになっています。 もしそんな機能がついていなかったとしましょう。そんな場合でも、 差分をまったく記載しないよりは常に差分を含めるようにするほうがずっとマシです。 たまに巨大なメールが送信されることになりますが、許容範囲です。 共同開発においては、みんなが他人の変更をレビューしたりコメントしたりすることが重要です。 そのための努力は、いくらしてもしすぎることはありません)

  2. コミットメールの Reply-to ヘッダは、コミットメール用のメーリングリストではなく 開発者向けのメーリングリストにしておきましょう。 そうすると、コミットメールの内容をレビューして何らかのコメントをしたくなった人が 「返信」すると、それが自動的に開発者向けメーリングリストに流れることになります。 こうしておくべき理由はいくつかあります。 まず、技術的な議論はひとつの場所に集約するということ。 技術的な議論を行う場として最適なのは、開発者向けメーリングリストです。 次に、コミットメール用のメーリングリストに参加していないメンバーにも 議論の内容を伝えるということ。 3つ目に、コミットメール用のメーリングリストはあくまでも コミットの内容をチェックするだけのものであり、 決して「コミットの内容のチェックがメインだけど、 たまに技術的な議論もある」というものであってはいけないからです。 コミットメール用のメーリングリストに登録する人たちは、 コミット内容のメールだけが送られてくることを期待しています。 それ以外の内容が送られると、暗黙の了解を裏切ってしまうことになります。 最後に、コミットメールの内容を処理して(ウェブページなどに) 結果を出力するプログラムを作成するような人のことを考えるということ。 この種のプログラムは、 コミットメールのようなお決まりのパターンのメールに関してはうまく動作します。 しかし、人間が書いたメールを処理させると変な結果になってしまうでしょう。

    ここでお勧めした Reply-to の設定は、決して 本章の前半で述べた 「Reply-to はどうすべきか」 の内容と矛盾するものではないことに注意しましょう。 先ほども、メッセージの 送信者 自身が Reply-to を設定するぶんには特に問題はないとしています。今回の場合、 メッセージの送信者はバージョン管理システムです。 バージョン管理システム自身で Reply-to を指定して開発者向けメーリングリスト向けに返信させようとしているのですから、 さきほどの説明とは矛盾しません。

ブランチの活用

バージョン管理システムにあまり慣れていないユーザーは、 ブランチの作成やマージ作業を怖がる傾向があるようです。 おそらく、これは CVS の悪評の副作用でしょう。 CVS のブランチ作成処理やマージ処理は直感的とは言えず、 多くの人がそれを避けるようにしています。

もしあなたもその中のひとりだというのなら、 怖がる気持ちを乗り越えてブランチ作成やマージについて勉強してみましょう。 いったん作業に慣れてしまえば、そんなに難しいものではありません。 また、プロジェクトに参加するメンバーが増えれば増えるほどこの作業の重要性も増します。

ブランチを使用すると、限られた資源(プロジェクトのソースコード中の作業場所) を有効活用できるので便利です。 通常は、すべての開発者がひとつの砂場の上で作業をします。 みんなでひとつのお城を作っていこうとしているわけです。 あるとき、ひとりのメンバーが「ここに跳ね橋をつけましょうよ」と言い出しました。 でも、他のメンバーは、それがそのお城にとって本当に有用なのかどうかがわかりません。 そのメンバー用に砂場の一角を隔離し、彼女にはそこで作業をしてもらう。 ブランチを作成するとは、そういうことになります。 もしうまい具合に跳ね橋が出来上がったら、 彼女は他のメンバーを呼び寄せてそれを見てもらいます。 みんなが納得するようなできばえであることがわかれば、 バージョン管理システムを使ってその跳ね橋をみんなのお城に移植 ("マージ")するのです。

共同作業を進めるうえでこの機能がいかに有用かは、 言うまでもないことでしょう。この機能を使えば、 「他の人に迷惑がかからないかな?」 なんて気にせずに思う存分新しいことを試せるのです。 同じくらい重要なこととして、 バグ修正や安定版リリースのためのブランチを本流から隔離する (7章パッケージの作成、リリース、日々の開発 「リリースを安定させるプロセス」「複数のリリースラインを管理する」 を参照ください) ということがあります。 そうすれば、それぞれの流れを追いやすくなります。

偏見を捨て、ブランチを積極的に使うようにしましょう。 そして、他のメンバーにもブランチの使用を推奨しましょう。 しかし、不要になったブランチはいつまでも残しておかないようにしましょう。 ブランチが増えれば増えるほど、コミュニティー内での注目が散らばってしまいます。 そのブランチとは直接関係のない開発者であっても、 周りで起こっていることを気にせずにはいられないでしょう。 無理もありません。もちろん、 ブランチに対するコミットであってもコミットメールは同じように送ります。 しかし、ブランチは開発者のコミュニティーを分断する仕組みとなるべきではありません。 わずかな例外を除いては、 初期の目的を達成して本流にマージした時点でブランチを削除するようにしましょう。

情報の一元管理

ブランチが重要だということは、当然マージ処理も重要になってくるということです。 同じコミットを2回繰り返すなんていうことがないようにしましょう。 つまり、ある変更がバージョン管理システムに投入されるのは1回だけにしておくということです。 そうしておくことで、ある変更に対応するリビジョン(あるいはリビジョン群) が一意に決まるようになります。その変更と同じ内容を別のブランチにも適用したい場合は、 そのブランチ上でもまったく同じように手を加えてそれをコミットするというのではなく、 最初の変更をマージするようにしましょう。 手作業で同じように修正したものをコミットしても結果は同じですが、 そうすると正確なリリース管理ができなくなります。

この件に関する実際のアドバイスは、 使用するバージョン管理システムによって異なります。 あるシステムでは、「マージ」は特別な処理として扱われ、 通常のコミットとは別のものとなります。 そして独自のメタデータを保持します。 また、システムによっては、 マージした結果を通常のコミットと同様に適用するものもあります。 このようなシステムでは、「マージした結果のコミット」と 「新しい変更のコミット」の区別はログメッセージで行います。 マージした際のログメッセージには、 元の変更の際のログをそのまま繰り返してはいけません。 そうではなく、「この変更はマージである」ことと、 どのリビジョンをマージしたのかを簡単に記述するようにします。 実際の変更内容を知りたければ、 マージ元のログメッセージを見るようにするわけです。

ログメッセージの重複を避けるのがなぜそんなに大事なのかというと、 ログメッセージは後から修正される可能性があるからです。 同じ内容のログを繰り返し記述していると、 だれかが元のログメッセージを修正したときに コピー先のメッセージがそのままになってしまう可能性があります。 後から見たら、これは非常にややこしい状況になります。

同じ原則は、変更を取り消す (revert) 際にもあてはまります。 ある修正が廃案になったときのログメッセージは、 単にそれが revert されたということだけを記述します。 実際に何をどのように戻したのかまでを書いては いけません。だってそれは、 もともとその変更を行った際のログを見ればわかることなんですから。 もちろん「なぜ」取り消したのかという理由の説明は必要でしょう。 しかし、元の変更の際のログメッセージを一言一句書き写す必要はありません。 できれば、元の変更の際のログメッセージも修正し、 それが結局取り消されたことを記述しておくとよいでしょう。

これまで説明してきたことからも何となくお分かりでしょうが、 特定のリビジョンを参照する際の表記方法は統一しておいたほうがいいでしょう。 これは、ログメッセージだけでなくメールやバグ追跡システムなどでも同じです。 CVS を使っているのなら、 "path/to/file/in/project/tree:REV" という形式をお勧めします。ここで、REV は CVS のリビジョン番号 (たとえば "1.76" など) を指します。 Subversion を使っているのなら、(たとえばリビジョン 1729 の場合の) 標準の表記法は "r1729" となります (ファイルのパスは不要です。 Subversion はリポジトリ全体でリビジョン番号を管理するからです)。 それ以外のシステムでもきっと、 チェンジセットを表すための標準形式があることでしょう。 ともかく、メンバーには標準の形式を使ってもらうようにしましょう。 この表記法を統一しておくと、後からプロジェクトの流れを追うのが簡単になり (6章コミュニケーション7章パッケージの作成、リリース、日々の開発 で説明します) ます。 これらの管理を行うのはたいていはボランティアなので、 できるだけ簡単に進められるようにしておくことが重要です。

7章パッケージの作成、リリース、日々の開発「リリースと日々の開発」 もご覧ください。

承認

たいていのバージョン管理システムには、 特定のユーザーに対してリポジトリ内の特定の場所だけのコミットを許可したり 逆に拒否したりといったことをする機能があります。 「ハンマーを与えられたら、人はみんな周囲の釘を探すようになる」 という原則どおり、多くのプロジェクトでこの機能が使われてきました。 アクセス権を注意深く管理し、特定の場所にだけコミット権を与えて 他の場所は触らせないようにするといった具合です (8章ボランティアの管理「コミッター」 で、 コミット権の管理方法について説明しています)。

このように厳格に管理してしまえば、悪影響が出る可能性を減らせることでしょう。 しかし、もうすこし緩やかな方針でもかまいません。 プロジェクトによっては、緩やかな方針を採用しているものもあります。 たとえリポジトリの一部分のみへのコミット権を与えられたユーザーであっても、 設定上はリポジトリ全体を変更できる権限を与えるというものです。 ただ「コミットするのはこの範囲だけにしておいてね」とお願いするだけです。 こうしたところで、実害はないことを覚えておきましょう。 ふつうのプロジェクトなら、すべてのコミットは何らかの形でレビューされます。 誰かが予期せぬコミットをしたら、 それを見つけた人が何かコメントすることでしょう。 その変更を取り消すべきだと判断したのなら、やることは簡単です。 すべてバージョン管理されているのだから、 単にその変更を取り消せばいいだけのことです。

緩やかな方針にしておく利点はいくつかあります。 まず、ある開発者の権限を拡張する (プロジェクトに長年かかわっていると、よくあることです) 場合に一切手間がかからないということです。 単に「今日からは、ここもコミットしていいよ」というだけで、 後はすぐにコミットできるようになります。

次に、より緻密な方法で権限の拡張ができるようになります。 一般に、エリア X のコミッターがエリア Y にもコミットしたいと考えた場合は、 まず Y に対するパッチを投稿してレビューしてもらうことになります。 すでに Y へのコミット権を持つメンバーがそのパッチをレビューして承認したら、 パッチを投稿した人に対して「直接コミットしてもいいよ」と伝えます (もちろん、誰がレビューして承認したのかという情報は ログメッセージに残しておきます)。 この方法だと、実際にパッチを書いた人がコミットをすることになります。 これは、情報管理の面でも功績をたたえる意味でも重要です。

最後に、最も重要なのが、この緩やかな方式を採用すると お互いに信頼し、尊重しあう空気が生まれるということです。 この方式の場合、「君はこの部分にコミットする能力があることがわかった。 ぜひコミットしてくれ」というようにとられます。 厳格に管理してしまうと「君のできることには制限があるんだ」 ということを強調するだけでなく 「間違って変なことをしてしまわないかどうかが心配なんだ」 と疑っているように感じられてしまいます。 できればこのようなことは避けたいでしょう。 だれかを新たにコミッターとして迎え入れるということは、 みんなの信頼の輪の中に新しいメンバーを加えるということです。 その際には、本来必要なもの以上の力を与え、 「それをどう使うかはあなたしだい。でもこれ以上のことはしないでね」 としたほうがいいでしょう。

Subversion プロジェクトでは、かれこれ 4 年以上この「緩やかな管理」 方式を採用しています。本書の執筆時点で、フルコミッターは 33 人、 一部にだけコミット権限のあるメンバーが 43 人います。 この管理方式では、システムが管理するのは「コミッターかそうでないか」 だけです。その詳細 (どの部分にコミット権があるかなど) は人間が管理します。 今のところ、コミット権のない部分について故意にコミットするなどといった 問題は発生していません。コミット権に関する誤解が生じたことも何度かありましたが、 いつも速やかに円満解決していました。

このような自己管理方式が明らかに現実的でない場面もあるでしょう。 当然、そんな場合は厳格な管理が必要となります。 とはいえ、そんな状況はまれです。 たとえ何千人の開発者が何百万行のコードを扱っていたとしても、 そのコードに対するすべてのコミットはだれか他の人によるレビューを受けます。 おかしなコミットがあればすぐに指摘されるでしょう。 もしコミットをレビューしあう習慣ができていないのなら、 それは認証システムがどうのこうのいう以前の問題です。

まとめると、よっぽどの理由がない限りは バージョン管理システム上のアクセス権限にあまり気を使う必要はないということです。 厳密に管理したところで得られる具体的なメリットはあまりありません。 それより人間による管理に頼ったほうが得られるものは多いでしょう。

もちろん、制限をすること自体が無意味だといっているわけではありません。 権限のないところへコミットさせるようなことは、あまりしたくないでしょう。 さらに、多くのプロジェクトでは「フルコミッター (制限のないコミッター)」 には何らかの特権 (たとえばプロジェクトの運営に関する投票に参加できるなど) が与えられています。コミット権の扱いに関する政治的な意味合いについては 4章プロジェクトの政治構造と社会構造「誰が投票するのか?」 で詳しく説明します。



[19] configure ファイルをバージョン管理するか否かについては、 別の見方もあります。Alexey Makhotkin の記事 "configure.in and version control" が、次の URL で見られます。 http://versioncontrolblog.com/2007/01/08/configurein-and-version-control/