Mercurial入門

[ゲーム「バイオハザード」シリーズ](https://ja.wikipedia.org/wiki/バイオハザードシリーズ)では，ゲーム中に現れるアイテム「タイプライター」を使ってプレイデータをセーブ（保存）できる．タイプライターは一般的には **[セーブポイント](https://ja.wikipedia.org/wiki/セーブポイント_%28ゲーム%29)** と呼ばれるシステムで，それまでのプレイ内容をセーブしておき，あとでそこから再開できるようにするためのシステムだ．

![1*Hj82rzxZQqZQe0PKYgcmOQ.jpeg](https://qiita-image-store.s3.amazonaws.com/0/15782/1c2ae743-5b16-8106-38d5-7411bd4bdbea.jpeg)

_Image courtesy of [4Gamer](http://www.4gamer.net/games/267/G026771/20141120048/)_

バイオハザードではタイプライターのある場所でしかプレイデータをセーブできず，またセーブ回数も持っているインクリボンの個数までという制限があった．一方で，普段お使いのコンピュータシステムなら **どこでも，無制限に，プレイデータ（作業内容）をセーブできる．**

このようなシステムをバージョン管理システム (Version Control System) と呼び，略してVCSと言う．VCSには様々な種類があるが，現在主流なのは[Git](https://git-scm.com/)と **本稿で解説する[Mercurial](https://www.mercurial-scm.org/)** である．コンピュータエンジニアはGitを強く好む傾向があるが，Gitは多機能な反面わかりやすさを犠牲にしている．現在関わっているプロジェクトが全面的にGitを採用しているというような事情がなければ，Mercurialは魅力的な選択肢である．

本稿では macOS (OS X) でのMercurialの使い方に焦点をあてて解説をしてみたい．macOS (OS X) では [SourceTree](https://itunes.apple.com/jp/app/sourcetree-git-hg/id411678673?l=en&mt=12) のようなアプリを使えばコマンドラインに降りることなくMercurialを使うことができるが，本稿ではコマンドラインでMercurialを使う．そのために，手前味噌ではあるが[「『新しいLinuxの教科書』をMacで実践する」](http://qiita.com/kanaya/items/15ef1ba8af83a6b5c2c9)を先に参考にしてもらいたい．

なおMercurial（水銀）の元素記号はHgであるから **MercurialのことをHgと呼ぶこともしばしばある．** またセーブポイント（バイオハザードのタイプライター）は正しくは「リポジトリ」と呼ぶが，本稿ではセーブポイントと呼び続けることにする．その他，以下のように正式な呼称が対応する．

* セーブポイント → リポジトリ
* セーブする → コミットする
* ロードする → アップデートする
* プレイデータ → チェンジセット

# macOS (OS X) の準備

macOS (OS X) に開発環境とHomebrewが入っていると便利なので，[こちらの記事](http://qiita.com/kanaya/items/15ef1ba8af83a6b5c2c9)を参考にHomebrewのインストールまでしておいてもらいたい．

# Mercurialのインストール

Homebrewを使ってインストールする．ターミナルから `brew install mercurial` を実行しよう．

![1*AHGg_HIhIlPA31gwAJL9zw.png](https://qiita-image-store.s3.amazonaws.com/0/15782/22d96644-3c46-7652-ae38-e45613857eeb.png)

これで準備ができた．ターミナルで `hg` と打って以下のようなメッセージが出て来れば成功だ．

![1*eVypoFxGvbndWf1kS89WuQ.png](https://qiita-image-store.s3.amazonaws.com/0/15782/4fe45199-3fdd-b73d-9310-8e50a0b6845d.png)

準備の締めくくりに，Mercurialに自分の名前とメールアドレスを教えておいてあげよう．これにはホームディレクトリに .hgrc というファイルを作り，以下のような内容を書いておく．

```
[ui]
username = Ichi Kanaya <kanaya(at)pineapple.cc>
```

と言っても，いきなりエディタでピリオドから始まるファイル名を扱えないので，適当な[テキストエディタ](https://itunes.apple.com/jp/app/textwrangler/id404010395?l=en&mt=12)で上記の内容を書いたらひとまず hgrc.txt という名前でホームディレクトリ (/Users/{ユーザ名}) に保存しよう．どうしてもテキストエディタがない場合はWordでかまわない．保存するときに「書式なし(.txt)」を選び，次に出てくるダイアログの「行末」の部分だけ「改行文字(LF)のみ」に変更して保存してもらいたい．

![1*iEV2Xwo80eijSBFhJ1v6jA.png](https://qiita-image-store.s3.amazonaws.com/0/15782/041d923a-876c-6d38-3ac1-2a5dacbf3ad6.png)

続けてターミナルで `mv hgrc.txt .hgrc` としてファイル名を変えよう．

![1*ErsMDH4Hu3vW7PX43lY6Gg.png](https://qiita-image-store.s3.amazonaws.com/0/15782/e737d6d4-8819-cb83-65c9-d694f662b228.png)

リターンキーを押して何も言われなければ無事ファイル名が変更されている．文句を言われた場合はちゃんと hgrc.txt と書いているか確認しよう．

# バージョン管理の準備

バージョン管理したいドキュメントを入れるフォルダを作ろう．ここではホームディレクトリ（僕の場合は /Users/kanaya/ になっている）の下のDocumentsというフォルダの中にHelloというフォルダを作ることにしよう．Documentsディレクトリは最初からあるので，そこへ `cd` してから `mkdir` する．

![1*WgKizEnXZ0CEPZ4-3aiX8g.png](https://qiita-image-store.s3.amazonaws.com/0/15782/c8d5ccc0-8a9a-ce5f-00da-e3fbf2343723.png)

つづいてHelloディレクトリへ移り `hg init` する．

![1*CsNespkeYHh3acg7GwIoDA-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/375b2cad-e18a-a6f2-4908-06d259707041.png)

これでHelloディレクトリにMercurialのセーブポイント（リポジトリ）が組み込まれた．試しに `ls -aF` してみると .hg という隠しディレクトリがあることがわかる．

![1*qiMFeBP_VVfsUDJdE6wclQ-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/0f59cd4d-7c88-97b9-9e79-788dfee50b3c.png)

この .hg ディレクトリがセーブポイント（リポジトリ）の正体である．ここをいじってしまうとセーブデータが消えてしまうので .hg ディレクトリは触らないようにしよう．逆に言えば，定期的にセーブ（コミット）している限り，他は何をしてもだいたい安全だ．

# バージョン管理の第一歩

適当なテキストエディタでテキストファイルを作ってみよう．僕は [TextWrangler](https://itunes.apple.com/jp/app/textwrangler/id404010395?l=en&mt=12) で spec.txt というファイルを作った．（テキスト形式ならWordでも構わないし，後で述べるdiff機能を使わないのであればdocやdocx形式でも構わないのだが，話を簡単にするために TextWrangler を使うという前提で進めさせていただく．）

![1*fprvUp90kQhlduNdo5tbpQ.png](https://qiita-image-store.s3.amazonaws.com/0/15782/ee8f4d6f-6c6e-2466-3d14-b3b464eaf21c.png)

これをHelloディレクトリ（フォルダ）に保存する．

![1*2f-FRF0YgB93iX68etupDQ-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/67717305-b9b4-fdc4-9ed4-3c8df9916508.png)

この spec.txt をこれからセーブポイント（リポジトリ）にセーブ（コミット）しよう．まずこの spec.txt がいまどんな状態にあるのかMercurialに問い合わせてみよう．打つのは `hg status` だ．

![1*pMjRymcMUBvp5HjaE3YQHA.png](https://qiita-image-store.s3.amazonaws.com/0/15782/490d3223-c79e-c452-8782-820a2aa3a664.png)

すると，

> ? spec.txt

と言われる．「spec.txt なんて知りまへんでえ，ぶぅぶぅ」というわけだ．そこで spec.txt がセーブポイント（リポジトリ）へのセーブ（コミット）対象であることをMercurialに教えてあげよう．具体的には `hg add spec.txt` とする．

![1*zXSnt-8ZgRHyAXbWqOFUaA.png](https://qiita-image-store.s3.amazonaws.com/0/15782/f0e827d5-4d45-ca90-8c0e-f51dd1e955db.png)

ここでもう一度 `hg status` をしてみよう．

![1*2LAouYiGSgxhMZrz4s6uvA.png](https://qiita-image-store.s3.amazonaws.com/0/15782/976e33d9-5be0-697d-606c-1ae2ef689e87.png)

今度は 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はすることがないので何も言わなくなっていることがわかる．

![1*lVau8GsaYJG1FLvZQiybEw-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/d6c02e35-811b-a2bd-8c08-6829b85df2ff.png)

ここで spec.txt をちょっと改変してみよう．下の写真のように2行ほど行を追加してみた．

![1*pO_Bl_5anDWvSG-Xoy7dxw.png](https://qiita-image-store.s3.amazonaws.com/0/15782/0e41f4fe-bcbe-305d-88c9-d64dbb2ce385.png)

ファイル spec.txt を上書き保存して，ターミナルで `hg status` を実行してみよう．次のようになるはずだ．

![1*V4QX17GdqHlXq0uYXITHFg.png](https://qiita-image-store.s3.amazonaws.com/0/15782/21f09d5d-f560-bd46-205a-2dc0517cdd16.png)

今度は

> M spec.txt

になった．この「M」は「spec.txt は前回のセーブ（コミット）から進んでまっせ」という意味だ．どう進んだかというのもMercurialは知っている．それを知るのが `hg diff` という命令だ．次のように `hg diff spec.txt` と打ち込んでみよう．

![1*MQK-uL_Y53b-Hbf3_6s-1Q-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/3eda4145-ac6d-5d38-604d-8cefd0d9ecd6.png)

では，この変更もセーブポイント（リポジトリ）にセーブ（コミット）してしまおう．すでにMercurialは spec.txt がセーブ（コミット）対象だと知っているので，今度は `hg add` する必要はない．《Gitユーザへの注意: Mercurialでは一度リポジトリに追加したファイルは毎回 `add` しなくても良い．》

正しくセーブ（コミット）できた場合MercurialはUnixの伝統に従って口をつぐむ．念のため `hg status` してみてもMercurialは「もうやることあらへんで〜」と何も言わない．

![1*QqPR9eJsi-TP3np7xDHfjQ-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/1a081a20-0ef2-6bae-ba0d-a8e2fb392d58.png)

が，セーブ（コミット）の履歴は残っている．それを確認してみよう．タイプするのは `hg log` だ．

![1*0sVCmdF8N0qxFqMlkk5Igw-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/d41de347-8bf0-1812-47d6-b757e30747bc.png)

セーブ（コミット）した履歴が残っているのがお分かりいただけるだろう．バイオハザードと違って，プレイデータは上書き保存されない．いつでも古いプレイデータを取り出せるのだ．ちなみにプレイデータは正しくはチェンジセットと言う．技術的な話になるがMercurialは過去のプレイデータとの差分だけを保存しているので，チェンジ（変化）の集合（セット）と呼ぶのだ．

次は古いプレイデータ（チェンジセット）を取り出す方法を見てみよう．

# 古いデータを取り出す

いま spec.txt に加えた変更がまずかったと気がついたとしよう．今回の例のように行を足しただけならそれほど問題にはならないが，長い文章を推敲してセーブ（コミット）したが，やはり気に入らなくなったということもあるだろう．そんな時には，セーブポイント（リポジトリ）から古いデータを取り戻すことができる．

まず，念のため spec.txt を開いているエディタを閉じておこう．続けてMercurialに0番のプレイデータ（チェンジセット）を出してくれと伝えよう．こうするには `hg update 0` とすればいい．

![1*KFUR1yZqSPmfvfvh4J7gEA-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/5266c29b-7948-bf8e-5fde-db83ef9d5326.png)

この状態でエディタで spec.txt を開いてみてくれ．このように最初にセーブ（コミット）した状態に戻っているだろう．

![1*wMTNeHosMcR4NBjKFcruLw-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/be0cff18-2894-ab6b-d6b6-613d1e8e7373.png)

もちろん，2番目のプレイデータ（チェンジセット）も1番として保存されている．それを引き出してみよう．念のためエディタを閉じてから，ターミナルで次のようにしてもらいたい．いまプレイデータ（チェンジセット）の1番（つまり2番目）は最新なので，番号指定は省略できる．

![1*oZcQYdQBHeotmc9jFO_kjQ.png](https://qiita-image-store.s3.amazonaws.com/0/15782/f087b2b9-b0fb-ced5-0a9e-27090bf394c2.png)

このようにして，Mercurialを使えば歴史を行ったり来たりできるのだ．

# 平行宇宙へ行く

タイムマシンで過去に行って過去を書き換えてしまったら，当然異なった未来が訪れるだろう．

いまの spec.txt の状態を過去から未来へという図で表すとこんな感じになる． 

![1*CWagAAeWdwetl-WvtlZLEw.png](https://qiita-image-store.s3.amazonaws.com/0/15782/13ccc5bc-b8ee-59cb-4b98-1e450613df63.png)

いまいちど `hg update 0` で最初のプレイデータ（チェンジセット）である0番を呼び戻そう．

![1*2UEHFgl5sfLfbMVt5O9aHA.png](https://qiita-image-store.s3.amazonaws.com/0/15782/34cb8e68-5d6b-d873-3b50-56e2da6d7832.png)

これで一旦プレイデータ（チェンジセット）の1番のことは忘れておける．次のような状態だと思って欲しい．

![1*Kffm_mN3rOBX8AZfw1rV4Q.png](https://qiita-image-store.s3.amazonaws.com/0/15782/35c799dc-af7e-675e-2356-060285a1ba8a.png)

ここで spec.txt を編集して，次のような一文を加えたとしよう．

![1*5-Wx2bByk3ejBXauWiQpmA.png](https://qiita-image-store.s3.amazonaws.com/0/15782/8da314a2-0235-fa56-9312-e75b0df33a8c.png)

改めて `hg status` を見てみよう．

![1*V4QX17GdqHlXq0uYXITHFg-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/d8e47991-efdb-c866-0577-d5b6b35420ae.png)

すると spec.txt が改変されているので，もうお馴染みの

> M spec.txt

となっている．これをセーブポイント（リポジトリ）にセーブ（コミット）しよう．もちろん `hg commit -m ‘memo’` をすれば良い．やってみよう．

![1*Pm5NUnnbxweHDs_s3mz5wQ.png](https://qiita-image-store.s3.amazonaws.com/0/15782/d91107a3-a0e6-1958-e42e-a2fc48afc83d.png)

今度はMercurialから次のようなメッセージが来た．

> created new head

これはどういうことかというと，歴史を書き換えてしまったため，次の図のようにプレイデータ（チェンジセット）の履歴が枝分かれしていることを伝えてくれているのだ．

![1*KdWrSIK5TZP6RytKHxU5-g.png](https://qiita-image-store.s3.amazonaws.com/0/15782/781bd55e-6eb4-8318-f4a6-5ebc54e91a6f.png)

ここで `hg log spec.txt` としてみると，次のようにchangesetの2番のparentが0番になっているのがわかる．

![1*Dq1bmODh4uBMYcJO7eDW8g-2.png](https://qiita-image-store.s3.amazonaws.com/0/15782/f31f97b0-79d8-535c-bad4-3f271c7fd983.png)

ここでまた気が変わって，プレイデータ（チェンジセット）の1番を元に編集を続けたくなったとしよう．もうやり方はお分かりだと思う．スクリーンショットだけ掲載しよう．

![1*obPPD_ULKCL9DZcMSaDAlg.png](https://qiita-image-store.s3.amazonaws.com/0/15782/29317cb1-9f63-03dd-dcdb-522dd515b9b0.png)

ここで spec.txt にまたなにがしかの編集を行い，セーブ（コミット）しよう．

![1*5a4MLZATzpzbE-sAnQTmAg.png](https://qiita-image-store.s3.amazonaws.com/0/15782/58c770cd-6016-7f65-345c-c314c784d1d5.png)
![1*_G5xlGlmeUKFfUq4HogCbw.png](https://qiita-image-store.s3.amazonaws.com/0/15782/65d83a51-1518-9141-5f51-fd7db885c3b0.png)

この結果，プレイデータ（チェンジセット）の履歴は次のようになる．

![1*S8svn557fx-adFtNX7v6ug.png](https://qiita-image-store.s3.amazonaws.com/0/15782/a979569b-5783-0a01-2e6a-02034b7a1701.png)

このように，過去データをロード（チェックアウト）して編集したあとセーブポイント（リポジトリ）へセーブ（コミット）していくことで，平行宇宙を作りつつもお互い行ったり来たりできるようになるのである．

# あといくつかのコマンド

バイオハザードでは必要ないが，あといくつかの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](https://bitbucket.org/)をお勧めしたい．BitbucketはMercurialに対応しているし，無料アカウントでもリポジトリを非公開にできるからだ．以下Bitbucketを使ったバックアップ方法について述べる．

まずBitbucketで無料アカウントを作成する．Bitbucketアカウント名，パスワードは後々使うので覚えておこう．続けて[ヘルプページ](https://confluence.atlassian.com/bitbucket/import-code-from-an-existing-project-259358821.html)の “Import an existing, unversioned code project to an empty repository” という項目の5番目からを実行すれば良い．とだけ書くと不親切なので，順を追って説明しよう．なお以下の手順は将来変わるかもしれないので，参考程度にしてもらいたい．

1. Bitbucketにログインする．
1. Repositoriesメニューから Create repository サブメニューを選ぶ．
1. “Create a new repository” という画面になったら “Repository name” 項目に “Hello” と入力し “Repository type” を “Mercurial” にする．他はそのままでよい．念のため “Access level” の項目 “This is a private repository” にチェックが入っているか確認しよう．
1. “Create repository” ボタンを押す．
1. ターミナルでHelloディレクトリに移動し `hg push https://{Bitbucketユーザ名}@bitbucket.org/{Bitbucketユーザ名}/Hello` とする．途中パスワードを聞かれるので，Bitbucketで設定したパスワードを打ち込もう．（Bitbucketはリポジトリ名の大文字を小文字へ変換してしまうのでHelloはhelloでも構わない．）うまくいくと次のような画面になるだろう．
1. 最後にBitbucketのサイトに正しく保存されているか確認しよう．これには https://bitbucket.org/{Bitbucketユーザ名}/hello へアクセスすればよい．画面右手の “Recent activity” にメモ（コミットメッセージ）が並んでいれば成功だ．
1. あとは定期的に `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](https://bitbucket.org/kanaya/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` だけでよい．

---

[元記事はこちら．](https://medium.com/pineapple-blog/mercurial入門-46ff97fa3f7b#.qft59oze5)