Mercurial ~ ひと通り(個人で)

前置き

定番のワークフローの中でも、自分だけの世界で(実際はもっと限定して、1つのリポジトリだけで)完結する作業について、ひと通り解説します。用語についてはコンセプトを参照して下さい。

本文

サンプルプロジェクト

何かリアルな実例(例えば、プログラム開発とか書籍の共同執筆とか)を使って説明した方が分かりやすいのかもしれませんが、ここでは何の意味もないサンプルプロジェクトを使います。このプロジェクトにはfooとかbarのような意味のないファイルがあり、その中身は"a"とか"b"のような単純なものです。

fooやbarを編集する様子を「fooの3行目に"c"を書き足す」などと書くと煩わしいので、echoコマンドを使って編集の代替としました。要所でcatコマンドによりファイルの内容を表示するようにしています。

まずは、サンプルプロジェクト用の作業ディレクトリとして、proj1を作ります。

~ $ mkdir sandbox/proj1
~ $ cd sandbox/proj1
~/sandbox/proj1 $

hgコマンド

Mercurialのコマンド名はhgです。オプションなしで実行すると簡単なusageが表示されます。

~/sandbox/proj1 $ hg
Mercurial - 分散構成管理ツール

基本コマンド:

 add        指定ファイルの追加登録予約
 annotate   ファイル行毎のリビジョン情報表示
 clone      既存リポジトリの複製
 commit     指定ファイルないし全ての変更内容のリポジトリへの記録
 diff       作業領域全体(ないし指定ファイル)の差分抽出
 export     1つ以上のリビジョンに対するヘッダおよび変更内容の出力
 forget     次回コミットにおける指定ファイルの登録除外
 init       指定されたディレクトリでの新規リポジトリの作成
 log        リポジトリ全体ないしファイルの変更履歴の表示
 merge      作業領域の内容と他のリビジョンのマージ
 pull       指定リポジトリからの変更履歴の取り込み
 push       指定リポジトリへの変更履歴の反映
 remove     次回コミットにおける指定ファイルの登録除外
 serve      HTTP 経由でのリポジトリの公開
 status     作業領域のファイル操作状況の表示
 summary    作業領域状態の概要表示
 update     作業領域の更新

全コマンドの一覧は "hg help" で、コマンド詳細は "hg -v" で表示されます

初期化(新規リポジトリの作成)

今のところproj1ディレクトリは空っぽです。ここに新規リポジトリを作成します。

~/sandbox/proj1 $ ls -a
.  ..
~/sandbox/proj1 $ hg init
~/sandbox/proj1 $ ls -a
.  ..  .hg

プロジェクトにファイルを追加

プロジェクトにファイルfooを追加し、それをリポジトリへ登録します。

~/sandbox/proj1 $ echo a >>foo        # fooを生成。
~/sandbox/proj1 $ hg sta              # リポジトリの状態を見る。
? foo
~/sandbox/proj1 $ hg add              # fooを管理対象としてリポジトリへ登録。
foo を追加登録中
~/sandbox/proj1 $ hg sta
A foo
~/sandbox/proj1 $ hg com -m "add foo" # コミット。
~/sandbox/proj1 $ hg sta
~/sandbox/proj1 $ hg sta -c           # 変更の無いファイルも表示。
C foo

リポジトリの状態を表示したときにファイル名の先頭に付いている記号には以下のような意味があります。

  • M:Modified
  • A:Added
  • R:Removed
  • !:Missing
  • ?:Not tracked
  • I:Ignored
  • C:Clean

デフォルトではCleanなファイルは表示されませんが、-cオプションを付けると表示されます。

上記の例ではコミット時に-mオプションを使ってコメントを登録していますが、-mオプションを付けなかった場合はエディタが起動されるので、そこへコメントを入力してからエディタを保存終了して下さい。

プロジェクトのファイルを編集

次にfooを編集してみましょう。

~/sandbox/proj1 $ echo b >>foo               # fooを編集。
~/sandbox/proj1 $ hg com -m "edit foo(b)"
~/sandbox/proj1 $ echo c >>foo               # さらに編集。
~/sandbox/proj1 $ hg com -m "edit foo(c)"
~/sandbox/proj1 $ cat foo                    # 現在のfooの内容。
a
b
c
~/sandbox/proj1 $ hg log                     # これまでのログ。
チェンジセット:   2:434dd1159ca5
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:36:18 2011 +0900
要約:             edit foo(c)

