«前の日記(2008-03-09 (日)) 最新 次の日記(2008-03-13 (木))»  

まちゅダイアリー


2008-03-11 (火)

個人で簡単に使える分散バージョン管理ツール Mercurial

先日の Trac で OpenID を使う際に、必要に迫られて Mercurial というバージョン管理ツールをインストールした。 正直なところ、バージョン管理には Subversion があるし、「分散」バージョン管理ツールなんて複雑で面倒なだけだろうと思っていた。 でも、ちょっと使ってみたら大間違い。むしろ「分散」なんて意識せずに個人で使うにはとっても向いているんじゃないか。 個人で分散バージョン管理ツールを使うべき理由はこんな感じかな。

  • 「リポジトリ」へのチェックイン、チェックアウトという概念がない。
    • わざわざワークスペースを別に用意しなくていい。
    • 作業しているディレクトリをそのままバージョン管理ツールで管理できる。
  • ネットワークに繋がっていなくてもdiffを確認できる。
  • CGIスクリプトを設置すればレンタルサーバと連携できる(設置にはシェルが必要らしい)
    • WebDAV と違ってHTTPプロキシとの親和性がいい(PROPFINDなどのメソッドをサポートしていなくてもOK)

考えてみれば、 CVS や Subversion は中央にリポジトリを置くモデルなので、 svn-admin で領域を作って、ソースをインポートして、そこからチェックアウトして、と1人で使う分には最初のセットアップがちょっと面倒。 でも、分散バージョン管理ツールの場合はそれぞれのマシンがリポジトリになれる。 ということは、別に他のマシンと連携しなくても、そのマシンだけで完結しているというメリットがあること。

これは使わざるを得ない。 って訳で、一人で使う分で必要になる操作を簡単にまとめてみたよ。 構成は、結城さんのSubversionの基礎練習を参考にさせてもらった。

インストール

Mercurial の公式サイトに Windows 用、 Mac 用、 Debian, Ubuntu, RedHat のそれぞれのバイナリパッケージが置いてあるので、それを入れるだけでOK。

バージョン管理するファイルの作成

まずはバージョン管理したいディレクトリを作って、その中にファイルを追加する。 今回は test1.txt, test2.txt とした。

$ mkdir hgtest
$ cd hgtest
$ vi test1.txt
$ vi test2.txt
$ ls
test1.txt       test2.txt

リポジトリの作成

Subversion が svn というコマンドを使うように、 Mercurial は hg というコマンドを使う。 管理したいディレクトリに移動して、 init コマンドを発行するだけで OK 。 Subversion の svn-admin create と import を同時にやっているような感じ。

$ hg init

これで、カレントディレクトリに .hg ディレクトリが作成され、このディレクトリが Mercurial の管理下に入る。 hg stat で管理状態が確認できる。まだファイルを追加していないので「?」が表示される。

$ hg stat
? test1.txt
? test2.txt

add コマンドでファイルを追加し commit コマンドでリポジトリへ反映する。

$ hg add *
$ hg commit -m 'first import'

この辺は Subversion と同じだなぁ。 面倒なインポートやチェックアウトが無く、作業中のディレクトリをそのまま管理対象にできるので Subversion より最初の敷居が低い。

管理用の .hg というディレクトリが作られている。Subversion と違ってトップのディレクトリのみに作られるっぽい。

$ ls .hg
00changelog.i   requires        undo.branch
dirstate        store/          undo.dirstate

ファイルの差分を確認する

追加したファイルを変更してみる。

$ vi test1.txt

hg diff で差分をみることができる。

diff -r 3b701cee8925 test1.txt
--- a/test1.txt Wed Mar 12 01:31:25 2008 +0900
+++ b/test1.txt Wed Mar 12 01:36:26 2008 +0900
@@ -1,1 +1,1 @@
-hello mercurial
+good night...

変更内容を戻す場合は revert が使える。 revert すると変更中のファイルが .orig として残る。 うっかり revert して作業中のファイルを消した人には助かる機能。

$ hg revert test1.txt
$ ls
test1.txt  test1.txt.orig  test2.txt

あと、ファイルを消した場合は hg update で復活(最後にコミットした状態で)。

コミットと履歴の確認

変更点をコミットしてコミットログを表示。

$ hg commit -m 'test1.txt: hello to good night'
$ hg log 
changeset:   1:bd8bcd244b94
tag:         tip
user:        machu@macbook.local
date:        Wed Mar 12 01:37:00 2008 +0900
summary:     test1.txt: hello to good night

