ラベル git の投稿を表示しています。 すべての投稿を表示
ラベル git の投稿を表示しています。 すべての投稿を表示

2010-12-28

ZSH のパス設定

以前、MacBook と Mac mini Server の間で git clone しようとして失敗したことがあった(→「MacBook にも Git を (あるいはリモートリポジトリの準備)」)。原因は、リモート側のシェルの PATH 設定だった。git でリモートリポジトリから SSH 経由で clone しようとする場合、リモート側で(SSH 経由で) git コマンドが実行される。リモート側のシェルのパスに git コマンドをふくむディレクトリが入っていなければ、git コマンドが見つからずエラーになる。

シェルは起動時に設定ファイルを読み込む(実行する)ことで実行環境を整える。このとき、たいていのシェルでは実行モードによって読み込む設定ファイルが変わる。実行モードというのはログインシェル、対話シェル、そしてスクリプト実行用シェルの 3 つのことで、git clone で起動されるシェルはスクリプト実行用シェルになる。このため、たとえ ssh コマンドでリモートログインした状態で対話的に git コマンドを使えたとしても、git clone しようとすると (git コマンドが見つからず)エラーになることがある。

今日も、MacBook と iMac の間で git clone しようとして同じエラーが出て失敗した。以前解決したはずの問題にまた遭遇したことになる。というのも、あれからしばらくしてシェルを zsh に変えたからだ(→「twitter より (2010-08-03)」)。最初の設定のときに、ssh コマンドでリモートログインしてローカルなシェルの場合と同様に使えることを確認して安心していた。今日まで git clone のようなリモートのコマンドを直接実行することはなかったから、この問題に気付かなかった。

では、zsh を使う場合リモート(のスクリプト実行用)のシェルが参照するパスを設定するにはどうすれば良いのか? より具体的に言えば、git のリモートリポジトリを置いたコンピュータのシェルが zsh のとき、git clone 等が失敗しないようにするにはどうすれば良いのか?

答えは ~/.zshenv

結論を先に書くと、スクリプト用シェルのために PATH を設定するには ~/.zshenv に書けば良い。書式は通常のシェルスクリプトと同じ。つまり、git clone が失敗する問題を解決するためには、リモート側(clone されるリポジトリがある方)に ~/.zshenv を作り、以下のように PATH の設定をしてやれば良い(git コマンドを MacPorts でインストールしている場合)。

export PATH=/opt/local/bin:/opt/local/sbin:$PATH

これまで、zsh のためのパスは ~/.zshrc で設定してきた。この方法どこが悪かったのだろう?

それは実行モードごとの設定ファイルの読み込みが以下のようになっているからだ(→「【コラム】漢のzsh (1) 最強のシェル、それは「zsh」 | マイコミジャーナル」参照)。一言で言えば、~/.zshrc はスクリプト実行用シェルのときは読み込まれない。

zsh の設定ファイル読み込み順序
実行モード 読み込み順
ログインシェル
  1. ~/.zshenv
  2. ~/.zprofile
  3. ~/.zshrc
  4. ~/.zlogin
対話シェル
  1. ~/.zshenv
  2. ~/.zshrc
スクリプト用シェル
  1. ~/.zshevn

これを見れば、スクリプト用シェルが参照する PATH は ~/.zshenv で設定しなければならないことがわかる。

~/.zshenv を読むより前に起きていること

さて、これで MacBook と iMac の間で git clone に失敗する問題は解決できたが、ついでに zsh における PATH の設定について調べてみた。

zsh の man ページによれば、シェルが起動時に最初に読み込むのは /etc/zshenv だとのこと。その後、上述の表のような順序で設定を読み込む。では、/etc/zshenv はどうなっているのか?

Mac OS X 10.6.5 の /etc/zshenv の内容を以下に示す。

# system-wide environment settings for zsh(1)
if [ -x /usr/libexec/path_helper ]; then
 eval `/usr/libexec/path_helper -s`
fi

ここに書いてあるのは /usr/libexec/path_helper があれば、それを実行しろというもの(バッククォート記法なので、正確には path_helper の実行結果をスクリプトとして実行しろ、となる)。

