Mercurial入門
ゲーム「バイオハザード」シリーズでは,ゲーム中に現れるアイテム「タイプライター」を使ってプレイデータをセーブ(保存)できる.タイプライターは一般的にはセーブポイントと呼ばれるシステムで,それまでのプレイ内容をセーブしておき,あとでそこから再開できるようにするためのシステムだ.
バイオハザードではタイプライターのある場所でしかプレイデータをセーブできず,またセーブ回数も持っているインクリボンの個数までという制限があった.一方で,普段お使いのコンピュータシステムなら,どこでも,無制限に,プレイデータ(作業内容)をセーブできる.
このようなシステムをバージョン管理システム (Version Control System) と呼び,略して VCS と言う.VCS には様々な種類があるが,現在主流なのは Git と本稿で解説する Mercurial である.コンピュータエンジニアは Git を強く好む傾向があるが,Git は多機能な反面わかりやすさを犠牲にしている.現在関わっているプロジェクトが全面的に Git を採用しているというような事情がなければ,Mercurial は魅力的な選択肢である.
本稿では OS X (Mac) でのMercurialの使い方に焦点をあてて解説をしてみたい.OS X では SourceTree のようなアプリを使えばコマンドラインに降りることなく Mercurial を使うことができるが,本稿ではコマンドラインで Mercurial を使う.そのために,手前味噌ではあるが「『新しいLinuxの教科書』をMacで実践する」を先に参考にしてもらいたい.
なおMercurial(水銀)の元素記号はHgであるから,Mercurial のことを Hg と呼ぶこともしばしばある.またセーブポイント(バイオハザードのタイプライター)は正しくは「リポジトリ」と呼ぶが,本稿ではセーブポイントと呼び続けることにする.その他,以下のように正式な呼称が対応する.
□セーブポイント → リポジトリ
□セーブする → コミットする
□ロードする → アップデートする
□プレイデータ → チェンジセット
OS X の準備
OS X に開発環境と Homebrew が入っていると便利なので,こちらの記事を参考に Homebrew のインストールまでしておいてもらいたい.
Mercurialのインストール
Homebrew を使ってインストールする.ターミナルから brew install mercurial
を実行しよう.
これで準備ができた.ターミナルで hg
と打って以下のようなメッセージが出て来れば成功だ.
準備の締めくくりに,Mercurial に自分の名前とメールアドレスを教えておいてあげよう.これにはホームディレクトリに .hgrc
というファイルを作り,以下のような内容を書いておく.(ここで (at)
は @
に置き換えてもらいたい.)
[ui]
username = Ichi Kanaya <kanaya(at)pineapple.cc>
と言っても,いきなりエディタでピリオドから始まるファイル名を扱えないので,適当なテキストエディタで上記の内容を書いたらひとまず hgrc.txt
という名前でホームディレクトリ (/Users/{ユーザ名}
) に保存しよう.どうしてもテキストエディタがない場合はWordでかまわない.保存するときに「書式なし(.txt)」を選び,次に出てくるダイアログの「行末」の部分だけ「改行文字(LF)のみ」に変更して保存してもらいたい.
続けてターミナルで mv hgrc.txt .hgrc
としてファイル名を変えよう.
リターンキーを押して何も言われなければ無事ファイル名が変更されている.文句を言われた場合はちゃんと hgrc.txt
と書いているか確認しよう.
バージョン管理の準備
バージョン管理したいドキュメントを入れるフォルダを作ろう.ここではホームディレクトリ(僕の場合は /Users/kanaya/
になっている)の下の Documents
というフォルダの中に Hello
というフォルダを作ることにしよう.Documents
ディレクトリは最初からあるので,そこへ cd
してから mkdir
する.
つづいて Hello
ディレクトリへ移り hg init
する.
これで Hello
ディレクトリにMercurialのセーブポイント(リポジトリ)が組み込まれた.試しに ls -aF
してみると .hg
という隠しディレクトリがあることがわかる.
この .hg
ディレクトリがセーブポイント(リポジトリ)の正体である.ここをいじってしまうとセーブデータが消えてしまうので .hg
ディレクトリは触らないようにしよう.逆に言えば,定期的にセーブ(コミット)している限り,他は何をしてもだいたい安全だ.
バージョン管理の第一歩
適当なテキストエディタでテキストファイルを作ってみよう.僕は TextWrangler で spec.txt
というファイルを作った.(テキスト形式ならWordでも構わないし,後で述べる diff 機能を使わないのであればdocやdocx形式でも構わないのだが,話を簡単にするために TextWrangler を使うという前提で進めさせていただく.)
これを Hello
ディレクトリ(フォルダ)に保存する.
この spec.txt
をこれからセーブポイント(リポジトリ)にセーブ(コミット)しよう.まずこの spec.txt
がいまどんな状態にあるのか Mercurial に問い合わせてみよう.打つのは hg status
だ.
すると,
? spec.txt
と言われる.「spec.txt
なんて知りまへんでえ,ぶぅぶぅ」というわけだ.そこで spec.txt
がセーブポイント(リポジトリ)へのセーブ(コミット)対象であることを Mercurial に教えてあげよう.具体的には hg add spec.txt
とする.
ここでもう一度 hg status
をしてみよう.
今度は spec.txt
の状態が「?
」ではなく次のように「A
」になった.
A spec.txt
この状態では spec.txt
はまだセーブ(コミット)されていないので,こんどは Mercurial に「セーブ(コミット)するよ」と伝えないといけない.このときコミットメッセージという短いメモをつけないといけない.今回は最初のセーブ(コミット)なので “The first version.” とメモをつけてみよう.
メモ(コミットメッセージ)は日本語も通るのだが,最初なので格好つけて英語にしておいた.
ここで -m
以下を省略するとデフォルトのエディタがいきなり立ち上がり,メモ(コミットメッセージ)を書けと迫られる.悪いことにデフォルトのエディタは特別に設定しない限りvimというマニアックなエディタになっている.もし -m
以下をつけ忘れてこのような画面になってしまったら,落ち着いて,まず英語入力モードに切り替えよう.日本語キーボードなら「英数」キーを押すとか,古参 Mac ユーザならコマンド+スペースとか,ともかく英語入力モードにしてくれ.次に冷静に :q!
とキーを押してくれ.これでエディタの終了と先ほどの hg commit
の影響をキャンセルできる.この後もう一度 hg commit -m ‘The first version.’
からやり直してもらいたい.
さて,もう一度 hg status
をしてみると,もはや Mercurial はすることがないので何も言わなくなっていることがわかる.
ここで spec.txt
をちょっと改変してみよう.下の写真のように2行ほど行を追加してみた.
ファイル spec.txt
を上書き保存して,ターミナルで hg status
を実行してみよう.次のようになるはずだ.
今度は
M spec.txt
になった.この「M
」は「spec.txt
は前回のセーブ(コミット)から進んでまっせ」という意味だ.どう進んだかというのも Mercurial は知っている.それを知るのが hg diff
という命令だ.次のように hg diff spec.txt
と打ち込んでみよう.
では,この変更もセーブポイント(リポジトリ)にセーブ(コミット)してしまおう.すでに Mercurial は spec.txt
がセーブ(コミット)対象だと知っているので,今度は hg add
する必要はない.《Gitユーザへの注意: Mercurialでは一度リポジトリに追加したファイルは毎回 add
しなくても良い.》
正しくセーブ(コミット)できた場合 Mercurial は Unix の伝統に従って口をつぐむ.念のため hg status
してみても Mercurial は「もうやることあらへんで〜」と何も言わない.
が,セーブ(コミット)の履歴は残っている.それを確認してみよう.タイプするのは hg log
だ.
セーブ(コミット)した履歴が残っているのがお分かりいただけるだろう.バイオハザードと違って,プレイデータは上書き保存されない.いつでも古いプレイデータを取り出せるのだ.ちなみにプレイデータは正しくはチェンジセットと言う.技術的な話になるが Mercurial は過去のプレイデータとの差分だけを保存しているので,チェンジ(変化)の集合(セット)と呼ぶのだ.
次は古いプレイデータ(チェンジセット)を取り出す方法を見てみよう.
古いデータを取り出す
いま spec.txt
に加えた変更がまずかったと気がついたとしよう.今回の例のように行を足しただけならそれほど問題にはならないが,長い文章を推敲してセーブ(コミット)したが,やはり気に入らなくなったということもあるだろう.そんな時には,セーブポイント(リポジトリ)から古いデータを取り戻すことができる.
まず,念のため spec.txt
を開いているエディタを閉じておこう.続けて Mercurial に0番のプレイデータ(チェンジセット)を出してくれと伝えよう.こうするには hg update 0
とすればいい.
この状態でエディタで spec.txt
を開いてみてくれ.このように最初にセーブ(コミット)した状態に戻っているだろう.
もちろん,2番目のプレイデータ(チェンジセット)も1番として保存されている.それを引き出してみよう.念のためエディタを閉じてから,ターミナルで次のようにしてもらいたい.いまプレイデータ(チェンジセット)の1番(つまり2番目)は最新なので,番号指定は省略できる.
このようにして,Mercurial を使えば歴史を行ったり来たりできるのだ.
平行宇宙へ行く
タイムマシンで過去に行って過去を書き換えてしまったら,当然異なった未来が訪れるだろう.
いまの spec.txt
の状態を過去から未来へという図で表すとこんな感じになる.
いまいちど hg update 0
で最初のプレイデータ(チェンジセット)である0番を呼び戻そう.
これで一旦プレイデータ(チェンジセット)の1番のことは忘れておける.次のような状態だと思って欲しい.
ここで spec.txt
を編集して,次のような一文を加えたとしよう.
改めて hg status
を見てみよう.
すると spec.txt
が改変されているので,もうお馴染みの
M spec.txt
となっている.これをセーブポイント(リポジトリ)にセーブ(コミット)しよう.もちろん hg commit -m ‘memo’
をすれば良い.やってみよう.
今度は Mercurial から次のようなメッセージが来た.
created new head
これはどういうことかというと,歴史を書き換えてしまったため,次の図のようにプレイデータ(チェンジセット)の履歴が枝分かれしていることを伝えてくれているのだ.
ここで hg log spec.txt
としてみると,次のように changeset 2番の parent が0番になっているのがわかる.
ここでまた気が変わって,プレイデータ(チェンジセット)の1番を元に編集を続けたくなったとしよう.もうやり方はお分かりだと思う.スクリーンショットだけ掲載しよう.
ここで spec.txt
にまたなにがしかの編集を行い,セーブ(コミット)しよう.
この結果,プレイデータ(チェンジセット)の履歴は次のようになる.
このように,過去データをロード(チェックアウト)して編集したあとセーブポイント(リポジトリ)へセーブ(コミット)していくことで,平行宇宙を作りつつもお互い行ったり来たりできるようになるのである.
あといくつかのコマンド
バイオハザードでは必要ないが,あといくつかの Mercurial コマンドを覚えておけば役にたつだろう.
hg rename {元ファイル名} {新ファイル名}
はファイル名を変更するときに用いる.コマンドラインで mv {元ファイル名} {新ファイル名}
とする代わりで,Mercurial を通してファイル名変更をすることで履歴が引き継がれるようにできる.
hg forget {ファイル名}
は hg add
の反対でファイルを Mercurial の管理から外すために使う.管理から外してもファイルはそのまま残る.
hg remove {ファイル名}
はファイルの削除をするときに用いる.これは hg forget {ファイル名}
と rm {ファイル名}
を連続して実行するのと同じである.なおファイルは消してもリポジトリには残っており,履歴が遡って消されるわけではない.あと hg add
した直後は hg remove
できないので hg forget
を使おう.
Bitbucketを使ってバックアップをとる
セーブポイント(リポジトリ)を消してしまっては元も子もないので,それをバックアップする方法を書いておこう.
もともと Mercurial は複数のセーブポイント(リポジトリ)を同期させることができるようになっている.これは複数メンバで作業するときに便利なようにだ.この機能は,単にセーブポイント(リポジトリ)のバックアップとしても使える.
バックアップ先は,運用ポリシーが許せば外部サーバにするのが確実だ.万が一Macのディスクごと壊れても,外部サーバが生きていれば復旧できるからだ.僕はバックアップ先として Atlassian が運営する Bitbucket をお勧めしたい.Bitbucket は Mercurial に対応しているし,無料アカウントでもリポジトリを非公開にできるからだ.以下 Bitbucket を使ったバックアップ方法について述べる.
まず Bitbucket で無料アカウントを作成する.Bitbucket アカウント名,パスワードは後々使うので覚えておこう.続けてヘルプページの “Import an existing, unversioned code project to an empty repository” という項目の5番目からを実行すれば良い.とだけ書くと不親切なので,順を追って説明しよう.なお以下の手順は将来変わるかもしれないので,参考程度にしてもらいたい.
(0) Bitbucket にログインする.
(1) Repositories メニューから Create repository サブメニューを選ぶ.
(2) “Create a new repository” という画面になったら “Repository name” 項目に “Hello” と入力し “Repository type” を “Mercurial” にする.他はそのままでよい.次のような画面になっていれば正解だ.念のため “Access level” の項目 “This is a private repository” にチェックが入っているか確認しよう.
(3) “Create repository” ボタンを押す.
(4) ターミナルで Hello
ディレクトリに移動し hg push https://{Bitbucketユーザ名}@bitbucket.org/{Bitbucketユーザ名}/Hello
とする.途中パスワードを聞かれるので,Bitbucket で設定したパスワードを打ち込もう.(Bitbucket はリポジトリ名の大文字を小文字へ変換してしまうので Hello
は hello
でも構わない.)
うまくいくと次のような画面になるだろう.
(5) 最後に Bitbucket のサイトに正しく保存されているか確認しよう.これには https://bitbucket.org/{Bitbucketユーザ名}/hello
へアクセスすればよい.画面右手の “Recent activity” にメモ(コミットメッセージ)が並んでいれば成功だ.
あとは定期的に hg push https://{Bitbucketユーザ名}@bitbucket.org/{Bitbucketユーザ名}/Hello
をすればその都度バックアップが取られる.コマンドが長くて面倒な人向けに,デフォルトのバックアップ先(リモートホストと言う)を設定する方法があるのだが,残念ながら .hg/hgrc
というテキストファイルを直接いじるか,次の節で述べるように一旦 Bitbucket から復元するかしかない.一応 .hg/hgrc
を直接いじりたい人向けに,一番簡単な方法だけ書いておこう.ターミナルで echo “[paths]\ndefault = https://{Bitbucketユーザ名}@bitbucket.org/{Bitbucketユーザ名}/hello” >> .hg/hgrc
とするのだ.
【追記】.hg/hgrc
を更新するツール hgsetup を作成した.hgsetup はシェルスクリプトなので,自分の作業ディレクトリにコピーした上で chmod +x hgsetup; ./hgsetup ‘{お名前}’ {メールアドレス} {Bitbucketアカウント} {プロジェクト名}
と実行してもらいたい.実行後はhgsetupスクリプトを削除して構わない.
Bitbucket からの復元
ディスクがクラッシュした,OS をクリーンインストールした,新しい Mac を買ったなどで,Bitbucket からリポジトリごと復元したい場合はターミナルで hg clone https://{Bitbucketユーザ名}@bitbucket.org/{Bitbucketユーザ名}/hello
とする.残念ながらディレクトリ名は Hello
ではなく小文字の hello
になってしまうが,手動で hello
を Hello
に変えておいても問題はない.
なお,この状態でデフォルトのバックアップ先(リモートホスト)が設定されているので,以降バックアップは hg push
だけでよい.