チェンジセット:   1:931b1380343a
ユーザ:           maru
日付:             Tue Apr 19 18:36:08 2011 +0900
要約:             edit foo(b)

チェンジセット:   0:c8d28627af9b
ユーザ:           maru
日付:             Tue Apr 19 18:35:31 2011 +0900
要約:             add foo

3回のコミットを経て、最新(ティップ)リビジョンはR2です。

commmit

過去リビジョンの参照

古いリビジョンの内容を表示したり差異を調べてみましょう。

~/sandbox/proj1 $ hg cat -r 1 foo      # R1のfooを表示。
a
b
~/sandbox/proj1 $ echo d >>foo         # fooを編集。
~/sandbox/proj1 $ hg diff foo          # fooの作業ディレクトリ版とティップ版を比較。
diff -r 434dd1159ca5 foo
--- a/foo       Tue Apr 19 18:36:18 2011 +0900
+++ b/foo       Tue Apr 19 18:37:56 2011 +0900
@@ -1,3 +1,4 @@
 a
 b
 c
+d
~/sandbox/proj1 $ hg diff -r 1 foo     # fooの作業ディレクトリ版とリビジョンR1を比較。
diff -r 931b1380343a foo
--- a/foo       Tue Apr 19 18:36:08 2011 +0900
+++ b/foo       Tue Apr 19 18:38:04 2011 +0900
@@ -1,2 +1,4 @@
 a
 b
+c
+d
~/sandbox/proj1 $ hg diff -r 0:1 foo   # fooのリビジョンR0とR1を比較。
diff -r c8d28627af9b -r 931b1380343a foo
--- a/foo       Tue Apr 19 18:35:31 2011 +0900
+++ b/foo       Tue Apr 19 18:36:08 2011 +0900
@@ -1,1 +1,2 @@
 a
+b
~/sandbox/proj1 $ hg com -m "edit foo(d)"  # コミット。

作業ディレクトリの親リビジョンを変える

さて、ここまで4回コミットしましたが、いつも作業ディレクトリの親はティップでした(つまりティップに対してコミットしてきた)。ここで、作業ディレクトリの内容を古いリビジョンに入れ替えてみましょう。

~/sandbox/proj1 $ hg parents               # 親リビジョンを表示(現在はティップ)。
チェンジセット:   3:c6a9db7df968
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:38:45 2011 +0900
要約:             edit foo(d)

~/sandbox/proj1 $ hg update -r 1           # 作業ディレクトリをR1に入れ替え。
ファイル状態: 更新数 1、マージ数 0、削除数 0、衝突未解決数 0
~/sandbox/proj1 $ hg parents               # 親がR1に変わった。
チェンジセット:   1:931b1380343a
ユーザ:           maru
日付:             Tue Apr 19 18:36:08 2011 +0900
要約:             edit foo(b)

~/sandbox/proj1 $ cat foo
a
b
~/sandbox/proj1 $ hg update                # 親をティップに戻す。
ファイル状態: 更新数 1、マージ数 0、削除数 0、衝突未解決数 0
~/sandbox/proj1 $ hg parents
チェンジセット:   3:c6a9db7df968
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:38:45 2011 +0900
要約:             edit foo(d)

updateコマンドにより作業ディレクトリの内容を入れ替えることができますが、これは作業ディレクトリの親を変更していることと同じなのです。

update

古いリビジョンが親になっている状態で作業ディレクトリのファイルを編集しても構いません。その後でコミットすると新しいブランチが生成されます(詳しくは別の記事コンセプトブランチを参照)。

作業ディレクトリに未コミットのファイルが残っている状態でupdateした場合(つまり親リビジョンを変えようとした場合)、オプションによって挙動が異なります。例として、親をR1に変えた後でfooを編集した(コミットしてない)状態を考えます。ここでhg updateすると、以下のような結果になります。

(a) $ hg update      # 編集したfooとティップのfooをマージして作業ディレクトリに置く。
(b) $ hg update -c   # 未コミットのファイルがあるため、updateは失敗する。
(c) $ hg update -C   # 未コミットのファイルは破棄して、ティップのファイルを作業ディレクトリへ置く。