この path_helper というコマンドは PATH を設定するためのシェルスクリプトを生成するためのもので -s オプションで B-shell 用のスクリプトが作られる。man ページには直接実行するものじゃないゾ、と書いてあるが、そこをあえて実行してみた結果を以下に示す。実行の前に PATH と MANPATH の設定を消しているのは、このコマンドが現在の設定に追加するようになっているから。空にしておくことで、zsh が /etc/zshenv でこのコマンドを実行したときの結果がわかる。

[imac] mnbi% PATH=''
[imac] mnbi% MANPATH=''
[imac] mnbi% /usr/libexec/path_helper -s
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin"; export PATH;
MANPATH="/usr/share/man:/usr/local/share/man:/usr/X11/share/man"; export MANPATH;

では、path_helper は PATH (と MANPATH) に入れるべきディレクトリをどうやって知るのだろう? man ページによれば、それは /etc/paths と /etc/manpaths だとのこと。そして、ここに書かれたものに、さらに /etc/paths.d と /etc/manpaths.d に置かれたファイルの内容を付け加えて、PATH と MANPATH とする。

以下に、Mac OS X 10.6.5 の /etc/paths の内容を示す。

/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin

同じく、Mac OS X 10.6.5 では /etc/paths.d には X11 というファイルがあり、その内容は以下のようになっている。

/usr/X11/bin

以上のことから、~/.zshenv を使ってユーザごとにパスを設定する以外にも、追加したいパスを書いたファイルを /etc/paths.d に置けば、システム全体で(正確には zsh を使っているすべてのユーザで)同様の効果が得られることがわかる。

関連リンク

関連記事

2010-12-20

Xcode プロジェクトを git で管理する

MacBloggerGlass のプロジェクトの git 管理を開始することにした。Xcode はツール自身が生成するファイルがいろいろあって、何を git 管理に任せれば良いのかが難しい。ツールのことを知るためには自分で試行錯誤を繰り返すのが一番だが、ここは素直に先人の知恵に頼ることにした。

Xcode-Git-User-Script

今回利用したのは、github に登録されている Xcode-Git-User-Script というプロジェクトのスクリプトだ。この先、何度も繰り返すことになることだから、ツールの機能として取り込む方が良いと判断した。

このプロジェクトが提供するスプリプトは Xcode のスクリプトメニュー(「ウィンドウ」メニューと「ヘルプ」メニューの間にあるスクロールっぽいアイコン)にユーザスクリプトとして追加するもので、メニューから実行することで Xcode のプロジェクトに対して .gitignore と .gitattributes を追加してくれる。

ユーザスクリプトとして追加

まず、github の Xcode-Git-User-Script プロジェクトを開き、pasteMe_into_xcode_script_menu というファイルの内容を全選択しコピーしておく。その後の手順は以下のとおり。

  1. Xcode のスクリプトメニュー(スクロールっぽいアイコン)から「ユーザスクリプトを編集…」を実行する。
  2. 「ユーザスクリプトを編集」ダイアログが現れるので、左下にある「+」ボタンを押す。
  3. (「+」ボタンを押すことで現れる)追加メニューの中から「新規シェルスクリプト」を選択する。
  4. 右側のペインにスクリプトをペーストする。
  5. 必要なら左側のリスト項目から追加したスクリプトの名前を変更しておく(ダブルクリックで編集状態になる)。

右のスクリーンショットは「Create .gitignore」という名前で追加したところ。

スクリプトを実行してみる

スクリプトメニューから追加したスクリプトの名前を選ぶ。するとフォルダを選択するダイアログが出てくる。.gitignore を追加したいプロジェクトのフォルダを選べば良い。README にも書かれているが、このダイアログで「保存」ボタンを押すと、右のスクリーンショットにあるような警告パネルが現れる。気にせず「"."を使用」を押せば良い。

また、このスクリプトでは .gitignore に加えて、.gitattributes というファイルも追加するため、スクリプトの実行中にフォルダを選ぶダイアログが 2 回現れる。当然、警告パネルも 2 回現れることになる。

