初期データのインポート

GNU arch の初期インポートの典型的なユースケースは三種類ある。

以下では最初の利用方法について説明する。二番目については次章 のインベントリの議論を通じて説明し、最後のものは分岐の章で説明しよ うと思う。初期設定に関してだけ言えば、二番目のケースが一番面倒で、 最後のものは一番簡単だ。

概論

バージョンを作ったら、あとは初期データをそこにインポートす るだけだ。「インポート」とは、これまでバージョン管理下 になかったひとまとまりのデータを、最初にバージョンに格納することだ。 このひとまとまりのデータは、全体としてひとつのディレクトリにまとめ られていなければならない。格納したいデータの一部があるディレクトリ にあり、残りのデータがそれとは親子関係のないディレクトリにあるよう な場合、そのままの形ではインポートすることはできない。このような場 合は管理対象の単位をそれぞれに分割するか、新しいディレクトリの中に 両者のコピーを作り、それをインポートする必要がある。このようにして まとめたデータの最上位のディレクトリをツリーのルートと言い、この領 域全体をツリーと言う。

ツリーの中にはどのような名前のファイルを置くこともできるし、 またそれらがどのようなファイル形式であっても良い。ファイル形式は非 常に大きくテキストファイルとそれ以外のバイナリファイルに区別できる ことはすでに述べた。そこでバージョン管理対象として差分管理をする場 合にはテキストファイルが向いているという話をしたが、GNU arch の場 合、バイナリファイルも管理することができる。ただしこれはとにかく管 理することはできる、といった程度の話であって、バイナリファイルに対 しては GNU arch は特に優れた性能を発揮するわけではない。たとえばこ れもすでに述べたことだが、バイナリファイルを管理する場合、リビジョ ン間の差分を人間に理解可能な形で直観的に示すことはできない。できる ことは現在または過去の指定されたリビジョンのバイナリファイルをその まま取り出すことだけだ。

GNU arch でバイナリファイルを管理するのは、大部分がテキスト ファイルだが、その一部がテキストファイルに付随したバイナリファイル であるような場合が多い。たとえば君が編集している HTML ファイルがあ るドキュメントルート配下を GNU arch で管理しつつ、HTML ファイルが 参照する一部のアイコンや小さな画像などを同時に管理対象としたいよう な場合が考えられる。あるいは、このドキュメント自身を考えてみてほし い。このドキュメント自身、何を隠そう tez@kamihira.com--2004s/Book--GNU-arch--0.0.1というバージョンで管 理される立派なアーカイブだ。この中身はと言えば、ほとんどが XML 文 書、つまりはテキストファイルで、文書中に現れる画像は OpenOffice の Impress というバイナリファイルから生成した png 形式のバイナリファ イルだ。両方とも Book--GNU-arch--0.0.1 の一部としてバージョン管理 されている。

ツリーの中のすべてのファイルとディレクトリがバージョン管理対 象下に置かれるわけではない。もちろんそうすることもできるが、実際に は管理したくないファイルやディレクトリが混じっていることがよくある。 たとえば、C 言語の開発をしていて、ディレクトリにいくつかファイルが ある場合、コンパイルの中間結果の *.o のような形のファイルや、エディ タのバックアップファイルなどはバージョン管理したくはないだろう [7]。あるいは 自分専用のメモ書きファイルのようなものがツリー中に含まれていてその ファイルについては広く公開したくないこともあるかも知れない。インポー トする前には、どのファイルをバージョン管理下におき、どれをバージョ ン管理外にするかをあらかじめ指定する必要がある。

GNU arch ではこの指定をするには、まずは管理対象とするツリー を tla init コマンドを利用して、GNU arch 管理可能なプロジェクトツ リーの形に変えなくてはならない。プロジェクトツリーとは、GNU arch の管理領域用のディレクトリ{arch} を最上位に含むようなツリーのこと だが[8]、この {arch}ディレクトリ中の設定ファイル、 =tagging-method[9]の内容によって指定するた めだ。tla init コマンドは {arch} 管理領域をツリーのルートに追加す る以外のことは一切しない。

