バージョンコントロールシステムの比較

提供: tknotebook
移動: 案内検索

このページはまだ正式に公開されていない下書きです。

まだ、間違いや嘘がたくさん混じっているはずです。

ご注意ください!!!

バージョンコントロールシステム(VCS)の基本

まずここではバージョンコントロールシステム(以降VCS)の基本的な考え方と用語について解説します。

リポジトリ

VCSは様々なファイルやディレクトリをひとまとめにしてそのバージョンを管理します。 このひとまとめにしたファイルやディレクトリなどの内容を集めたものをリポジトリといいます。

単にファイルやディレクトリを集めただけでは、それは単なるファイルシステムですが、 リポジトリの中のファイルやディレクトリには「歴史」が含まれており、 ファイルやディレクトリがいつ誰によって作られ、どのように変更されて行ったかが全て保存されています。

リポジトリの中には様々な時点のファイルやディレクトリの状態が、何らかの方法で全て保存されており、 ファイルやディレクトリを任意の時点の状態に復元することが可能です。

VCSのリポジトリの図.png

スナップショット

VCS はリポジトリにファイルやディレクトリの様々な時点の「状態」を再現することができますが、 特定の時点の全てのファイルやディレクトリの状態のことを、ここでは「スナップショット」 と呼ぶことにします。

「スナップショット」には全てのファイルやディレクトリの状態の他に、スナップショットを登録した人や登録日時 など様々な情報が追加されています。

スナップショットは

  • Subversion では リビジョン
  • Git では スナップショットコミット
  • Mercurial ではコミットチェンジセット

と呼ばれます。

スナップショットの実態は、隣の世代のスナップショットとの差分情報やファイルへのポインタ情報を中心にした小さなものであることが多いため、Mercurial のように まるで変更履歴のように言うこともあります。しかし、 スナップショットとは、その実体という観点では、リポジトリに含まれる、ある時点での全てのファイルとディレクトリを復元するのに必要な情報にたどり着くための情報のことです。

スナップショットとは論理的にはある時点での全てのファイルとディレクトリの状態+αとと考えてよいものです。 つまり、「スナップショット」という言葉通り、全てのフォルダとファイルのある時点での状態を切り取ったスナップ写真(記念写真)です。

Tip: Mercurial はフォルダ情報を保持しないため、空のフォルダは再現できず消えてしまいます。

リポジトリの歴史

歴史の形

リポジトリはスナップショットの集合体ですが、それだけでは VCS としてあまり役に立ちません。

我々が VCS を使うのはリポジトリの歴史をリポジトリに刻み、またリポジトリの歴史を辿りたいからです。 リポジトリに歴史があるので、われわれはVCSのなかから目的のスナップショットを選ぶことができるのです。

リポジトリの歴史とは、どのスナップショットを元に、次のスナップショットが作られていったかを示す一連の情報です。


VCS リポジトリの歴史.png


上図はリポジトリの歴史を模式的に表したものです。図中の丸はひとつのスナップショットを表しています。

左端の「開始」とかかれたスナップショットは、リポジトリに最初に登録されたスナップショットです。利用者はこのスナップショットをベースにファイルやディレクトリを修正/追加/削除して次々に新しいスナップショットを作成してリポジトリに登録してゆきます。

図ではスナップショットAは開始のスナップショットを修正して、スナップショットBはスナップショットAを修正して作られたものです。

矢印のバルーンコメントにどのような修正が有ったか書いてありますが、これも歴史に含まれる情報のひとつです。この情報ももちろんとても有用な情報ですが、最も肝心な歴史の情報は、どのスナップショットがどのスナップショットから作られたかということです。これが歴史全体の構造を決めます。

分岐

歴史は基本的にはスナップショットA、Bのように 直線的に延びて行きますが、 スナップショットCとDのように、同じスナップショットを修正して作られるものもあります。 このように枝分かれすることを、この記事では「分岐」と呼び、分岐する際の起点となるスナップショットを 「分岐点」と呼ぶことにします。

マージ

スナップショットEのように、2つのスナップショットを元に作られるスナップショットもあります。これをこの記事では 「マージ」と呼ぶことにします。マージとは2つのスナップショットを分岐点まで遡ってそれぞれのそれまでの修正を把握し、両方の修正を反映するように作ったスナップショットのことです。

スナップショットの作成は人手によるものですが、マージも例外ではありません。 マージの作成は、その大部分は VCS が自動的に行います。しかし、必ずしも全てを自動的に行えるものではなく、 時に両立しない修正を選んだり、新たにコードを編集しなおしたりしてコードの整合性を保つ人による作業が必要になることが あります。

矢印の向き

既にお気づきかと思いますが、スナップショットを結ぶ矢印の方向は過去(修正前)への方向になっています。 これには大きな意味はありません。GitというVCSが最近のスナップショットから過去に向かって歴史をさかのぼれるように リポジトリが作られているので、それを図に採用したに過ぎません。

このドキュメントでは、Gitに敬意を表し、この矢印の方向(過去方向)を採用することにします。

VCSの紹介

この記事では3種類のVCSについて考えます。

  1. Subversion
  2. Git
  3. Mercurial

です。

Subversion

略称

SVN