あとは、対象のプロジェクトのフォルダ(ディレクトリ)で git init すればリポジトリのセットアップが完了だ。

Xcode の次のバージョンに期待

Xcode の次のバージョンでは git のサポートも入るらしい。そうなれば .gitignore のことなんかもツール自身が面倒を見てくれるはず。ま、いつ出てくるのかはわからないけど。β版を試す勇気はないしな。

関連リンク

関連記事

2010-11-24

twitter より (2010-11-23)

  • 18:13  iPad のアップデート中。アップデートが終わり、リブートした後の同期(バックアップ)に時間がかかるわ。雑誌の PDF データがでかいんだよね(Good Reader のデータになってる)。
  • 19:05  AirPlay って iPhone や iPad から tv への配信のみなのか。逆はできない。ちょっと残念だけど、これだけでもオモシロイ。iPhone や iPod touch ならリモコン感覚で使えるしな(実際リモコンにもなる)→ http://bit.ly/h97C0V
  • 19:06  AirPlay があると iPod touch に動画を溜めてみたくなる。
  • 21:17  そうだ、iPad のメールも iPhone と同じで「全受信」が使えるようになったんだね。これに慣れてしまうと、iPad でメールを開いたときにいちいちアカウントを切り替えるのがメンドウでしかたなかった。地味だけど、これも 4.2.1 になって良かったことの 1 つだな。
  • 21:34  お、いいね。.gitignore の設定集。プロジェクトごとだけじゃなく、グローバルに ignore を設定することもできるのね。OSX で git を使うときは便利だな。「.DS_Store」とか、いちいち足さなくても良くなる。→ http://bit.ly/fQxBqD
  • 21:51  今どきの若者や子どもたちの中にはダイヤル式の電話なんか見たこともなかったりするんだろうな。きっと使い方もわからないんだろうな。→ http://inspire.2ia.pl/post/35068946/dial-the-old-fashion-way
  • 21:55  ちょっと試してみたけど、おもしろかった。iPhone にも最適化されていて素敵。ただ、iPhone で開くとランダムボタンは出てこない。ちょっと残念。 → http://bit.ly/hLlA1V
Powered by twtr2src.

2010-09-30

既存のプロジェクトを github に公開する

ローカルで(つまり、手元の Mac や PC で)すでに git 管理しているディレクトリを github に公開する方法をメモしておく。単純な手順だし、ヘルプにも詳しく書かれているからそれを見れば良いだけなんだが、いずれ自分視点での記録も重宝するはず。

以前に書いた記事の続きになる。よって、ここでは Github へのユーザ登録はもちろん、SSH 公開鍵の登録も完了しているものとする。

手順

公開までの手順を段階に分けると以下のようになる。

  1. github に新プロジェクトを登録する。
  2. ローカルのリポジトリで、Github のプロジェクトリポジトリをリモートリポジトリとして追加する。
  3. ローカルからリモート(github)に既存のコミットを push する。
1. プロジェクトの登録

github にログインし Dashboard を開くと、右のサイドバーに「New Repository」というボタンが見つかる。これをクリックすると登録の開始となる。

登録画面で指定する情報は 3 つ。「Project Name」、「Description」そして「Homepage URL」だ。大事なのは「Project Name」。ここに入力したものがそのままリポジトリ名(の一部)になる。ここで日本語を指定するとどうなるかはわからない。また、プロジェクト名が早い者勝ちなのかどうかは不明(たぶんそうだろう)。

「Description」と「Homepage URL」は登録後にプロジェクトの個別ページから変更できる。登録には空でも良いようだ(少なくとも Homepage URL を空にしても問題なかった)。

2. リモートリポジトリの追加

手元の git リポジトリに対して、コミットをやったり(push)取ったり(pull)するためのリモートリポジトリを追加する。

git のヘルプ(Creating a repo) にあるように以下のコマンドを実行すれば良い。実際には、foo を github のユーザ名、bar を手順 1. で作ったプロジェクト名で、それぞれ置き換える。

