「Mercurial」バージョン管理システムについてメモ。
Mercurialという分散型バージョン管理システムについて、@kerukerupappa さんに本をお借りしたのでメモを取りながら読書しているので自分の忘備録として書いておきます。見やすさとか気にしないで書くので読みづらいと思いますm(__)m 詳しいとこと手抜きなとこがあったり、途中で書き方が変わったりもします。
ちなみに、借りた本だから手元に無くなる前にメモを取らないとと思ってメモを取ってみましたが、inputとoutputを同時に行うせいか、ただ読むよりずっと理解ができました。他の本を読むときも出来ればメモを取りたいと思います。が、難点は時間がかかること。読みたい本が色々あるから悩ましいです。いい読書の方法を模索中です。
Mercurial = 「構成管理」ツール。概ね履歴管理の意味。
cvs,subversion は中央集権的。ネット接続が必要。規模が大きくなるとつらい。
Mercurialの特徴
◯分散リポジトリ
構成管理情報のフルセットのコピーが利用者全員の手元にある。ネットができなくても構成管理操作を行える。
全員が同一のデータを共有する保証の仕組みはない →運用ルールを定める
◯チェンジセット指向
「誰が、どの時点の情報に対して、いつ、どのように」複数のファイルを一括して記録する際に、ファイル横断的に一括して記録
↓
ある変更を実施した時点での全てのファイルの状態を完全に再現できる。
MercurialはPythonで実装されている。←メモリリークが無い。変更が容易。
他の分散リポジトリ形式を採用しているツール・・・git,Bazaar-NG,darc
分散リポジトリ形式は全体の成果を集約するリポジトリサーバーの他に中間的なリポジトリサーバーを設けることで負荷分散が容易。
タイムマシンとしてのMercurial
制約
・あらかじめセットした領域でしか機能しない
・時間を遡れるのは登録したファイルのみ
・特定の時点にしか遡れない
領域のセットアップ
$ cd ~ /対象ディレクトリ
$ hg init
(hg init ディレクトリ名、でディレクトリが作成される)
hg init した領域をリポジトリと呼ぶ
.hgというディレクトリができる。管理情報なのでここに書き込まないこと。他は作業領域。
ファイルの登録
$ hg status コマンドを実行してみると
? index.html
のように先頭に?が着いたファイルの一覧が表示される。
$ hg add index.html コマンドを実行すると
index.htmlファイルが登録される。
$ hg status index.html コマンドを実行すると
A index.html
のように先頭にAが付く。
Mercurialはテキストファイルとバイナリファイルの判別を自動で行う。
リビジョンの作成
遡ることのできるポイントをリビジョン(revision)と呼ぶ。
(「リビジョン」「バージョン」以外にも「チェンジセット」と呼ばれることもある)
コミットの実施
$ hg commit コマンドを使う
$ hg commit -m 'コミットメッセージ' のように-mを使ってコミットメッセージを登録できる。
$ hg commit -1 message.txt のようにするとmessage.txtの内容をコミットメッセージとして使用できる。
コミット履歴の参照
$ hg log コマンドを使う
$ hg log -r 1 のように-rオプションで指定したリビジョンを表示できる。
コミット詳細の参照
$ hg log -v コマンドを使う
$ hg log -p -r 2 index.html
のようにすると各ファイルの具体的な変更内容を表示できる。その際は-rオプションを付けてリビジョンを指定すること。
ファイル内容の由来を調べる
$ hg annotate コマンドを使う
ファイルの各行がどのリビジョンの時点で書かれたか表示する。
過去の状態の再現
$ hg parents
このコマンドを実行すると現時点の作業領域がどのリビジョンか表示する。これが現在時刻に相当する。
$ hg update 3
リビジョン番号3まで遡る。
hg updateが失敗する時は、addしてもcommitしていない場合がほとんど。
うっかり枝分かれさせてしまった場合、
$ hg head
の出力に2つ以上のリビジョンが表示されるか否かで枝分かれの有無を判定できる。こうなったらmergeを実行して枝分かれを解消する。
一括して取り出して出力する
$ hg archive -r 2 /tmp/mywork .%h
のように実行すると、/tmp/myworkに出力される。.%hは取り出し対象リビジョンのハッシュIDで置き換えられる(?よくわからん)
-t オプションでアーカイブ形式で出力できる。
$ hg cat -r 1 index.html
hg cat を使うと、特定のファイルのみ取り出す。
-o オプションで保存先ファイル名を指定できる。
目印を付ける
リビジョン番号やハッシュIDは数値なのでわかりづらい。
$ hg tag -r 1 reviewed-1
のように実行すると、reviewed-1という名前でタグを付けることができる。
$ hg tags
現時点でのタグ一覧表示
「tip」というタグが表示されるが、これはMercurialが自動で生成する「そのリポジトリにおける最新のリビジョン」を指す特別なもの。
$ hg log -r tip
このコマンドは
$ hg tip
とおなじ
記録対象からの除外
$ hg remove casestudy/0001.html
を実行すると、casestudy/0001.htmlが除外される。
$ hg status コマンドを実行すると
R casestudy/0001.html
のように先頭にR が付く。リムーブされたファイルを表す。
除外したら $ hg commit で確定する
除外しても記録は残る。
ファイルの変更の取り消し
hg update だと「全体」を復元するので、”hg revert”を使用する。
$ hg status を実行すると
M index.html のように表示される。Mは変更されていることを表す。
$ hg revert index.html を実行すると変更を取り消して親リビジョン時点の状態に戻る。ディレクトリも指定できる。ファイルを削除してしまった場合にも適用可能。
Mercurialコマンドの取り消し
"hg commit"以外なら、”hg revert”で取り消しできる。
1.ファイルを変更
2.”hg add”
3."hg revert"
の順で実行した場合、add が取り消されるが、ファイルの変更は取り消されない。
hg commitの取り消し
$ hg rollback
直前のcommit実行が取り消される。
hg commitをまたいだ取り消し
ファイル内容の復元
”hg revert”に-r オプションを付けると復元される際のファイルの内容を指定したリビジョン時点のものにすることができる。
ファイル名の付け直し
"hg copy"で複製する
$ hg rename A B でリネーム
ローカルマシン上でリポジトリを複製する
全体の複製
$ hg clone A A-backup
AがA-backupという名前でリポジトリが複製される。
"hg init"は必要ない
部分の複製
差分だけが欲しい時。
"hg pull" ・・・自リポジトリ←他リポジトリという取り込み
"hg push"・・・自リポジトリ→他リポジトリという反映
ネットワーク越しでリポジトリを複製する
SSH経由のネットワーク連携が一番
全体の複製
$ hg clone ssh://hguser@hgserver/path/to/repo A-backup
ローカルマシン上でリポジトリを複製する方法の複製元の部分がネットワークのアドレスに変わるだけ。
この例では、hguserはユーザー名、@hgserverはサーバー名。
path/to/repo はホームディレクトリからの相対位置。パス表記を"//"で始めると絶対パス。
部分の複製
"hg pull"や"hg push"もリポジトリ指定をssh:で始まる表記になる以外はローカルと同じ要領。
$ hg paths を実行すると
default = ssh://hguser@hgserver/path/to/repo と表示される
これは、連携先リポジトリとして「defalut」が指定された場合は、ssh://hguser@hgserver/path/to/repoとみなす。の意味。
$ hg pull default を実行すると
ssh://hguser@hgserver/path/to/repoからpullするのと同じ。
"hg clone"で複製したリポジトリの場合、複製元のリポジトリの場所が自動的にdefaultとして設定される。
複製されたリポジトリ同士は、普段は何の連携処理を行なっていない。一方全く同じ状態を元に、全く異なるリビジョンを保持するようになる。
分岐したリビジョンを一つの成果に統合するマージ(merge)の説明
Mercurialでは、子リビジョンを持たないリビジョンをヘッド(head)と呼ぶ。
リポジトリ中のヘッドの一覧は、"hg heads" で表示される。(通常一つのリビジョンしか表示されない)
例えば、"hg pull" で別リポジトリの成果を取り込んだ際に以下のような表示を目にすることがある。
added 1 changesets with 1 changes to 1 files (+1 heads)
(+1 heads)に注目!
これがヘッドが複数ある(multiple heads)状態。複数のヘッドがある状態では、一方のヘッドで実施した変更は他方のヘッドには影響を与えない。
マージの実施
対象を決める
Mercurialが一度にマージできるのは2つのヘッドまでなので、3つ以上ある時はマージを繰り返す。
マージの開始
念のため"hg parent" で親リビジョンを確認しておく。
万一マージ対象とするリビジョンと異なる場合は、"hg update" を実行して親リビジョンを変更する。
特に"hg update" によるリビジョン移動を多用している場合はこの手順が重要。
親リビジョンを確認し終えたら"hg merge" を実行する(commitするまで完了ではない)
$ hg merge
ヘッドが3つ以上ある時などは引数にマージ対象リビジョンを指定する。
衝突の解消
同一箇所に異なる変更を加えているとマージでエラーメッセージが出る。この状態を「衝突(conflict)」という。
「衝突」している箇所に対してマージ結果としての適切な内容を指定することを「衝突の解消」ないし「解消(resolve)」という。
対話的なマージツールの場合なら画面に従って解消を行う。対話的じゃない時→ぐぐろう
$ hg resolve -1
で各ファイルのマージ状況を見ることができる。
手動で衝突を解消したらそれをMercurialに通知するために以下を実行する。
$ hg resolve -m ファイル名
ファイル名を指定しないと衝突が検知された全てのファイルが操作対象となるため注意する。
マージの完了
"hg commit" により新たなリビジョンとして記録する。