差分と複数のファイル

ここまでのところをまとめさせてほしい。まず、デジタルデータに は時間の経過と共に変化するタイプのものがあって、それを管理したい場 合にはバックアップを随時とって名前をつければ良いのだが、それだとバー ジョン間の差分をすぐに知ることができない。でも一部のデジタルデータ は良い性質を持っていて、いつでも二つのバージョン間の差分を人間が理 解できる形に計算することができる。こういうファイルのことをテキスト ファイルと呼ぶ。そういうことだった。ここから先は、議論の対象になる ファイルはいつでもテキストファイルであるとする。それから、バージョ ンのことをリビジョンといいXXX、それぞれのリビジョンを、R-0, R-1, R-2 ととおし番号で呼ぶことにする。混乱してきたら、R-0 とかは日付と時間 の入ったファイル名のことだと思い出してほしい。たとえば ... という 具合だ。

さて、前の節で示した、二つのリビジョンの間の差分をとるプログ ラムの話だが、別にこれは私が作ったプログラムじゃない。何十年も前に ハッカーたちが協力して知恵を出し合ってつくったもので、GNUdiff とい う名前のプログラムだ。「グニューディフ」と読む。何でこんな奇妙な名 前なのかは話すと長い。単に「ディフ」と言っても通じる。それから、こ のディフとペアになったもう一つの有名なプログラムがある。それは GNUpatchと言う。「グニューパッチ」と読む。こちらも「パッチ」と言え ばその手の人たちには通じる。ディフの方はもう説明した。パッチはこれ とちょうど逆のことをするプログラムだ。つまり、あるリビジョンと、差 分を与えて、変更後のリビジョンを復元するプログラムだ。つまり:

図 1.3. 一列に並んだリビジョン

一列に並んだリビジョン

のようになっているとき、R-0 と R-1 を GNUdiff に渡すと、R-0 とR-1の差分を計算してくれる。これを diff(R-1,R-0)と書くことにする。 R-1 のほうを先に書くのは、差分をとる処理がちょうど引き算に似ている から、R-1 引く R-0 という目で見たいからだ。GNUpatch は GNUdiffの ちょうど逆のことをする。つまり diff(R-1,R-0)とR-0 を渡すと、R-1 を 復元してくれるのだ。

図 1.4. GNUdiff の処理イメージ

GNUdiff の処理イメージ

図 1.5. GNUpatch の処理イメージ

GNUpatch の処理イメージ

diff(R-1,R-0)なんて書いても、ピンとこないかも知れないが、前の 節のドキュメントの差分を思い出してほしい。あの形のものを指している だけだ。いちいちあの表示を書いていたら紙が持たない(本当は紙じゃな いけど)し話がまわりくどくなってしまうので、ご勘弁願いたい。R-0 とか R-1も、例の 15000行のドキュメントにちょこちょこ修正が入ったようなものを イメージしてほしい。ああいうものを指している記号だ。話は脱線するが、 シンボルの力は偉大だと思う。「車」と書けば、実際の車を用意しなくて も車について語ることができるし、「宇宙」と書けば、実際に宇宙を用意 しなくてもとりあえずは宇宙について語ることができる。時には話をは しょった見返りに、実物にでくわした時に、手痛いしっぺ返しを受けるこ ともあるわけだがそれはまた別の話だ。

さてここまで道具立てがそろうと、この章の最初のバージョン管理 の手法、つまり単なるバックアップファイルの蓄積より、もう少しスマー トな管理手法をとることができる。バックアップファイルほどディスクを 消費しないし、同時にリビジョン間の差分を即座に見てとれるという一石 二鳥の方法だ。それをこれからお見せしよう。

まず、元のバックアップ手法のリビジョンを一列に並んだところを もう一度思い浮かべてほしい。各リビジョンでの修正量が少なければ、こ れらのデータはよく似ているのだった。これらのリビジョンの隣り合う二 つに対して、GNUdiff を呼び出して、差分を求める:

図 1.6. 隣り合うリビジョン間への GNUdiffの実行