git remote add origin git@github.com:foo/bar.git

このコマンドの意味は、手元の git リポジトリに対して、origin という名前で git@github.com... のリポジトリを参照する、と宣言するものだ。つまり、リポジトリに(短い)別名を付けているのだ(↓参照)。

(「入門git」p.105 〜 106 より)
自分のデフォルトのリモートリポジトリには origin という名前が付いている。これは、何であれクローンしてきたリポジトリのフルネームに対する別名だ。

[...snip...]

自分のリポジトリに origin がなければ、git remote add で、origin を追加することができる。ローカルリポジトリを git init で開始した後、それをリモートリポジトリに送る必要があるときには、この方法が便利だ。

3. 既存のコミットを push

push コマンドは、その名の示す通り、手元のリポジトリに対するコミットをリモートリポジトリに送るものだ。git push A Bで、B のリポジトリに対してなされたコミットを A のリポジトリに送る、という意味になる。引数の順序が少し混乱を招くが(「push A to B」だと思うと逆の意味なる)、これは引数を省略できるという仕様によるものだろう。

(「入門git」p.103 より)
Git はこのコマンドがパラメータなしで呼び出されると、いくつか推測をする。まず、プッシュ先は origin リポジトリだろうと推測する。次に、リポジトリ上にある現在のブランチを、リモートリポジトリ上の対応するブランチ(もしあれば)に送信するのだろうと推測する。

push で指定するのは、まず「どこに送るのか」という情報であり、次に「何を送るのか」を指定する、と覚えれば良い。少し考えれば当たり前のことだとわかる。なぜなら「何を送るのか」は大抵の場合わかりきったことだからだ。だから「どこに送るのか」を指定するのだ。で、リモートリポジトリが 1 つしかなければ、それすらも明白なので省略可能なのだ。

実行結果

以下に、手順 2. 〜 3. を実際に実行している様子を示す。ここでは bloggerglass という GAE 上のアプリのソース一式を登録している。

[imac] mnbi% git remote add origin git@github.com:mnbi/bloggerglass.git
[imac] mnbi% git config --list
[...snip...]
remote.origin.url=git@github.com:mnbi/bloggerglass.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
[imac] mnbi% git push origin master
Identity added: /Users/mnbi/.ssh/github_id_rsa (/Users/mnbi/.ssh/github_id_rsa)
Counting objects: 42, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (42/42), 8.72 KiB, done.
Total 42 (delta 8), reused 0 (delta 0)
To git@github.com:mnbi/bloggerglass.git
 * [new branch]      master -> master

日々のコミット作業

リモートリポジトリを作ったからといって、ローカルで行う日常の作業はほとんど変化しない。唯一違うのはローカルリポジトリにコミットした後、リモートリポジトリへ push することが増えたこと。

先に例として挙げた bloggerglass では、今のところリモートリポジトリは 1 つで、ブランチも作っていないから、引数なしで push コマンドを実行するだけで良い。

以下に、push コマンドの実行例を示す。

[imac] mnbi% git push
Counting objects: 9, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 425 bytes, done.
Total 5 (delta 4), reused 0 (delta 0)
To git@github.com:mnbi/bloggerglass.git
   6057da1..7f9add6  master -> master

bloggerglassでは、すでに typo の修正やデバッグ用のコードの除去などで(...orz)、数回コミットを push している。↑の実行例もその 1 つ。

参考文献

入門git
Travis Swicegood
オーム社 ( 2009-08-12 )
ISBN: 9784274067679
おすすめ度:アマゾンおすすめ度

関連リンク

関連記事

2010-08-17

Github に SSH 公開鍵を登録する

Github のリポジトリにアクセスするためには、あらかじめこちらの SSH 公開鍵を登録しておかなければならない。公開鍵は ssh-keygen コマンドで作れば良い。ウチの環境では、LAN 内の他の Mac へのリモート接続等に公開鍵を使っているため、今回 Github へ登録するものは、それとは別に作ることにした。そのための手順は以下のようになる。

  1. 公開鍵生成時に鍵ファイルの名前を指定する。
  2. Github への SSH 接続では標準とは異なる鍵ファイルを使うように設定する。