複数のファイルとサブディレクトリ

では、さらにプロジェクトを修正していきます。foo以外のファイルも追加してみましょう。

~/sandbox/proj1 $ echo a >>bar
~/sandbox/proj1 $ mkdir sub
~/sandbox/proj1 $ cd sub
~/sandbox/proj1/sub $ echo a >>buz
~/sandbox/proj1/sub $ hg sta
? bar
? sub/buz
~/sandbox/proj1/sub $ hg add
../bar を追加登録中
buz を追加登録中
~/sandbox/proj1/sub $ hg sta
A bar
A sub/buz
~/sandbox/proj1/sub $ hg com -m "add bar and sub/buz"
~/sandbox/proj1/sub $ hg log -l 3
チェンジセット:   4:66762a649349
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:42:59 2011 +0900
要約:             add bar and sub/buz

チェンジセット:   3:c6a9db7df968
ユーザ:           maru
日付:             Tue Apr 19 18:38:45 2011 +0900
要約:             edit foo(d)

チェンジセット:   2:434dd1159ca5
ユーザ:           maru
日付:             Tue Apr 19 18:36:18 2011 +0900
要約:             edit foo(c)

コミットするときのカレントディレクトリは、(proj1の下なら)どこでも構いません。

ファイル名を変更する

ファイル名を変更する場合は、シェルコマンド(mvとか)を使わずにhgのrenameコマンドを使いましょう。シェルコマンドを使っても構いませんが、その場合、hgはファイル名変更の前後で別々のファイルとして管理します。

~/sandbox/proj1/sub $ cd ..
~/sandbox/proj1 $ cat bar
a
~/sandbox/proj1 $ echo b >>bar
~/sandbox/proj1 $ hg com -m "edit bar(b)"
~/sandbox/proj1 $ echo c >>bar
~/sandbox/proj1 $ hg com -m "edit bar(c)"
~/sandbox/proj1 $ hg rename bar barrr      # barをbarrrに変更。
~/sandbox/proj1 $ hg sta
A barrr
R bar
~/sandbox/proj1 $ hg com -m "rename bar to barrr"
~/sandbox/proj1 $ hg sta
~/sandbox/proj1 $ cat barrr
a
b
c
~/sandbox/proj1 $ echo d >>barrr
~/sandbox/proj1 $ hg com -m "edit barrr(d)"
~/sandbox/proj1 $ hg log barrr             # barrrのログを表示(ファイル名変更後のログのみ)。
チェンジセット:   8:b63d3a430609
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:44:31 2011 +0900
要約:             edit barrr(d)

チェンジセット:   7:e15b7674791e
ユーザ:           maru
日付:             Tue Apr 19 18:44:09 2011 +0900
要約:             rename bar to barrr

~/sandbox/proj1 $ hg log barrr -f -l 3     # -fオプションでファイル名変更前のログも表示。
チェンジセット:   8:b63d3a430609
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:44:31 2011 +0900
要約:             edit barrr(d)

チェンジセット:   7:e15b7674791e
ユーザ:           maru
日付:             Tue Apr 19 18:44:09 2011 +0900
要約:             rename bar to barrr

チェンジセット:   6:ea4917b81d35
ユーザ:           maru
日付:             Tue Apr 19 18:43:49 2011 +0900
要約:             edit bar(c)

このように、hg renameすると、元のファイルが削除されて新しいファイルが追加されます。一見、別々のファイルとして管理されているように見えますが、-fオプション付きでlogを見ると、旧ファイル名のときのlogも表示されるのが分かります(シェルコマンドでファイル名を変更すると、こうはいきません)。

ファイルを削除する

ファイルの削除もシェルコマンドではなくhgのremoveコマンドを使いましょう。シェルコマンドで削除した場合でも、hg removeによりリポジトリの管理対象から外す必要があります。

~/sandbox/proj1 $ hg remove barrr          # barrrを削除。
~/sandbox/proj1 $ hg sta
R barrr
~/sandbox/proj1 $ hg com -m "remove barrr"
~/sandbox/proj1 $ ls
foo  sub
~/sandbox/proj1 $ hg log -l 2
チェンジセット:   9:50f3095c9a73
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:46:29 2011 +0900
要約:             remove barrr