隣り合うリビジョン間への GNUdiffの実行

そして、命知らずにも、R-1 から R-3 までのファイルを削除する。 すると以下のようなファイルが残る

図 1.7. 最初のリビジョンと差分の集まりだけを残したところ

最初のリビジョンと差分の集まりだけを残したところ

d(rN,rN+1)の形のファイルは普通はとても小さい。前の例の行数を 実際に数えてみてほしい。30行にも満たない。これに対して、R-0, ... R-3 のようなファイルは非常に大きい。修正の量にもよるが、どれも大体 15000行 くらいだろう。だから、バックアップ方式だと 15000 × 6 = 90000行のデータを保管しなくてはならない。一方、差分は普通はどれも 小さい。余裕を見て平均 60 行としておこう。それでも R-0 と差分の全体 では、15000 + 5 * 60 = 15300 行にしかならない。ほとんど R-0 そのも ののサイズではないか。差分の内容はすぐにわかるし、データサイズも小 さくて済む。あとは各リビジョンをうまく復元できるかどうかなのだが、 GNUpatchを使えば求めることができる。まず R-0 はすでに手にしている。 R-1 は、R-0 と diff(R-1,R-0)をGNUpatchに渡せば求めることができる。R-2 はいま求めた R-1 とdiff(R-2,R-1)を再び GNUpatchに渡せばいい。こんな風 に繰り返しGNUpatchを呼び出せば、リビジョンの数がどんなに増えてもい つかは欲しいリビジョンが求まる。図で書くとこうだ。

図 1.8. GNUpatchによる各リビジョンの復元

GNUpatchによる各リビジョンの復元

でも、R-0 と diff(R-1,R-0)... などから次の R-4 を作るにはど うしたらいいんだろうか? それにはこうする。まず今いった方法で何回も 繰り返し GNUpatch を呼び出して R-3 を作る。そしてこれを R-4 という 名前にコピーする。このままではまだ R-4 は R-3 と一緒だ。それから、 例の冷や汗もののレビューで君はこの R-4 に修正を加えて保存する。こ れで晴れて R-4 ができた。それからさっきよけておいた R-3 と R-4 の 差分 diff(R-4,R-3) を GNUdiff を使って計算する。これを差分のリスト に追加して R-3 と R-4 を削除する。これでおしまい。

今回の差分作戦の基本は以上だが、この発想の上でいろいろな改良 を加えることはできる。たとえば、差分ファイルでディレクトリやフォル ダが一杯になってしまうのを防ぐために、R-0 と残りの差分全体を一つの ファイルにまとめてしまえるような、新しいファイルの形式を定義してや る。そしてGNUpatchとGNUdiffをうまく改造して、この新しいファイルか らデータを取り出したり、好きなリビジョンを取り出せるようにしてやる。 複数のファイルをアーカイブというソフトを使って一つにまとめた経験は ないだろうか、ちょうどあんな感じだ。

図 1.9. 差分の集まりをひとつのファイルにまとめた様子

差分の集まりをひとつのファイルにまとめた様子

これでいくら差分ファイルが増えていっても、その新しいファイル の内容がどんどん増えるだけで、ディレクトリがファイルで一杯になった りすることはなくなる。それから、差分の内容をすぐに思い出せるように、 差分のそれぞれに小さなメモつけることができるようにしておく。バージョ ン管理システムの世界では、このようなメッセージをログメッセージとか、 単にログとか呼ぶ。ちょうど好きなカセットテープのケースに「いとしの あゆ」とか書くのと一緒だ。こうしておけば、この一つのファイルの中に、 このファイルが最初のリビジョンから現在にいたるまで辿ってきた、すべ ての歴史が刻まれていることになる。そしてインディージョーンズが謎の 古代文字を解読するように、君はすべての過去にアクセスし、そこに流れ る人の思いを辿ることができるのだ。このような仕組みを作るための具体 的なプログラムをイメージできないとしても、おおよその雰囲気はわかっ てもらえるのではないかと思う。