SSH 公開鍵の生成

以下が実際の公開鍵生成の実行結果。参考にしたのは help.github にある「Generating SSH keys (OSX)」。また、鍵のファイル名を変更する方法については「Macにgitをインストールしてそのままgithubにも登録」にならった。

[imac] mnbi% ssh-keygen -C "mnbi@foo.bar.baz"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/mnbi/.ssh/id_rsa): github_id_rsa
[...snip...]
SSH の設定

「Troubleshooting SSH issues」の "SSH config" にしたがい、~/.ssh/config に以下の記述を追加する。

Host github.com
 User git
 Hostname github.com
 PreferredAuthentications publickey
 IdentityFile ~/.ssh/github_id_rsa
Github への接続テスト

生成した公開鍵(↑の実行例では github_id_rsa.pub)の内容を Github に登録した後、「Generating SSH keys (OSX)」にしたがい、接続テストを行う。以下はその実行結果。

[imac] mnbi% ssh git@github.com
The authenticity of host 'github.com (207.97.227.239)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,207.97.227.239' (RSA) to the list of known hosts.
Identity added: /Users/mnbi/.ssh/github_id_rsa (/Users/mnbi/.ssh/github_id_rsa)
PTY allocation request failed on channel 0
ERROR: Hi mnbi! You've successfully authenticated, but GitHub does not provide shell access
           Connection to github.com closed.

Github はシェルアクセスを認めていないため接続は切られる。肝心なのは「You've successfully authenticated」の部分。これにより、認証は成功したことがわかる。

追記@2010-11-17

実際のプロジェクトの登録については、「既存のプロジェクトを github に公開する」を参照。

関連リンク

関連記事

2009-11-10

MacBook にも Git を (あるいはリモートリポジトリの準備)

MacBook にも Git をインストール。先日の Mac mini Server のときと同じく ports まかせ。

こうして、ネットワークでつながった 2 台のコンピュータの両方に Git が準備できた。両者の間でリポジトリの clone や、変更の push を試してみよう。

プロトコルを選ぶ

Git は分散 VCS で、かつリポジトリの間に優劣の差がない。実際にそうするかどうかは別として、すべてのリポジトリはリモートリポジトリになることができる。他のコンピュータからのリポジトリの複製要求に応えることができる。適切に設定してやれば。

手元の(ローカル)なコンピュータに Git がインストールされていれば、ネットワーク上(リモート)のコンピュータからリポジトリの内容を複製するための準備は整っている。実際、GitHub などの公開リポジトリから git clone で複製できる。では、複製要求に応える方のコンピュータにはどんな準備が必要なのか。

その問いに応えるためには、まず、Git がリモートリポジトリにアクセスするプロトコルを選ばなくてはならない。プロトコルによって準備が異なるからだ。

「入門git」(p.97-100) によれば、Git が対応しているネットワーク接続のためのプロトコルは、SSH、git、そして HTTP/HTTPS の 3 つ。今回、このうちの SSH と git を使った接続をそれぞれ試してみた。以下に、それぞれの場合にリモート側のコンピュータで必要な設定について試した内容と結果を述べる。
(この記事では SSH の場合のみを扱う。git プロトコルについては別の記事で書く)

Git コマンド群への PATH 設定

さて、2 台のコンピュータ間で SSH 経由のリモートログインができるように設定されているとする (うちの MacBook と Mac mini Server ではすでにそうなっている)。この状態で以下のコマンドを叩いてみる(入門git; p.98, 101)。

[foo:~] % git clone bar.local:projects/greeting

foo.local から bar.local のリモートリポジトリを clone しようというものだ。もし、このとき git-upload-pack: Command not found. というエラーが出て、clone が失敗するようなら、リモート側での PATH の設定に失敗している。というか、うちの Mac mini Server ではこうなった。一方、MacBook をリモート側にするとこのエラーが出ない。clone に成功する。その原因を探るのに、2〜3時間かかってしまった。