利用するサンプルプログラム

さて、そろそろ、何か良いデータのサンプルが必要になる。GNU arch はどのような種類のデータも管理することができるが、やはりプ ログラム言語のソースコードを管理することが多いので、C 言語のプロ ジェクトで説明しようと思う。複数のファイルを管理できることと、サ ブディレクトリも管理できることを示すため、四つのファイルからなる プロジェクトを考えることにする[10]。このプロジェクトは 4 っつの 通常ファイルと、それらを編成するための二つのサブディレクトリから なっている。以下のようなものだ。

$ pwd
/home/octopus/proj
$ find
.
./lib
./lib/tools.c
./inc
./inc/tools.h
./main.c
./cc.sh
$

main.c は tools.c にある関数を呼び出している。

$ cat main.c
#include "./inc/tools.h"

int main()
{
        hello_world();

        return (0);
}
$

呼び出される側の lib/tools.c は printf() で文字列を表示する だけだ。

$ cat lib/tools.c
#include <stdio.h>

void hello_world()
{
        printf("hello world\n");
}
$

lib/tools.c のプロトタイプ宣言は inc/tools.h にある:

$ cat inc/tools.h
void hello_world();
$

コンパイルは cc.sh という小さなスクリプトで行う。

$ cat cc.sh
#!/bin/sh

cc -o hw main.c lib/tools.c
$

とても単純だ。先に進む前にプログラムが本当に動作するかどう か確認しておこう。いまの例をエディタで実際に作成した場合には、 cc.sh を実行可能とすることに注意してほしい。その後、コンパイルし、 実行を確認する。

$ chmod +x cc.sh
$ ./cc.sh
$ ls
cc.sh  hw  inc	lib  main.c  {arch}
$ ./hw
hello world
$ 

コンパイルによって hw という実行ファイルが作成された。確かに 動作している。

初期インポート作業(1) - tla init-tree

では話を戻して、このディレクトリを、プロジェクトツリーに変え、デフォル トバージョンを前の節で作っておいた test--proj--1.0 に設定する。 これには tla init-tree を使う:

$ ls
cc.sh  inc  lib  main.c
$ tla init-tree test--proj--1.0
$ ls
cc.sh  inc  lib  main.c  {arch}
$ tla tree-version
octopus@bluegate.org--2004/test--proj--1.0
$

{arch}という管理用のサブディレクトリができた。tla tree-version はデフォルトバージョンを表示するためのコマンドだ。確 かに test--proj--1.0 になっている。tla init-tree コマンドはアーカ イブの領域に対しては何も変更していない—参照すらしていない —ことに注意してほしい。このコマンドはあくまでもいま作ったプ ロジェクトツリーが、デフォルトで test--proj--1.0 バージョンに関連 づいていることを指定しただけだ。

初期インポート作業(2) - tla id-tagging-method

tla init-tree を済ませたら、IDタグづけの方法を選択しなくて はならない。IDタグづけの方法については次章で詳しく説明するが、プ ロジェクトツリー中のどのファイルをバージョン管理対象とみなしどれ をそうみなさないかを決める方式のことだ。これには name, tagline, explicit の三種類がある[11]現在の IDタグづけの方法を表示す るには引数なしでこのコマンドを実行する:

$ tla id-tagging-method
explicit
$ 

explicit になっている。ここでは説明のために最も簡単なnames の方式に設定することにする。設定する場合には引数で指定すればよい:

$ tla id-tagging-method names
method set: names
$ tla id-tagging-method
names
$ 

これで names になった。

初期インポート作業(3) - インポートファイルの確認

IDタグづけの方法の設定が済んだら tla inventory コマンドを 使って実際のインポート対象となるファイルを確認する:

$ tla inventory
S  cc.sh
S  hw
S  inc/tools.h
S  lib/tools.c
S  main.c
$ 

S という文字はソースファイル、つまりバージョン管理対象とな るファイルを意味する記号である。この他にも P,B,J,T,U で表される 状態がある。それぞれ、プレシャス、バックアップ、ジャンク、ツリー、 アンリコグナイズ(非認識)の意味だ。詳しくは次章で説明する。

上記の一覧の中で、hw というファイルがソースファイルだと認 識されているが、これはコンパイルの結果できたファイルであり、管理 対象としなくはない。ファイルを管理対象外とするには {arch}/=tagging-method というファイルを編集し、exclude で始まる 行の内容を調整する。{arch}/=tagging-method という文字列の並びは 何度見ても気持が悪いかも知れないが、れっきとした普通のファイルで ある。vi を使っているなら:

$ vi {arch}/=tagging-method

emacs を使っているなら:

$ emacs {arch}/=tagging-method

でうまく編集できるはずだ。試してみてほしい。このファイル中、 exclude で始まる行があるはずだ。私の環境では以下のようになってい た:

exclude ^(.arch-ids|\{arch\}|\.arch-inventory)$

これは正規表現という決まりにしたがって記述された行で、「. arch-ids または {arch} または .arch-inventory という名前のファイ ルはソースファイルから除外してください」という意味になる。正規表 現についてあまり詳しくない人は、GNU arch で利用するための最低限 度の説明を補遺にしておいたので読んでみてほしい。しかし、カンが働 く人なら正規表現を知らなくても、hw を除外するにはどうしたらよい か、あたりをつけることはできるだろう。そう、以下のようにしてやれ ばよいのだ:

exclude ^(hw|.arch-ids|\{arch\}|\.arch-inventory)$

先頭のほうに、"hw|" という文字列を追加したのがわかる。これ でファイル保存でエディタを抜け、もう一度 tla inventory コマンド の出力を見てみよう:

$ tla inventory
S  cc.sh
S  inc/tools.h
S  lib/tools.c
S  main.c
$ 

hw がいなくなってくれた。ソースファイルから除外されたのだ。 これでインポートの準備がやっと整った。=tagging-method ファイルを 編集して気がついたと思うのだが、このファイル中には exclude 行の 他にもいろいろと怪しいことが書かれている。このあたりについても次 章でじっくり説明するので楽しみにしていてほしい。

初期インポート作業(4) - インポート

おまたせしました、と心から言いたい気分だ。どうして使い始め からこんなに複雑なのだろう。たかがバージョン管理システムだろう。 俺にとってはただの手段でしかないんだ。こむつかしいこといいなさん な、こっちはとっとと使いたいだけなんだよ、と。そう感じているなら、 たぶんあなたは正常な人間だ。でも忍耐もここまでだ。インポート処理 自体は、まるでアレキサンダー大王の最後みたいにあっけない。

$ tla import
* imported octopus@bluegate.org--2004/test--proj--1.0
$ 

あまりにあっけなくて本当にインポートできたかどうか不安にな る。確認する方法はいくつかある。まずは、アーカイブ全体のようすを ざっと見るための tla abrowse コマンドを実行すること。

$ tla abrowse
octopus@bluegate.org--2004
  test
    test--proj
      test--proj--1.0
        base-0

$ 

base-0 という表示があるだろう。これは最初のリビジョンの名 前だ。確かに作成されているようだ。余談になるが abrowse コマンド 出力が、カテゴリ名、ブランチ名、バージョン名のような階層構造っぽ く表示されているのにだまされないでほしい。すでに言ったように、実 際にはこれらの間に強い階層構造はない。

tla abrowse コマンドの出力でも安心できない場合には、実際に アーカイブ中の base-0 リビジョンを今のプロジェクトツリーとは別の 場所に取り出してみればよい。これには以下のように tla get コマン ドを使う:

$ pwd
/home/octopus/proj
$ cd ..
$ ls
ARCHIVES  proj	tla-1.2  tla-1.2.tar.gz
$ tla get test--proj--1.0 hogehoge
* from pristine cache: octopus@bluegate.org--2004/test--proj--1.0--base-0
* making pristine copy
* tree version set octopus@bluegate.org--2004/test--proj--1.0
$ ls
ARCHIVES  hogehoge  proj  tla-1.2  tla-1.2.tar.gz
$ cd hogehoge
$ ls
cc.sh  hw  inc	lib  main.c  {arch}
$ 

ホームディレクトリに戻って、hogehoge というディレクトリに base-0 リビジョンを展開してみた。やはりうまくインポートできてい るようだ。でなければうまく取り出せるわけがない。納得できたら hogehogeを消しておこう。せっかく get コマンドが出てきたので少し 補足するが、get コマンドを最後の引数なしで実行してみよう。

$ pwd
/home/octopus/hogehoge
$ cd ..
$ ls
ARCHIVES  hogehoge  proj  tla-1.2  tla-1.2.tar.gz
$ rm -rf hogehoge
$ tla get test--proj--1.0
* from pristine cache: octopus@bluegate.org--2004/test--proj--1.0--base-0
* making pristine copy
* tree version set octopus@bluegate.org--2004/test--proj--1.0
$ ls
ARCHIVES  proj	test--proj--1.0--base-0  tla-1.2  tla-1.2.tar.gz
$ tla get test--proj--1.0
get: output directory already exists (/home/octopus/test--proj--1.0--base-0)
$ 

言いたいことはこうだ。展開先ディレクトリを指定しないと、 tla get は バージョンにリビジョン名をつなげたような名前のサブディ レクトリ—いまの場合だとtest--proj--1.0--base-0—を作っ てそこにリビジョン内容を展開すること、展開しようとするディレクト リがすでに存在する場合にはそれを上書きすることはないということ。 展開先ディレクトリは必ず新しく作成されなくてはならない、というこ と。確認したらディレクトリを消しておこう。

$ ls
ARCHIVES  proj	test--proj--1.0--base-0  tla-1.2  tla-1.2.tar.gz
$ rm -rf test--proj--1.0--base-0
$ ls
ARCHIVES  proj	tla-1.2  tla-1.2.tar.gz
$ 

もう信じてもいいだろう。我々は確かに base-0 という最初のリ ビジョンを手に入れたのだ。プロジェクトツリーとアーカイブの様子を 図で示すと以下のような感じになっている。

図 3.4. プロジェクトツリーとアーカイブ

プロジェクトツリーとアーカイブ

プロジェクトツリー(今の場合 /home/octopus/proj)を削除して もアーカイブ中にできた base-0 は影響を受けないことに注意しよう。 プロジェクトツリーとは君が汗を流し、呻き、額を打ちつけ、格闘しつ づける、おがくずと鉄の切りくずが散らかる、油の匂が漂う泥くさい 「作業場」なのだ。あとで君のアーカイブからしみ一つない理路整然と したソースファイルを tla get で取り出した人間には、君のそんな姿 などおそらく想像もつかないだろう。だがそれでいいのだ。それが本当 の美学なのだから。



[7] emacs エディタなら foo~ とか #foo.bar# のような雰 囲気でディレクトリに残ることが多い。

[8] CVS で言う、CVS ディレクトリにあたる。

[9] これは通常のエディタで編集可能なテ キストファイルである。

[10] 正直言って、このサ ンプルは明らかに改良が必要だと考えている。汎用的なデータを管理で きると言っておきながら結局プログラム言語を例としなくてはならない ことについては本当に申し訳ない気がする。もっと実践的でプログラム に依存しないような汎用的な例でこのサンプルは書き換える必要がある と感じている。

[11] 正確には現在では利用され ないが下位互換性を維持するための implicit という方法もあるがここ では扱わない。