さらにいろいろな改良を加えることができる。いままでの例ではたっ た一つのファイルをバージョン管理してきたが、一般には複数個のお互い に関連のあるファイルを一緒に管理することが多いだろう。たとえば 15000行の一つのドキュメントはいかにも大きすぎる。このドキュメント が 3 章からできているのなら、三つのファイルに分けて管理したほうが 楽だろう。ディレクトリ中にはファイルごとの差分がどんどんできていく が、いま述べたようにもとのファイルとそのファイルの差分を一つのファ イルにまとめる手法を使えば、いつまでたってもディレクトリのファイル の数は 3 個のままだ。こうしてバージョン管理の対象は単一のファイル からあるディレクトリ全体という、より豊富なデータ構造に移ることにな る。そして単一ファイルのバージョン管理は、たまたまバージョン管理す るディレクトリに一つのファイルだけが存在するという特殊なケースとみ なすことができる。

細かい、と君は言うかも知れない。あんたの言うことは細かい。要 するに、こう言いたいんだろう。バックアップファイルをたくさんとるか わりに、もっと効率が良くて、変更点もすぐにわかる一石二鳥の方法があ ると。それを使うにはなんとかって言う二つのプログラムを使えばいい、 と。やり方はこれこれ、こうだ、と。あとはこのやり方にしたがって、そ のグニューなんとか をうまく組み合わせたプログラムを作ってくれ、と。 しかし、だ、これじゃ、エンジンのパーツ一式とドライバとスパナを俺に 渡して、はい、さようならって言ってるようなもんだ。いいか、言っとく けど俺はプログラムのことなんてぜんぜん知らない。あんたには簡単かも 知れないけど、俺はそんなもん組み立てたことなんてない。できるやつに 頼めって? なるほど、会社にはすごい詳しいやつが二人いる。特にその一 方はすごいらしい。俺には二人とも同じように、なんだかすごい連中だと しか見えないが、その滅多に口を利かない片方が、もう一方のことを天才 と言うんだ。だからおそらく相当すごいやつなんだろう。しかし、だ。俺 はこいつが気に入らない。ピカイチ気に入らない。人を見下してばかりい る嫌な野郎だ。俺にはわかる。ああいう奴にはプログラムが組めない人間 はみんなバカに見えるんだ。なにさまのつもりだ。はっきりいってこんな 男にモノを頼むくらいなら、舌を噛み切って死んだほうがよっぽどましだ。

なるほど、かなり深刻そうだ。しかし、実際には油まみれになって エンジンを組み立てる必要もないし、少なくともこの件では君も命を落と さずに済む方法がある。ちょっとわざとらしいのだが、実はいま君がまさ に言ったようなものを、すでに組み立ててくれた人がいるのだ。人という のは正確じゃないかも知れない。人々、それも大勢の人々、しかも長い時 間をかけて、しかも大した見返りもなしに、だ。このいきさつと経緯につ いての物語は、それ自体とても面白いのだが、別の機会に譲ろうと思う。 とにかくここから先、もう君は GNUdiff と GNUpatch のことを、近所の ゲーセンにおいてある 2ゲーム100円のリセットボタンみたいにきれいさっ ぱり忘れることができる。テレビの中のごちゃごちゃした部品についての 知識がなくてもリモコンをいじれば、なんだか知らんがテレビは見れるし、 百円玉を自動販売機に突っ込めば、なんだか知らんがコーラが出てくる。 同じことだ。スイッチポンで脱水、乾燥、柔軟仕上げ。かしこい主婦なら 迷わずえらぶ全自動洗濯機みたいなソフトがある。それが CVS、コンカレ ントバージョンシステム、だ。次の節ではこのソフトについて少し話をし ようと思う。ところで君んとこのイヤな野郎の話だが、そいつが嫌なやつ だからって、コンピュータに詳しいやつがみんなそういう連中だなんて思 わないでほしい。君の専門が何か私は知らないが、どんな分野だって、本 物っていうのは決して多くはないものだ。私は言ったはずだ。公正廉潔な 女性もたくさんいるし、ピアスの似合う大物政治家だって、いるにはいる のだ。たぶん。