リモートのシェルでの PATH の設定にはいろいろな要素がからむ。以下は、うちの Mac mini Server の場合の原因だ。同じ症状だったとしても、これがあてはまらない場合もある。自分にとっての記録と、誰かの参考のために残しておく。

MacPorts を使って Git をインストールした場合、(標準では)コマンド群が置かれるのは /opt/local/bin になる。MacPorts そのものをインストールしたときに、この場所が PATH に足されるよう設定ファイルが変更されるのだが、場合によっては(例: インストール後にログインシェルを変更した)この設定が有効にならないことがある。

MacPorts のインストーラは、その最終段階で .profile または .tcshrc を変更するようだ。うちの Mac たちのシェルは tcsh に変更してあるので、以下の記述は tcsh の場合のみにあてはまる。.tcshrc ではこんな行が追加される。

# MacPorts Installer addition on 2009-10-25_at_13:33:42: adding an appropriate PATH variable for use with MacPorts.
setenv PATH /opt/local/bin:/opt/local/sbin:$PATH
# Finished adapting your PATH environment variable for use with MacPorts.

これらの行がない場合(肝心なのは setenv の行、他はコメント)、MacPorts のコマンド群はすべて見つからない。ところで、PATH の設定は他にも方法がある。ログインシェルなら .tcshrc の後、.login も読まれるため、そちらで設定することもできる(というか、わたしはそうしていた)。つまり、.tcshrc 以外の方法で PATH を設定していた場合、対話的にターミナルから使う場合には問題なくコマンドが見つかるのに、対話的じゃないとき(つまりリモートシェルのような場合)には、コマンドが見つからず失敗する、という現象が起きる。

原因がわかれば対処できる。単純に、Mac mini Server の .tcshrcで↑に挙げた PATH の設定の行を追加するだけ。たった 1 行の追加だ。実は、ここに至るまで色々と試行錯誤を経たのだけど、この解決策がもっともシンプルなのでこれを採用。

clone する

実は SSH をプロトコルにする場合、以上でリモート側の設定は完了。後はコマンドを叩くだけ。こんな風になる。

[foo:~] % git clone bar.local:projects/greeting
Initialized empty Git repository in /Users/baz/tmp/greeting/.git/
remote: Counting objects: 16, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 16 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (16/16), done.
Resolving deltas: 100% (2/2), done.

まとめ

さて、今回はここまで。Git の話題というよりは、MacPorts と SSH の話になってしまった。

この先、リモートのリポジトリに push したり、pull してきたり、実際に使う場合にはいろいろと覚えなきゃならないことがある。単にコマンドを覚えるだけでなく、どういった運用にするのかも考えなきゃならない。

想定しているシナリオは、普段デスクトップで作業をしていて、出張だとか何かで部屋やオフィスを出なればならないとき、ノートブックにデスクトップから clone して作業環境を持っていく、というもの。出先での作業の記録はノートブックのリポジトリに commit しておき、戻ってからデスクトップに push する。

何もリポジトリを分散させなくても、SD カードや USB メモリといったリムーバブルメディアにリポジトリを構築すれば、上記のようなシナリオには十分に対応できる。この方法なら Subversion のような集中リポジトリタイプの VCS でも可能。好みの問題だ。集中と分散、どっちが好きか。

上にも書いたが、SSH を使わず Git オリジナルのプロトコルを使う方法もある。そちらについては、また別の機会に書くつもり。調べたいことがまだ残っているので。

参照情報

関連記事

2009-11-08

平等分散リポジトリの見せる夢

はじめての Git

LOG+REPOのテンプレートや素材、そして記事を保全するために Git で管理することにした。まずは「入門git」の第三章、「最初のプロジェクトを作る」に書かれた手順を追ってみた。

git init がすべての始まり。CVS や Subversion とは違い、中央リポジトリは存在しない。昨日までの作業場所がそのままリポジトリの置き場所にもなる(↓)。

(入門git; p.25)
Git で自分のリポジトリがあるのは、自分の作業ツリーとまったく同じ場所にある .git ディレクトリの中だ。

