Mercurialをソースコードからインストールする
基本的にterminal上で使うアプリケーション(エディタ、言語処理系、細かなツール等)は、ソースコードからビルドして使うようにしている。
複数の版を使えるようにしたいのもあるし、なによりビルドすることが好きだからだ。
Mercurialをビルドする前に、docutilsを使えるようにしておこう。Mercurialのドキュメントはdoctuilsを使って生成している。
pythonモジュールなのでpipを使うのが簡単だ。
ソースからインストールする場合Docutils: Documentation Utilitiesから最新のものを取得しよう。
$ tar zxf docutils-0.7.tar.gz $ cd docutils/ $ ./setup.py install
pipならコマンドを叩くだけでいい。
$ pip install docutils
これでMercurialをインストールする準備が整った。Mercurialのソースコードを取得しよう。
$ wget http://mercurial.selenic.com/release/mercurial-1.9.tar.gz $ tar zxf mercurial-1.9.tar.gz $ cd mercurial-1.9
デフォルトでは/usr/local以下にインストールされるので、任意の場所にインストールする。 Makefileのコメントにあるように、makeを実行するときにPREFIXを指定する。
$ vim Makefile # If you want to change PREFIX, do not just edit it below. The changed # value wont get passed on to recursive make calls. You should instead # override the variable on the command like: # # % make PREFIX=/opt/ install PREFIX=/usr/local export PREFIX $ make PREFIX=/path/to/install/dir install
これでMercurialをインストールできた。
Mercurialで築いたコミットを並び替える
DVCS(GitやMercurialなど)の利点は、コードを書き散らかしたあとにとりあえずコミットして、あとから論理的な歴史になるようにコミットを並び変えたり、コミットをまとめたりできることだ。
Mercurialでは、これらの歴史の改変はMQ拡張を使って実現できる。
たとえば、次のような歴史を作っていたとしよう。
$ hg glog --style=compact @ 4[tip] 722b0c3ef8f7 2011-06-07 22:34 +0900 yoppi | D | o 3 e912ff6fd1f1 2011-06-07 22:33 +0900 yoppi | B | o 2 eaca60210a86 2011-06-07 22:33 +0900 yoppi | C | o 1 f669da88832f 2011-06-07 22:33 +0900 yoppi | A | o 0 b3a79f426bdc 2011-06-07 22:32 +0900 yoppi initial commit
コミットがA->C->Bとなっており論理的な並びになっていない。
そこでこのコミットを論理的な歴史に修正しよう。
コミットをまずMQでパッチにする。
$ hg qimport -r tip:1 $ hg qseries 1.diff 2.diff 3.diff 4.diff
さて、パッチ化したあとは適用済みになっているので、これらのパッチをキューから解除する。
$ hg qpop --all popping 4.diff popping 3.diff popping 2.diff popping 1.diff patch queue now empty
キューから削除することで、各パッチを入れ替えることができる。
言い換えると、キューにenqueueする順序を変えることがコミットの順序を入れ替えることになる。
では、キューにパッチをpushする順番を変更するにはどうすればいいのか?
パッチ化したものは.hg/patches以下に保存されている。
$ ls .hg/patches 1.diff 2.diff 3.diff 4.diff series status
パッチの順序はこの'series'ファイルで管理されている。
したがって、ファイルの中身をエディタで書き換えることでコミットの順序を並び替えられる。
コミットの順序を正しくする(A->B->C)にはリビジョン2と3を入れ替える。
$ cat .hg/patches/series 1.diff 2.diff 3.diff 4.diff $ vim .hg/patches/series $ cat .hg/patches/series 1.diff 3.diff 2.diff 4.diff
このあとに、パッチをpush(適用)して、パッチをもとのコミットに戻す。
$ hg qpush --all $ hg qfinish --all $ hg glog --style=compact
普通はhistedit拡張を使う
MQ拡張で操作すると少し手順が多くなる(慣れると気にならなくなるが)ので、histedit拡張を使うともっと簡単にコミットを並び替えられる。
これはgit rebase -i のように対話的にコミットの歴史を変更できる。
histeditはMercurialにbundleされていないので、bitbucketからcloneして~/.hgrcに設定を書いておこう。
~/.hgrcに
[extensions] histedit = /path/to/cloned/histedit/hg_histedit.py
とライブラリのパスを記述しておく。
histedit拡張の使い方はいたって簡単で、コミットの歴史を変更したいチェンジセットのrevsetsを指定するだけでよい。
先ほど、MQ拡張でコミットを並び替えたものを、HistEdit拡張で並び替えてみよう。
$ hg histedit -r tip:1
するとtipからリビジョン1のコミットの情報が1行ごとに書き込まれた状態でエディタが起動する。
pick 52119b06ce60 A pick d1f359253a3a C pick 6170a8d1a63b B pick faf26eeb0bb2 D # Edit history between 52119b06ce60 and faf26eeb0bb2 # # Commands: # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but fold into previous commit # d, drop = remove commit from history #
Gitとほぼ同じであり、コミットの順序を並び替えたいのであれば、並び替えたいコミット行を入れ替える。
今回はコミット'C'とコミット'B'を入れ替えるので、それぞれの行を入れ替える。
また、左端のカラムはhisteditの操作を意味しており、コミットを並び替える以外の操作も可能だ。
- e edit: コミットメッセージを変更する
- f fold: 一つ前の親コミットに含める(エディタ上だと上のものが親にあたる)
- d delete: そのコミットを破棄する
編集し終わったら保存してエディタを終了してコミットを並び替えが完了する。
histeditが便利なので、普段はこっちを使うけどMQを使ってやってることをラップしているので、より複雑な操作をしたい場合はMQ使うことになるので、MQでの操作も知っておいたほうがいい。
fastthreadがthread.rbよりどれだけ高速なのか
最近MacBookにPassengerの環境を作ろうとして、gem経由でインストールするとfastthreadというgemがインストールされたので、気になったのでなんだろうとコードを読んでみた。
どうやら標準添付ライブラリ(thread.rb)で提供されているQueueやSizedQueueをそのまま、Ruby拡張したものだ。
つまり、Cで記述されている。
そこで、thread.rbとfasttreadを比較するbenchmarkを計測してみた。
よくある、Queueを使う簡単なConsumer/Producerパターンを検証コードとした。
# coding: utf-8 require 'rubygems' if RUBY_VERSION < "1.9" require 'benchmark' N = 1000000 def consumer_producer queue = Queue.new producer = Thread.new do N.times do |i| queue << i end end consumer = Thread.new do loop { break if !producer.alive? && queue.empty? queue.pop } end consumer.join end Benchmark.bmbm do |benchmark| require 'thread' benchmark.report("thread:") { consumer_producer } require 'fastthread' benchmark.report("fastthread:") { consumer_producer } end
検証環境はWindows(cygwin)とMac(Core2 Duo 2.2GHz)で、実行すると次のような結果になった。
cygwin$ <ruby thread.rb Rehearsal ----------------------------------------------- thread: 1.154000 0.031000 1.185000 ( 1.193000) fastthread: 1.373000 0.094000 1.467000 ( 1.473000) -------------------------------------- total: 2.652000sec user system total real thread: 1.342000 0.000000 1.342000 ( 1.380000) fastthread: 1.373000 0.015000 1.388000 ( 1.381000)
Macでの実行結果。
osx$ <ruby thread.rb Rehearsal ----------------------------------------------- thread: 2.450000 0.020000 2.470000 ( 2.463525) fastthread: 2.310000 0.050000 2.360000 ( 2.380355) -------------------------------------- total: 4.830000sec user system total real thread: 2.200000 0.010000 2.210000 ( 2.206227) fastthread: 2.180000 0.010000 2.190000 ( 2.196245)
fastthread使っても、threadのままでもあんまりかわらない。誤差の範囲ぽい。