チェンジセット:   8:b63d3a430609
ユーザ:           maru
日付:             Tue Apr 19 18:44:31 2011 +0900
要約:             edit barrr(d)

hgを使わずに大量のファイルを削除してしまった場合、それら1つ1つに対してhg removeするのは面倒ですね。hg addremoveか、hg remove --afterで、一気にリポジトリの管理対象から外すことができます。addremoveには「未追加のファイルをリポジトリに追加する」という作用もあります。また、remove --afterは存在するファイルに対しては作用しませんが、警告が大量に出るので初めて使うときはビックリします。

タグを付ける

タグは、特定のリビジョンに対するaliasです。

~/sandbox/proj1 $ hg tag VERSION1.0        # 現在のティップ(R9)にタグ"VERSION1.0"を付ける。
~/sandbox/proj1 $ ls -a                    # タグを管理するファイル .hgtags が生成された。
.  ..  .hg  .hgtags  foo  sub
~/sandbox/proj1 $ hg log -l 2              # リビジョン番号が1つ上がってR10になった。
チェンジセット:   10:2f178affaf0d
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:47:13 2011 +0900
要約:             Added tag VERSION1.0 for changeset 50f3095c9a73

チェンジセット:   9:50f3095c9a73
タグ:             VERSION1.0
ユーザ:           maru
日付:             Tue Apr 19 18:46:29 2011 +0900
要約:             remove barrr

~/sandbox/proj1 $ hg sta -c                # .hgtagsもMercurialの管理対象。
C .hgtags
C foo
C sub/buz
~/sandbox/proj1 $ hg update -r 0           # 親をR0に変える。
ファイル状態: 更新数 1、マージ数 0、削除数 1、衝突未解決数 0
~/sandbox/proj1 $ hg parents
チェンジセット:   0:c8d28627af9b
ユーザ:           maru
日付:             Tue Apr 19 18:35:31 2011 +0900
要約:             add foo

~/sandbox/proj1 $ ls -a
.  ..  .hg  foo
~/sandbox/proj1 $ hg update -r VERSION1.0  # 親をVERSION1.0(つまりR9)に変える。
ファイル状態: 更新数 2、マージ数 0、削除数 0、衝突未解決数 0
~/sandbox/proj1 $ hg parents
チェンジセット:   9:50f3095c9a73
タグ:             VERSION1.0
ユーザ:           maru
日付:             Tue Apr 19 18:46:29 2011 +0900
要約:             remove barrr

~/sandbox/proj1 $ ls -a                    # このリビジョンには、まだ .hgtags は無い。
.  ..  .hg  foo  sub
~/sandbox/proj1 $ hg update                # 親をティップに変える。
ファイル状態: 更新数 1、マージ数 0、削除数 0、衝突未解決数 0
~/sandbox/proj1 $ hg parents
チェンジセット:   10:2f178affaf0d
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:47:13 2011 +0900
要約:             Added tag VERSION1.0 for changeset 50f3095c9a73

~/sandbox/proj1 $ ls -a                    # これ以降は .hgtags が存在する。
.  ..  .hg  .hgtags  foo  sub
~/sandbox/proj1 $ cat .hgtags              # .hgtagsは単純なテキストファイル。
50f3095c9a732b0850284225acca6081e9907644 VERSION1.0
~/sandbox/proj1 $ hg log .hgtags
チェンジセット:   10:2f178affaf0d
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:47:13 2011 +0900
要約:             Added tag VERSION1.0 for changeset 50f3095c9a73

~/sandbox/proj1 $ hg tags                  # 現在のタグ一覧。
tip                               10:2f178affaf0d
VERSION1.0                         9:50f3095c9a73

このように、hg tagを実行すると、(1)特定リビジョンへのタグ付けと、(2)タグ管理ファイルのコミットの2ステップが一気に行われます。hg tagによってリビジョンが1つ増えます。

Last modified:2011/06/15 00:01:16
Keyword(s):
References:[Mercurial(分散SCM)] [Mercurial ~ ひと通り(チームで)] [Mercurial ~ ブランチ] [Mercurial ~ 間違ったら]
This page is frozen.