ファイルを作ったら git add、そして git commit。変更しても git add、そして git commit。さっき何を変更したかを忘れたら git status。これまでにどんな変更をしたかを思い出したければ git log。詳細な差分が知りたくなったら git diff。

日常のサイクルを思い出すには Git早見表の "Commands Sequence" が最適。

Git は RCS っぽい

CVS や Subversion を一から導入するのはかなりハードルが高い。ソフトウェアのインストールのことではない。今時の有名なソフトウェアのインストールはとても簡単 (Git もそうだった)。よほどマイナーなプラットフォームにこだわっていない限り、迷うことはほとんどない。大変なのは、実際にプロジェクトをバージョン管理ソフト(以下、VCS)の管理下に置く作業の方だ。こっちには途方に暮れる点が少なくない。

何よりリポジトリをどこに置くかで迷う。ローカルなマシンに置くのか、ネットワーク上の共有フォルダに置くのか。ネット上に置くなら、むしろ VCS をサーバとして動かすべきじゃないのか。いっそのこと、Google に頼むか。・・・などなど。

慣れているなら迷わない。けれど、最初にこれをやるのはかなりハードだ。失敗してしまえば(後からもっと良い方法を思いついたら)、やり直しはメンドウ。そう思うと、ますます指が動かなくなる。

その点、作業場所がそのままリポジトリだという Git の方法は迷いがない。思い立ったら、ただ git init と叩くだけでいい。「やっぱ、や〜めた」となれば、rm -rf .git で、キレイさっぱり忘れてしまえる。

ふと思った。「あ、これって、RCS と同じ感覚だ。」

RCS は、もうずっと以前に unix 界隈でメジャーだった VCS (→ Wikipedia:Revision_Control_System)。そんなの聞いたことないや、っていう人はターミナルを開いて /usr/bin あたりを見てみるといい。ci とか co というコマンドが見つかるはずだ。少なくとも Snow Leopard には入ってる (Xcode と一緒に来たのかもしれない)。

RCS は、基本的に個人の作業成果を管理するためのシステムだ。独立したリポジトリの概念はなく、作業場所がリポジトリも兼ねる (ディレクトリごとに RCS ディレクトリを作れば、そこがリポジトリになる)。だから、チームで作業するようなプロジェクトには向かない。

個人からチームへ

ソフトウェアの規模が増大するにつれて、ソフトウェア開発の主役は個人からチームに移っていった。VCS にもチームでの作業を前提とした機能が求められた。CVS の誕生だ(→ Wikipedia:Concurrent_Versions_System)。CVS の始まりは RCS への不満だったという。RCS をベースにして、そこに不足している機能を付け加える方法で開発が進められた。いつしか RCS への依存もなくなり独立した VCS として、オープンソースソフトウェアプロジェクトを中心に広く使われるようになった。

一方で、ソフトウェア開発は複雑化の一途をたどった。チームメンバーの増加、地理的分散、増大するリリース作業の負担。プロジェクトインフラとしての VCS には、大規模かつ複雑なプロジェクトをサポートする機能が求めらるようになった。つまり、CVS にも機能不足と呼ばれるときが来たのだ。

(Subversion実践入門 第2版;p.6 - 7)
Subversion のプロジェクトは、CVS に精通した開発者のチームによって開始された。(・・・中略・・・) 彼らは CVS が既に古くなりつつあることを感じて、それに代わるツールを開発すべき時が訪ずれたと判断したのだ。Subversion の開発者たちには CVS の短所が痛いほど分かっていたので、彼らは高性能で現代的なバージョン管理システムを設計することに特に重点を置いた。

集中から分散へ

リポジトリを集中させるか、または分散させるか。分散させ、かつどこかにマスターを置くハイブリッド型か。これらはスタイルの違いであり、どれが優れていて何が劣っているというものではない。プロジェクトとチームの特性に応じて適切なものを選択するのが賢いやり方だ。