changeset:   0:3b701cee8925
user:        machu@macbook.local
date:        Wed Mar 12 01:31:25 2008 +0900
summary:     first commit

Subversion と違ってリポジトリが手元にあるので、コミットしたリビジョンの diff も簡単に確認できる。

$ hg diff -r 0:1
diff -r 3b701cee8925 -r bd8bcd244b94 test1.txt
--- a/test1.txt Wed Mar 12 01:31:25 2008 +0900
+++ b/test1.txt Wed Mar 12 01:37:00 2008 +0900
@@ -1,1 +1,1 @@
-hello mercurial
+good night...

ファイル名の変更

ファイル名の変更は rename 。svn move と同じかな。

$ hg rename test1.txt test3.txt
$ hg stat
M test1.txt.orig
A test3.txt
R test1.txt

でも commit したら前のファイルも .orig として残った。

$ hg commit -m 'rename test1.txt to test3.txt'
$ ls
test1.txt.orig  test2.txt       test3.txt

ヘルプをみたら copy + remove と書いてあった。

rename       rename files; equivalent of copy + remove

HTTP サーバ

serve コマンドで HTTP サーバが起動する。

$ hg serve

デフォルトポートは8000番。変えたい時は --port オプションで指定できる。

$ hg serve --port 8080

リポジトリの削除

トップディレクトリにある .hg ディレクトリを丸ごと消せば、何事もなかったかのようにバージョン管理していない状態に戻る。

その他のコマンド

その他のコマンド類は help で確認できる。

$ hg help
Mercurial Distributed SCM

list of commands:

 add          add the specified files on the next commit
 addremove    add all new files, delete all missing files
 annotate     show changeset information per file line
 archive      create unversioned archive of a repository revision
 backout      reverse effect of earlier changeset
 bisect       subdivision search of changesets
 branch       set or show the current branch name
 branches     list repository named branches
 bundle       create a changegroup file
 cat          output the current or given revision of files
 clone        make a copy of an existing repository
 commit       commit the specified files or all outstanding changes
 copy         mark files as copied for the next commit
 diff         diff repository (or selected files)
 export       dump the header and diffs for one or more changesets
 grep         search for a pattern in specified files and revisions
 heads        show current repository heads or show branch heads
 help         show help for a command, extension, or list of commands
 identify     identify the working copy or specified revision
 import       import an ordered set of patches
 incoming     show new changesets found in source
 init         create a new repository in the given directory
 locate       locate files matching specific patterns
 log          show revision history of entire repository or files
 manifest     output the current or given revision of the project manifest
 merge        merge working directory with another revision
 outgoing     show changesets not found in destination
 parents      show the parents of the working dir or revision
 paths        show definition of symbolic path names
 pull         pull changes from the specified source
 push         push changes to the specified destination
 recover      roll back an interrupted transaction
 remove       remove the specified files on the next commit
 rename       rename files; equivalent of copy + remove
 revert       restore individual files or dirs to an earlier state
 rollback     roll back the last transaction
 root         print the root (top) of the current working dir
 serve        export the repository via HTTP
 showconfig   show combined config settings from all hgrc files
 status       show changed files in the working directory
 tag          add a tag for the current or given revision
 tags         list repository tags
 tip          show the tip revision
 unbundle     apply one or more changegroup files
 update       update working directory
 verify       verify the integrity of the repository
 version      output version and copyright information

まとめ

「分散」バージョン管理ツールと聞くと、 Subversion などの集中型のバージョン管理ツールよりも難しい印象があったけど、むしろそれよりも分かりやすくて便利。 ブランチやタグや他のリポジトリとの連携は試していないけど、1人で使うだけならそこまで知らなくても十分に使える。 ということで、これまで使っていた個人リポジトリは Subversion から Mercurial へと移行してみようかな。 もちろん、チームで使う場合はこれまで通り Subversion を使うけどね。

はてぶのMercurialタグで関連する情報を調べられる。 こういう珍しい名前だとノイズが入らなくていいね。

Tags: mercurial

Mercurial で1人バージョン管理(複数マシンでの連携編)

作業中のディレクトリをそのまま気軽にバージョン管理できることが、1人だけでバージョン管理を使う時のメリットだと思っているけど、複数のマシンでリポジトリを同期させることももちろんできる。