歴史

21世紀に入る直前、バージョン管理システムと言えば CVS でしたが、多くの問題を抱えるシステムでした。

Collabnet Inc. は 2000年、 Karl Fogel を含む数人を雇って、CVSの改善版の開発に乗り出し、 2001年の夏には、自分自身をバージョン管理できるほどの完成度に達しました。

Subversionは革新的な新しい VCS を目指しませんでしたが、CVSの抱える多くの問題を解決し、CVSの代替として広く普及しました。

特徴

Sunversion は中央リポジトリを提供するサーバと、ファイルやディレクトリを修正してリポジトリに登録するクライアントからなる クライアント/サーバシステムです。


完全なリポジトリはサーバ側にしかなく、クライアント側には、

  • リポジトリの最新のスナップショットの一部分(サブツリー)
  • スナップショットから取り出された、編集中のファイルやフォルダがある作業フォルダー

が有ります。

クライアントは作業フォルダとスナップショットの一部分(サブツリー) の比較結果をサーバの中央リポジトリに送り、スナップショットを登録する仕組みになっています。

このようにSVNは中央集権型のVCSですが、ローカルなスナップショットの一部分(サブツリー)も持っており、 スナップショットの一部分(サブツリー)を更新(update)すると、作業用フォルダも自動的に更新(人手によるコンフリクト処理もを含む)を するあたりは分散型のVCSと少し似ています。

上で解説した意味での「分岐」はサポートしておらず、SVNでは、リポジトリのサブツリーのコピーを利用者が分岐と見なすことで分岐を 疑似的に実現しています。

Git, Mercurial

略称

  • Git = git
  • Mercurial=Hg

歴史

どちらも Linux Kernel の開発のために作られた分散バージョン管理システム(Distributed Version Control System = DVCS)。 現在 VCS の主流の双璧です。

特徴

互いに模倣しあっているため双方の機能はかなり似通っています。

手元の変更を手元のローカルなリポジトリで管理する点は両者とも同じです。 変更を公にする前に、手元のバージョン管理を利用しつつ十分に内容や動作の確認が行えるのが分散管理型のVCSの大きな特徴です。 また、前述のリポジトリの歴史(分岐やマージなど)を積極的に VCS 自体が仕組みとしてサポートしている点が SVN とは異なります。

git と hg では管理の成果を共有する方法の考え方が違います。

git はローカルマシン上でのバージョン管理にローカルリポジトリ、バージョン管理の共有にリモートリポジトリというように リポジトリの役割分担が明確です。

hg は全てのリポジトリは対等であり、バージョン管理の共有をどのように運用するかは利用者の取り決め次第です。 必ずしも中央リポジトリは必要なく、任意のリポジトリ間で同期が可能です。

より野放図で自由なのが hg と言えるでしょう。

現在、Linuxの開発が git を採用していることもあり、人気は git が上回っていますが、hg も、そのシンプルさから 根強いファンが多くいます。OpenJDKのなど、多くの大きなプロジェクトのバージョン管理に hg が採用されていることは有名です。

3種の VCS の比較

分岐

分岐とは基本的にファイルやディレクトリのセットの複数の版を同時に管理することです。 つまりファイルやディレクトリのセットの複数の版に対し、それぞれ別々に修正を行うことができ、 別々にリポジトリから取り出すことができるということです。

例えば、あるソフトウェアのリリース 2.3 をリリースしたとしましょう。

開発部隊は次期 2.4 に向けて開発作業に入るでしょうし、2.3 に致命的なバグが見つかって Hotfix版を出す必要があるかもしれません。

すぐに対処不要でも、2.3 に対して、近日中に対処しなければならない課題やバグフィックスも 必要でしょう。

この場合、少なくとも、リリース2.3, HotFix版、課題/バグフィックス版、次期開発版 を 別々に管理する必要があり、適宜修正を他の版へ吸収する必要があります。

SVN

SVN での分岐はシンプルで原始的です。太古からおこなわれてきた方法「コピーをとる」です。

SVNではリポジトリ内で、リポジトリに登録されたファイル/ディレクトリのサブツリーを別のディレクトリに コピーすることを「ブランチを切る」と言います。実に単純な解決方法です。

原始的なやり方ですが、実はそれほどひどい方法ではありません。なぜなら リポジトリに登録済みのスナップショットはVCSというシステムの性質上リードオンリーなので、 コピーをとるといっても、ファイル/フォルダの参照のみをコピーするだけでよいからです。

SVN では、作業コピーにリポジトリのサブツリーだけをチェックアウトできるという SVN の特性に合わせて、 SVN Switch というコマンドでサブツリー、つまり分岐を切り替えて、作業コピーの内容を 選んだ分岐に応じて切り替えられます。

これは SVN Update と類似のアルゴリズムで行われるため、ファイル/フォルダの削除/追加/変更は 差のあるファイル/フォルダに対してのみ行われるため、大変高速です。

SVNのやり方の唯一の欠点は、それが単なるコピーだということです。 分岐を作成した意図が残りにくく、他のVCSのように、分岐の歴史が明確に残りません。

後で分岐をマージする場合、分岐の作成者、分岐の管理者の手助けが不可欠でしょう。