だから、Git が現状(2009年末時点)で最高の VCS であり、他の VCS を使うことなど考えられない、などと言うつもりはない。しかし、個人が自分自身の活動を管理するために使うとしたら、Git のような分散タイプ、それもリポジトリ間に優劣の差(マスター/スレーブ)がない平等分散リポジトリタイプをサポートするものが良い。他の分散 VCS も「平等分散リポジトリ」をサポートするなら、あとは好みの問題だ。

個人の復権

GitHubの登場はコミッタを特権階級から追い落とす革命だった - Hello, world! - s21g

かつてはメンテナやコミッタが専権的にソフトウェア開発の決定権を握っていた構造が、Git/GitHubの登場によって、気がつかないうちに崩れ去っている。これはソフトウェア開発史上、非常に大きな出来事なんだろう

不思議なものでオープンなはずの、オープンソースソフトウェアでは↑のような状況が存在するのだという。一方で、クローズドな環境である企業の開発現場では、リポジトリの管理(昔はライブラリアンと呼ばれた)はメンドウなだけの労働であることが多い。誰も進んでやりたがる業務じゃない。そこでは管理者(マネージャじゃないよ、英語でいうならアドミニストレータ)は特権階級なんかじゃない。むしろ下働きだ。誰かがやらないといけない作業、大事なんだけど報われることの少ないロール。

オープンソースソフトウェアのプロジェクトにおいて、リポジトリに対する権限が開発者間に階級を生んでいるのだとしたら、そしてそれが開発者の間に感情の軋轢を生じさせるのならば、それはプロジェクトの特性に適していない管理方式なのだ。その場合、Git のような分散かつ平等なリポジトリを持つシステムは救いになる。

皆が自分のリポジトリを持ち、誰もマスターではなく、またスレーブでもない。ソースコードはブランチすることが前提で、世界中にさまざまな変種が存在する。誰もが自由にプッシュでき、誰もが自由にマージできる。ソフトウェアを中央のコミッタがデザインするのではく、個々のプログラマが自らの用途に合わせ、思うままにアレンジできる。何が正しくて何が間違っているのか、プログラマ自身が決めることができる。個人としてのプログラマの復権だ。

あとひとつ。Git のもたらすこのビジョンこそ、ソフトウェアの再利用というプログラマの(古くからの)夢を実現するものじゃないだろうか。再利用すべきはバイナリじゃない。ソースコードだ。皆がリポジトリを持つことで初めてそれが可能になる。

2009-11-06

MacPorts で Git をインストール

ブログのテンプレートをいじったりしているので、テンプレート(XML)のバージョン管理をしようと思い立った。Snow Leopard には Subversion (/usr/bin/svn 等)が標準で用意されている(開発ツールをインストールしたからかも)んだけど、せっかくなので Git に挑戦してみたい。まずは Mac mini Server に ports まかせで Git をインストール。手順はこれ(↓)だけ(「入門 git」の p.17 より)。

% sudo port install git-core +svn +doc

依存するパッケージも多数、未インストールの状態だったため、かなり時間がかかった。およそ 30 分。↑の port コマンドが完了した後は、こう(↓)なった:

% git --version
git version 1.6.5.1

これで完了、と思ったら、ports tree を更新していなかったことを思い出す。

% sudo port sync

古くなっているものがないか、確認してみる。

% port outdated
The following installed ports are outdated:
db46                           4.6.21_5 < 4.6.21_6       
git-core                       1.6.5.1_0 < 1.6.5.2_0     
sqlite3                        3.6.19_0 < 3.6.20_0

や、やられた〜 orz。更新しておく。

% sudo port upgrade outdated
--->  Computing dependencies for db46
--->  Fetching db46
...
--->  Extracting git-core
--->  Applying patches to git-core
--->  Configuring git-core
--->  Building git-core
--->  Staging git-core into destroot
--->  Deactivating git-core @1.6.5.1_0+doc+svn
--->  Computing dependencies for git-core
--->  Installing git-core @1.6.5.2_0+doc+svn
--->  Activating git-core @1.6.5.2_0+doc+svn
--->  Cleaning git-core

今度はすぐに終わった。

% git --version
git version 1.6.5.2

ミッション・コンプリート。今日はここまで。