「分散」リポジトリというだけあって、いろいろ機能がありそうだけど、とりあえず1人で使う時に必要なことだけを覚えた。

リポジトリのコピー

他のディレクトリやマシンからリポジトリを取得する。 Subversion での checkout に近いけど、 Mercurial はリポジトリ全体を丸ごとコピーするところが違う。 リポジトリが大きくなると時間かかりそうだけど、1人で使うレベルなら気にならないかな。 丸ごとコピーなので、コマンド名も clone になってる。 コピーしたいマシン上で clone コマンドを実行。 svn serve や CGI スクリプトで HTTP サーバを立てていれば、 SSH 以外に HTTP でも接続可能。 でも、 svn serve だと書き込みを許可するために設定がいるっぽい。

$ hg clone ssh://192.168.0.211/work/hgtest hgtest
requesting all changes
adding changesets
adding manifests
adding file changes
added 5 changesets with 7 changes to 3 files
3 files updated, 0 files merged, 0 files removed, 0 files unresolved

コピー元は path コマンドで確認できる。

$ hg path
default = ssh://192.168.0.211/work/hgtest

コピーした先でも自由に追加やコミットができる。 この時点ではコピー元のリポジトリへは反映されない。

$ vi test1.txt
$ hg commit -m 'text1.txt: update'
$ vi test2.txt
$ hg commit -m 'text2.txt: update'

現在のバージョン(チェンジセット)は tip コマンドで確認できる。 Subversion での trunk みたいなもの?

$ hg tip
changeset:   6:383b26fa4dc6
tag:         tip
user:        matsuoka@ubuntu2.localdomain
date:        Tue Mar 11 06:01:32 2008 +0900
summary:     text2.txt: update

コピー元との差分は outgoing コマンドで確認できる。 -p オプションを付ければ履歴も分かる。

$ hg outgoing -p
comparing with ssh://192.168.0.211/work/hgtest
searching for changes
changeset:   5:e0016f8b092c
user:        matsuoka@ubuntu2.localdomain
date:        Tue Mar 11 06:00:51 2008 +0900
summary:     test1.txt

diff -r 1735accccbf1 -r e0016f8b092c test1.txt
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/test1.txt Tue Mar 11 06:00:51 2008 +0900
@@ -0,0 +1,2 @@
+aaaa
+aa

changeset:   6:383b26fa4dc6
tag:         tip
user:        matsuoka@ubuntu2.localdomain
date:        Tue Mar 11 06:01:32 2008 +0900
summary:     text2.txt: update

diff -r e0016f8b092c -r 383b26fa4dc6 test2.txt
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/test2.txt Tue Mar 11 06:01:32 2008 +0900
@@ -0,0 +1,4 @@
+aaa
+aa
+aaaa
+

変更内容をコピー元に反映してよければ、 push コマンドを実行する。

$ hg push
pushing to ssh://192.168.0.211/work/hgtest
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 2 changesets with 2 changes to 2 files

変更内容を破棄したければ、コピー先のディレクトリを丸ごと消せば OK 。

まとめ

「分散」になると難しくなるかなーと思っていたけど、実は簡単だった。

  • svn checkout, svn commit の代わりに hg pull, hg push を使う
  • svn diff の代わりに hg outgoing -p を使う

1人で使う分にはこれで十分な感じ。 あぁ、これ、リモートの Web サイトの管理にも使えるなぁ。 ローカルでファイルを修正して、 hg pull でレンタルサーバに反映させるとか。

グループで使う時にはちゃんと考えて運用しないと大変そうだけど。

参考

Tags: mercurial
本日のツッコミ(全4件) [ツッコミを入れる]
dayflower (2008-03-12 (水) 04:26)

"hg add *" のところは,"hg addremove" や "hg commit -A" とか素敵機能もついてまう。

dataich (2008-03-12 (水) 05:55)

分かりやすくまとめられていますねー^^<br>GITと違ってTortoiseHGがあるのもいいですね。<br>ていうかすでにGIT用のGUIクライアントがあるのか???

まちゅ (2008-03-13 (木) 14:40)

>dayflowerさん<br>おおっ。カユいところに手が届く感じなのがいいですね。<br>日記も参考にさせてもらってます。

まちゅ (2008-03-13 (木) 14:41)

>dataichさん<br>SubversionでもTortoiseSVN入れたもののほとんど使わずじまいでした。<br>Windowsだと日本語ファイルで問題が起こりそうですね。