<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2310485404319956884</id><updated>2012-02-17T04:15:25.021+09:00</updated><category term='YAML'/><category term='Go'/><category term='EventMachine'/><category term='RSpec'/><category term='Ubuntu'/><category term='rvm'/><category term='Bundler'/><category term='Git'/><category term='翻訳'/><category term='Ruby'/><category term='Mercurial'/><category term='Erlang'/><title type='text'>見えないチカラ</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-1162065071484090226</id><published>2011-12-24T16:03:00.000+09:00</published><updated>2011-12-31T00:47:31.820+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Bundler'/><title type='text'>【翻訳】速くなったのはいいとして、Bundler 1.1 の他の新機能は？</title><content type='html'>Pat Shaughnessyさんの "Besides being faster, what else is new in Bundler 1.1?" を翻訳しました。&lt;br&gt;元記事はこちら： &lt;a href="http://patshaughnessy.net/2011/11/5/besides-being-faster-what-else-is-new-in-bundler-1-1"&gt;http://patshaughnessy.net/2011/11/5/besides-being-faster-what-else-is-new-in-bundler-1-1&lt;/a&gt;&lt;br&gt;（翻訳の公開は本人より許諾済みです）&lt;br&gt;&lt;br&gt;翻訳の間違い等があればブログコメントやTwitter(&lt;a href="http://twitter.com/oshow"&gt;@oshow&lt;/a&gt;)などで遠慮無くご指摘ください。&lt;br&gt;&lt;br&gt;2011年12月発売の &lt;a href="http://www.amazon.co.jp/dp/4774149365"&gt;WEB+DB PRESS Vol.66&lt;/a&gt; には Bundler の解説記事が載っているそうです。&lt;br&gt;「Bundler1.1 ではなく Bundler 自体を知りたい」という人は、そちらを手にとってみてはいかがでしょうか。&lt;br&gt;&lt;br&gt;&lt;div style="background-color: #FFFFFF; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 750px; margin: 0 auto 0 auto; padding: 0px 25px 20px 25px; -moz-box-shadow: 1px 1px 3px #000; -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000; line-height: 1.4em; border: 2px solid black; line-height: 1.5em;"&gt;&lt;h1&gt;速くなったのはいいとして、&lt;br&gt;Bundler 1.1 の他の新機能は？&lt;/h1&gt;&lt;br&gt;&lt;div style="text-align: center"&gt; 2011年11月5日&lt;br&gt;by Pat Shaughnessy&lt;br&gt;&lt;/div&gt;&lt;br&gt;　3週間前に私は、Bundler 1.0 と比べ&lt;a class="pat_a" href="http://keijinsonyaban.blogspot.com/2011/12/bundler-11.html"&gt;なぜ Bundler 1.1 は速くなるのか&lt;/a&gt;を説明した。あれは明らかに最も重要な新機能だ。しかしそれ以外にも新しいコマンドとオプションが Bundler チームによって 1.1 に実装されており、gem のより良い管理や、開発用マシンとサーバにインストールした gem を選別するのを助けてくれる。Bundler 1.1 の新しいコマンドはアップグレード可能な gem を教えてくれたり、もう必要なくなった gem を削除して綺麗にしたりしてくれることだろう。&lt;br&gt;&lt;br&gt;今日は &lt;span class="pat_command"&gt;bundle outdated&lt;/span&gt;、&lt;span class="pat_command"&gt;bundle clean&lt;/span&gt;、&lt;span class="pat_command"&gt;bundle install --standalone&lt;/span&gt; のそれぞれを、使用例と共に駆け足で見ていくことにしたい。Bundler を 1.1 へアップグレードすれば速度が改善したことにはすぐ気づくだろうが、Bundler 1.1 の新しいコマンドがどのような物か学ぶための時間も取って欲しい。きっと、gem をうまく整理できるようになるはずだ。&lt;br&gt;&lt;br&gt;&lt;h2&gt;Bundle outdated&lt;/h2&gt;&lt;br&gt;　&lt;span class="pat_command"&gt;bundle outdated&lt;/span&gt; は Bundler 1.1 で導入された最も便利かつ重要な新コマンドであり、バンドルされた gem の中から古くなったものを判別してくれる――つまり、もっと新しいバージョンが入手可能かどうか調べてくれる。例えば、Bundler 1.0 から 1.1.rc へアップグレードして、私が去年から放置していたちょいと古めの Rails 3.0.7 アプリで &lt;span class="pat_command"&gt;bundle outdated&lt;/span&gt; を実行してみよう。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ gem install bundler --pre&lt;br /&gt;&lt;span class="pat_output"&gt;Successfully installed bundler-1.1.rc&lt;br /&gt;1 gem installed&lt;br /&gt;Installing ri documentation for bundler-1.1.rc...&lt;br /&gt;Installing RDoc documentation for bundler-1.1.rc...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ cd /path/to/an/old/rails/app&lt;br /&gt;&lt;br /&gt;$ bundle outdated&lt;br /&gt;&lt;span class="pat_output"&gt;Fetching gem metadata from http://rubygems.org/........&lt;br /&gt;&lt;br /&gt;Outdated gems included in the bundle:&lt;br /&gt;  * rake (0.9.2.2 &gt; 0.8.7)&lt;br /&gt;  * activesupport (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * builder (3.0.0 &gt; 2.1.2)&lt;br /&gt;  * i18n (0.6.0 &gt; 0.5.0)&lt;br /&gt;  * activemodel (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * erubis (2.7.0 &gt; 2.6.6)&lt;br /&gt;  * rack (1.3.5 &gt; 1.2.4)&lt;br /&gt;  * rack-mount (0.8.3 &gt; 0.6.14)&lt;br /&gt;  * rack-test (0.6.1 &gt; 0.5.7)&lt;br /&gt;  * actionpack (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * mail (2.3.0 &gt; 2.2.19)&lt;br /&gt;  * actionmailer (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * arel (2.2.1 &gt; 2.0.10)&lt;br /&gt;  * activerecord (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * activeresource (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * aws-ses (0.4.3 &gt; 0.3.2)&lt;br /&gt;  * ffi (1.0.10 &gt; 1.0.9)&lt;br /&gt;  * railties (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * rails (3.1.1 &gt; 3.0.7)&lt;br /&gt;  * mysql2 (0.3.7 &gt; 0.2.13)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;まず最初に "Fetching gem metadate…" というメッセージと共に Bundler は RubyGems.org の API へ接続し、最新の gem 依存情報を取得する。これについての詳しい話は&lt;a class="pat_a" href="http://keijinsonyaban.blogspot.com/2011/12/bundler-11.html"&gt;3週間前の私の記事&lt;/a&gt;を見て欲しい。次に Bundler は古くなった gem をリストアップする。言い換えれば、これら gem には新しいバージョンが存在し、今試しに &lt;span class="pat_command"&gt;bundle update&lt;/span&gt; を実行すればアップデートされるはずの物たちだ。この例では Rails 3.0.7 の gem が古くなっているのがわかる。今は Rails 3.1.1 が使えるようになっているからだ（訳注：執筆時点ではそれが最新）。また同時に昨年からの間に rake の新バージョンがリリースされた事や、mysql2 やその他 Rails 3.1.1 関連の gem が新しくなっているのがわかる。&lt;br&gt;&lt;br&gt;これの便利な所は、Bundler がダウンロードしてインストールする gem を表示するが、実際には実行しないことだ。これにより gem のリストを調査し、アップデートしたい gem を選択する自由が与えられる。この例では、私は新しい mysql2 が欲しいが、Rails 3.1.1 にはアップグレードしたくない。このような場合、&lt;span class="pat_command"&gt;bundle update mysql2&lt;/span&gt; を実行することができる。Bundler 1.0 では、おそらく単に &lt;span class="pat_command"&gt;bundle update&lt;/span&gt; を実行して全ての gem をアップデートし、後はうまくいくように願うしかなかっただろう。もしも何か問題――テストが失敗するとかバージョンの衝突とか――があったら、git を使って最初からやり直しする事になる。&lt;br&gt;&lt;br&gt;デフォルトでは &lt;span class="pat_command"&gt;bundle outdated&lt;/span&gt; は出力に開発版バージョンの gem を含めることはない。実リリース版バージョンのうち、新しいバージョンだけを列挙する。開発版バージョンも入手可能か調べたいなら、&lt;span class="pat_command"&gt;--pre&lt;/span&gt; オプションを以下のように追加すればよい。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle outdated --pre&lt;br /&gt;&lt;span class="pat_output"&gt;Fetching gem metadata from http://rubygems.org/........&lt;br /&gt;&lt;br /&gt;Outdated gems included in the bundle (including pre-releases):&lt;br /&gt;  * rake (0.9.3.beta.1 &gt; 0.8.7)&lt;br /&gt;  * activesupport (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * builder (3.0.0 &gt; 2.1.2)&lt;br /&gt;  * i18n (0.6.0 &gt; 0.5.0)&lt;br /&gt;  * activemodel (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * erubis (2.7.0 &gt; 2.6.6)&lt;br /&gt;  * rack (1.3.5 &gt; 1.2.4)&lt;br /&gt;  * rack-mount (0.8.3 &gt; 0.6.14)&lt;br /&gt;  * rack-test (0.6.1 &gt; 0.5.7)&lt;br /&gt;  * actionpack (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * mail (2.3.0 &gt; 2.2.19)&lt;br /&gt;  * actionmailer (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * arel (2.2.1 &gt; 2.0.10)&lt;br /&gt;  * activerecord (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * activeresource (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * aws-ses (0.4.3 &gt; 0.3.2)&lt;br /&gt;  * ffi (1.0.10 &gt; 1.0.9)&lt;br /&gt;  * thor (0.15.0.rc2 &gt; 0.14.6)&lt;br /&gt;  * railties (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * rails (3.1.1 &gt; 3.0.10)&lt;br /&gt;  * delayed_job (3.0.0.pre2 &gt; 2.1.4)&lt;br /&gt;  * haml (3.2.0.alpha.8 &gt; 3.1.3)&lt;br /&gt;  * mysql2 (0.3.7 &gt; 0.2.13)&lt;br /&gt;  * ruby-debug-base (0.10.5.rc1 &gt; 0.10.4)&lt;br /&gt;  * ruby-debug (0.10.5.rc1 &gt; 0.10.4)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;これで、新しい "alpha.8" バージョンの haml や "pre2" バージョンの delayed_job など、その他インストール可能な開発版バージョンを知ることができる。&lt;br&gt;&lt;br&gt;私見だが、&lt;span class="pat_command"&gt;--pre&lt;/span&gt; オプションは単に気のきいている機能ってだけじゃなく、各 gem にどんなリリース計画があり、自分のアプリケーションにどう影響があるかを注視するための素晴らしい方法に思える。Bundler 1.1 は、たくさんググったり RubyGems.org を探しまわらなきゃ見つからない、価値ある知識を与えてくれている。各 gem 作者が開発中のコードが自分のアプリに必要な物かどうかは別にしても、開発版の gem にアップグレードしてテストの失敗やバグを発見することで、haml や delayed_job やその他のプロジェクトへもっと簡単にコントリビュートする事ができるようになるわけだ。&lt;br&gt;&lt;br&gt;&lt;h2&gt;bundle install --path のおさらい&lt;/h2&gt;&lt;br&gt;　Bundler 1.1 の新機能の説明を続ける前に、Bundler 1.0 で導入された、あまり認知されていないオプションについておさらいしよう。&lt;span class="pat_command"&gt;bundle install&lt;/span&gt; を実行すると普通、Bundler は新しい gem を &lt;span class="pat_command"&gt;gem install&lt;/span&gt; の時と同じ場所へダウンロードしてインストールする。「システムの gem」というやつに混ざるわけだ。この場所は Ruby をインストールしたディレクトリの中にあり、RVM を使っている自分のラップトップではこうなる (Ruby 1.8.7)："/Users/pat/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/gems/1.8/gems"&lt;br&gt;&lt;br&gt;しかし、&lt;span class="pat_command"&gt;--path&lt;/span&gt; オプションを渡せば gem を好きなディレクトリにインストールするよう Bundler に指示できる。例えば以下のように。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle install --path vendor/bundle&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;上記のコマンドで、新しい gem は "vendor/bundle/ruby/1.8/gems" のようなディレクトリにインストールされるはずだ。ほとんどの人はこのオプションに気づいておらず、というのも普通はさほど役に立たないからだ。自分のコンピュータ上でやる通常の開発作業では、システムへ gem をインストールしても大抵問題はない。しかし &lt;span class="pat_command"&gt;--path&lt;/span&gt; オプションが役に立つようなケースというのも存在し、特にサーバ上などではそうだ。例えば以下のようなケースが考えられる。&lt;br&gt;&lt;ul&gt;  &lt;li&gt;システムの gem ディレクトリへの書き込み権限がない。&lt;br&gt;&lt;/li&gt;  &lt;li&gt;Bundler を Capistrano と一緒に使っていて、このオプションが自動的に有効化されている。&lt;br&gt;&lt;/li&gt;  &lt;li&gt;Bundler を使ったアプリケーションと、そうでないアプリケーションがある。&lt;br&gt;&lt;/li&gt;  &lt;li&gt;同一サーバ上の各アプリケーションにバンドルされている gem が、それぞれ独立して隔離されていることを絶対確実にしたい。&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;一旦バンドルのパスをこの方法で設定したなら、それは永続的な設定として .bundle/config ファイルへ保存される。これにより、このアプリケーション開発時に将来実行する bundle コマンド はいつも同じパスを使ってバンドルすることが保証される。この値を確認したり、他の全てのコンフィグ設定を見るには &lt;span class="pat_command"&gt;bundle config&lt;/span&gt; コマンドを使う。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle config&lt;br /&gt;&lt;span class="pat_output"&gt;&lt;span style="color: #00FF00"&gt;Settings are listed in order of priority. The top value will be used.&lt;br /&gt;&lt;br /&gt;disable_shared_gems&lt;/span&gt;&lt;br /&gt;  Set for your local app (/path/to/an/old/rails/app/.bundle/config): "1"&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #00FF00"&gt;path&lt;/span&gt;&lt;br /&gt;  Set for your local app (/path/to/an/old/rails/app/.bundle/config): "vendor/bundle"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;パスの設定を削除して gem のインストール先をシステムへ戻すなら、&lt;span class="pat_command"&gt;--system&lt;/span&gt; オプションを使おう。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle install --system&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;&lt;h2&gt;--path が設定されている場合に自動的に&lt;br&gt;古い gem を片付ける&lt;/h2&gt;&lt;br&gt;　Bundler 1.1 のその他のステキ機能は、古くて使っていない gem をマシンから自動的に取り除く機能だ…ただし、&lt;span class="pat_command"&gt;--path&lt;/span&gt; を使ってバンドルのパスを設定していた場合だけだが。もし &lt;span class="pat_command"&gt;bundle install --path&lt;/span&gt; をせずに普通にシステムの方へ gem をインストールしていたら、未使用の gem を一掃してはくれない。なぜなら、システム上の他のアプリケーションがまだそれを使っているかもしれないからだ。&lt;br&gt;&lt;br&gt;ではどういう風に動作するか見ていこう。さきほどに引き続き私の古い Rails 3.0.7 アプリを例にするが、あれを Rails 3.0.7 から Rails 3.0.10 へアップグレードすることに決めたとしよう。まず最初に Gemfile をこう編集する。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span style="color: white"&gt;gem 'rails', '3.0.10'&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;それから、&lt;span class="pat_command"&gt;bundle update&lt;/span&gt; を実行する。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle update rails&lt;br /&gt;&lt;span class="pat_output"&gt;Fetching gem metadata from http://rubygems.org/........&lt;br /&gt;Using rake (0.8.7)&lt;br /&gt;Using abstract (1.0.0)&lt;br /&gt;Installing activesupport (3.0.10)&lt;br /&gt;Using builder (2.1.2)&lt;br /&gt;Using i18n (0.5.0)&lt;br /&gt;Installing activemodel (3.0.10)&lt;br /&gt;&lt;br /&gt;...etc...&lt;br /&gt;&lt;br /&gt;Using rspec-rails (2.6.0)&lt;br /&gt;Using ruby-debug-base (0.10.4)&lt;br /&gt;Using ruby-debug (0.10.4)&lt;br /&gt;Removing actionmailer (3.0.7)&lt;br /&gt;Removing actionpack (3.0.7)&lt;br /&gt;Removing activemodel (3.0.7)&lt;br /&gt;Removing activerecord (3.0.7)&lt;br /&gt;Removing activeresource (3.0.7)&lt;br /&gt;Removing activesupport (3.0.7)&lt;br /&gt;Removing rails (3.0.7)&lt;br /&gt;Removing railties (3.0.7)&lt;br /&gt;&lt;span style="color: #00FF00"&gt;Your bundle is updated! Use `bundle show [gemname]` to see where a bundled gem is installed.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;ここで分かるのは、Bundler は Rails 3.0.10 のための新しい gem（activesupport、activerecord、他）をインストールすると同時に、もう使っていない古い gem を自動的に削除してくれたってことだ！　古い gem を一掃することはディスク領域の節約にもなるし、gem 置き場の整備維持に一役買ってくれる。&lt;br&gt;定期的に gem を新しいバージョンにしている内に散らかってしまうのを、防いでくれるんだ。&lt;br&gt;&lt;br&gt;&lt;h2&gt;Bundle clean&lt;/h2&gt;&lt;br&gt;　それ以外にも &lt;span class="pat_command"&gt;bundle clean&lt;/span&gt; を実行することで、使っていない gem を自分から削除する事も出来る。&lt;span class="pat_command"&gt;--path&lt;/span&gt; オプションをセットしてさえいれば &lt;span class="pat_command"&gt;bundle install&lt;/span&gt; や &lt;span class="pat_command"&gt;bundle update&lt;/span&gt; の時に自動的に綺麗にしてくれるので、普通はこのコマンドを実行する機会はないだろう。&lt;br&gt;&lt;br&gt;&lt;span class="pat_command"&gt;--path&lt;/span&gt; を設定しておらずシステムの gem 領域を使っている場合でも、bundle clean を使うことで、現在のバンドルでは未使用の gem を全てシステムから削除することは可能だ。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle clean&lt;br /&gt;&lt;span style="color: #FF0000"&gt;Can only use bundle clean when --path is set or --force is set&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;ただしそのままコマンドを打つだけでは、削除できない。上の結果のように、gem を意図せず削除することを回避してくれている。もし本当に実行したいなら &lt;span class="pat_command"&gt;--force&lt;/span&gt; オプションを使うわけだが…気をつけよう、あなたのマシンで以下を試してはいけない。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle clean --force&lt;br /&gt;&lt;span class="pat_output"&gt;Removing actionmailer (3.1.1)&lt;br /&gt;Removing actionpack (3.1.1)&lt;br /&gt;Removing activemodel (3.1.1)&lt;br /&gt;Removing activerecord (3.1.1)&lt;br /&gt;Removing activeresource (3.1.1)&lt;br /&gt;Removing activesupport (3.1.1)&lt;br /&gt;Removing arel (2.2.1)&lt;br /&gt;&lt;br /&gt;etc...&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;お分かりのように、私のラップトップにある Rails 3.1.1 アプリはたった今すべて壊れてしまった！　予想通り、Bundler は今対象としているアプリケーションのバンドルには含まれていない gem を全て削除してしまった。この場合、今いじっていたアプリケーションは Rails 3.0.10 をバンドルしていたのだから、それには無関係な gem（Rails 3.1.1）を削除したというわけだ。&lt;br&gt;&lt;br&gt;&lt;span class="pat_command"&gt;bundle clean --force&lt;/span&gt; は、しばらくの間一つの Ruby アプリケーションしか触らない予定だと分かっていて、gem を整理してディスクスペースを節約したい時は便利だと思われる。システムの gem を綺麗にしておくことは、Bundler を使っていないレガシー Rails アプリケーションが気づかない内にシステムに入れている gem にうっかり依存してしまわないようにするのにも役立つ。&lt;br&gt;&lt;br&gt;&lt;h2&gt;Bundle install --standalone&lt;/h2&gt;&lt;br&gt;　これも Bundler 1.1 での新しいオプションで、Bundler がインストールされていないサーバやその他マシンでも動作するようなバンドルを作成させてくれる。以下のように実行される。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle install --standalone&lt;br /&gt;&lt;span class="pat_output"&gt;Using rake (0.8.7) &lt;br /&gt;Using abstract (1.0.0) &lt;br /&gt;Using activesupport (3.0.9) &lt;br /&gt;Using builder (2.1.2) &lt;br /&gt;&lt;br /&gt;... etc...&lt;br /&gt;&lt;br /&gt;Using rspec (2.7.0) &lt;br /&gt;Using rspec-rails (2.7.0) &lt;br /&gt;Using ruby-debug-base (0.10.4) &lt;br /&gt;Using ruby-debug (0.10.4) &lt;br /&gt;&lt;span style="color: #00FF00"&gt;Your bundle is complete! It was installed into ./bundle&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;このオプションにより &lt;span class="pat_command"&gt;bundle install --path ./bundle&lt;/span&gt; を実行した時に作成されるのと同じ、バンドル内容を格納したローカルディレクトリがもたらされる。ただし、"bundle/bundler/setup.rb" という追加ファイルが作成される点が違う。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ find bundle | more&lt;br /&gt;&lt;span class="pat_output"&gt;bundle&lt;br /&gt;bundle/bundler&lt;br /&gt;bundle/bundler/setup.rb&lt;br /&gt;bundle/ruby&lt;br /&gt;bundle/ruby/1.8&lt;br /&gt;bundle/ruby/1.8/bin&lt;br /&gt;bundle/ruby/1.8/bin/cdiff&lt;br /&gt;&lt;br /&gt;... etc...&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;このファイルの中身を見てみると、バンドルに含まれる各 gem の lib ディレクトリをロードパスに追加するコードが入っているのが分かる。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span style="color: white"&gt;path = File.expand_path(&lt;span style="color: #00FF00"&gt;'..'&lt;/span&gt;, &lt;span style="color: #AAAAFF"&gt;__FILE__&lt;/span&gt;)&lt;br /&gt;$:.unshift File.expand_path(&lt;span style="color: #00FF00"&gt;"#{path}/../ruby/1.8/gems/rake-0.8.7/lib"&lt;/span&gt;)&lt;br /&gt;$:.unshift File.expand_path(&lt;span style="color: #00FF00"&gt;"#{path}/../ruby/1.8/gems/abstract-1.0.0/lib"&lt;/span&gt;)&lt;br /&gt;$:.unshift File.expand_path(&lt;span style="color: #00FF00"&gt;"#{path}/../ruby/1.8/gems/activesupport-3.0.10/lib"&lt;/span&gt;)&lt;br /&gt;$:.unshift File.expand_path(&lt;span style="color: #00FF00"&gt;"#{path}/../ruby/1.8/gems/builder-2.1.2/lib"&lt;/span&gt;)&lt;br /&gt;$:.unshift File.expand_path(&lt;span style="color: #00FF00"&gt;"#{path}/../ruby/1.8/gems/i18n-0.5.0/lib"&lt;/span&gt;)&lt;br /&gt;$:.unshift File.expand_path(&lt;span style="color: #00FF00"&gt;"#{path}/../ruby/1.8/gems/activemodel-3.0.10/lib"&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;これにより、Bundler がインストールされていないサーバマシンでもアプリケーションを実行させることが出来る。またこれを見ると、普段 Bundler が実際には何をしているかが感じ取れると思う。Bundler は Gemfile に基づいたロードパスを構築するのが仕事なのだ。&lt;br&gt;&lt;br&gt;&lt;h2&gt;待て待て、まだまだあるぞ&lt;/h2&gt;&lt;br&gt;　その他、マイナーチェンジやバグフィックスなど今回で紹介しきれないたくさんのものが Bundler 1.1 には含まれている。&lt;a class="pat_a" href="https://github.com/carlhuda/bundler/blob/master/CHANGELOG.md"&gt;ChangeLog&lt;/a&gt; を調べたり、&lt;a class="pat_a" href="http://gembundler.com/"&gt;http://gembundler.com&lt;/a&gt; にある新しいバージョンのドキュメントを見てみるといいだろう。&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;b&gt;関連記事：&lt;a href="http://keijinsonyaban.blogspot.com/2011/12/bundler-11.html"&gt;【翻訳】なぜ Bundler 1.1 は速くなるのか&lt;/a&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;style type="text/css"&gt;h1 {  font-size: 2.5em;}h2 {  font-size: 2em;  line-height: 1.1em;}h3 {  font-size: 1.7em;}h4 {  font-size: 1.5em;}.pat_command {  font-family: Monaco;  background-color: #FCC;  padding: 2px;}.pat_coderay {  background-color: black;  border: 1px solid black;}.pat_code {  background-color: #FCC;  padding: 2px;}.pat_code_pre {  background-color: black;  margin: 0px;  padding: 7px;  font-family: Monaco;  line-height: 1.5em;  border: 1px solid #BCBE9F;  color: #FFAAAA;  display: block;  overflow: auto;}.pat_output {  color: white;}a:link.pat_a {  color: #0007ff;}a:visited.pat_a {  color: #551a8b;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-1162065071484090226?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/1162065071484090226/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/12/bundler-11_24.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/1162065071484090226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/1162065071484090226'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/12/bundler-11_24.html' title='【翻訳】速くなったのはいいとして、Bundler 1.1 の他の新機能は？'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-6793968927849122066</id><published>2011-12-24T15:55:00.000+09:00</published><updated>2011-12-30T13:39:00.139+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Bundler'/><title type='text'>【翻訳】なぜ Bundler 1.1 は速くなるのか</title><content type='html'>Pat Shaughnessyさんの "Why Bundler 1.1 will be much faster" を翻訳しました。&lt;br&gt;元記事はこちら： &lt;a href="http://patshaughnessy.net/2011/10/14/why-bundler-1-1-will-be-much-faster"&gt;http://patshaughnessy.net/2011/10/14/why-bundler-1-1-will-be-much-faster&lt;/a&gt;&lt;br&gt;（翻訳の公開と画像の使用は本人より許諾済みです）&lt;br&gt;&lt;br&gt;翻訳の間違い等があればブログコメントやTwitter(&lt;a href="http://twitter.com/oshow"&gt;@oshow&lt;/a&gt;)などで遠慮無くご指摘ください。&lt;br&gt;&lt;br&gt;2011年12月発売の &lt;a href="http://www.amazon.co.jp/dp/4774149365"&gt;WEB+DB PRESS Vol.66&lt;/a&gt; には Bundler の解説記事が載っているそうです。&lt;br&gt;「Bundler1.1 ではなく Bundler 自体を知りたい」という人は、そちらを手にとってみてはいかがでしょうか。&lt;br&gt;&lt;br&gt;&lt;div style="background-color: #FFFFFF; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 750px; margin: 0 auto 0 auto; padding: 0px 25px 20px 25px; -moz-box-shadow: 1px 1px 3px #000; -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000; line-height: 1.4em; border: 2px solid black; line-height: 1.5em;"&gt;&lt;h1&gt;なぜ Bundler 1.1 は速くなるのか&lt;/h1&gt;&lt;br&gt;&lt;div style="text-align: center"&gt; 2011年10月15日&lt;br&gt;by Pat Shaughnessy&lt;br&gt;&lt;/div&gt;&lt;br&gt;　ここ一年ほどの間で Rails 3 アプリケーションを作っていた人ならば、&lt;span class="pat_command"&gt;bundle install&lt;/span&gt; や &lt;span class="pat_command"&gt;bundle update&lt;/span&gt; に長い長い時間がかかるのが珍しくないことに気づいていた事と思う。ターミナルが30秒かそれ以上の間ハングしたように見え、その後 "Fetching source index for http://rubygems.org/." なんて文字が表示される。さてここで、あなたに良いニュースがある。明敏なる Bundler ＆ RubyGems.org チームはこれに対する解決策を考えだし、来たる新バージョンの Bundler ではそれが物凄く高速化されたのだ！　今日は、如何にして Bundler 1.1 がこんなにも速くなったのかを見ていきたいと思う――つまり RubyGems ＆ Bundler チーム達の、「巧速化」ぶりを見ていこう。&lt;br&gt;&lt;br&gt;&lt;b&gt;2011年11月追記：&lt;/b&gt;11月15日の &lt;a class="pat_a" href="http://bostonrb.org/"&gt;Boston.rb&lt;/a&gt; の集まりで、この話題に関するプレゼンをしたら盛況だった。Bundler 1.1 についてもっと知りたい人は、その時の&lt;a class="pat_a" href="http://bostonrb.org/presentations/month/November-2011"&gt;動画&lt;/a&gt;を見たり&lt;a class="pat_a" href="http://www.slideshare.net/pat_shaughnessy/why-bundler-11-will-be-much-faster"&gt;スライドのダウンロード&lt;/a&gt;が可能だ。&lt;br&gt;&lt;br&gt;&lt;h2&gt;なぜ Budler 1.0 が遅かったのか&lt;/h2&gt;&lt;br&gt;　Bundler 1.1 を見ていく前に、なぜ Bundler 1.0 はあんなにも遅かったのだろうか？　"Fetching source index..." と表示される時は何が起こっていて、そしてなぜそれに長時間かかったのか？　Nick Quaranto はこれについて、&lt;a class="pat_a" href="http://robots.thoughtbot.com/post/2729333530/fetching-source-index-for-http-rubygems-org"&gt;2011年1月に良いまとめ記事&lt;/a&gt;を書いてくれた。詳細を知りたいなら、その記事を見てみるといいだろう。Nick の説明によると、Bundler を走らせる度に起きているのは、RubyGems.org から全 gem のリストをダウンロードしてそれを処理に通すという作業らしい。RubyGems.org には数万個の gem があるわけだから、とても、とても時間がかかる。Nick は同時に、私がこれから続く節以降で説明しようとしている解決法も示唆してくれた。&lt;br&gt;&lt;br&gt;なぜこんなことをしているのかと言えば、Bundler の仕事はどの gem をあなたのアプリケーションに含めるべきかを決定する事――「バンドル」する事――であり、その決定は、ある gem がどの gem に依存しているかに基づいているからだ。だから、全ての gem の依存関係情報をダウンロードする必要があるのだ。この全ての情報をダウンロードして処理するのには、30秒かそれ以上かかる（ネットワーク環境と CPU にも左右されるが）。&lt;br&gt;&lt;br&gt;&lt;h2&gt;Bundler 1.1 は本当に速くなったのか？&lt;/h2&gt;&lt;br&gt;　新バージョンの Bundler が速くなったのかを調べるのに一番いい方法は、ただインストールして試すだけだ。(訳注：執筆・翻訳時点では Bundler 1.1 が正式リリース前であるため、インストールするために --pre を付けている)&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ gem install bundler --pre&lt;br /&gt;&lt;span class="pat_output"&gt;Successfully installed bundler-1.1.rc&lt;br /&gt;1 gem installed&lt;br /&gt;Installing ri documentation for bundler-1.1.rc...&lt;br /&gt;Installing RDoc documentation for bundler-1.1.rc...&lt;/span&gt;&lt;br /&gt;$ cd /path/to/my/favorite/rails/app&lt;br /&gt;$ bundle update&lt;br /&gt;&lt;span class="pat_output"&gt;Fetching gem metadata from http://rubygems.org/.........&lt;br /&gt;Using rake (0.9.2)&lt;br /&gt;Using multi_json (1.0.3)&lt;br /&gt;Using activesupport (3.1.1)&lt;br /&gt;Using builder (3.0.0)&lt;br /&gt;&lt;br /&gt;etc...&lt;br /&gt;&lt;br /&gt;Using sass-rails (3.1.4)&lt;br /&gt;Using sqlite3 (1.3.4)&lt;br /&gt;Using uglifier (1.0.3)&lt;br /&gt;Your bundle is updated! Use `bundle show [gemname]` to see where a bundled gem is installed.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;もし上記を試したなら、2つの劇的な違いに気づくはずだ。&lt;br&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;ずううっと速くなっている。私の場合たった4秒だった。Bundler 1.0 では30秒以上かかった――目覚しい進歩だ！&lt;br&gt;&lt;/li&gt;&lt;li&gt;"Fetching source index..." の表示と長い沈黙の代わりに、"Fetching gem metadata from http://rubygems.org/........." の表示と共にドットが徐々に増えていき、なんだか spec を走らせているように思えた。&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;しかし、これは実際どう動いているのだろう？　そして "Fetching gem metadate…" は何を意味しているのか？　ドットが徐々に増えるのは何によってなのか？　より詳しく見てみようじゃないか。&lt;br&gt;&lt;br&gt;&lt;h2&gt;RubyGems.org の API&lt;/h2&gt;&lt;br&gt;　何が起こっているかのヒントを得るために、&lt;span class="pat_command"&gt;bundle update&lt;/span&gt; を &lt;span class="pat_command"&gt;--verbose&lt;/span&gt; オプションを付けてもう一度試してみよう。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle update --verbose&lt;br /&gt;&lt;span class="pat_output"&gt;Fetching gem metadata from http://rubygems.org/&lt;br /&gt;Query List: ["rails", "sqlite3", "json", "sass-rails", "coffee-rails", "uglifier", "jquery-rails"]&lt;br /&gt;Query Gemcutter Dependency Endpoint API: rails sqlite3 json sass-rails coffee-rails uglifier jquery-rails&lt;br /&gt;Fetching from: http://rubygems.org/api/v1/dependencies?gems=rails,sqlite3,json,sass-rails,coffee-rails,uglifier,jquery-rails&lt;br /&gt;HTTP Success&lt;br /&gt;Query List: ["bundler", "railties", "actionmailer", "activeresource", "activerecord", "actionpack", "activesupport", "rake", "actionwebservice", "ffi", "sprockets", "tilt", "sass", "coffee-script", "multi_json", "execjs", "therubyracer", "thor"]&lt;br /&gt;Query Gemcutter Dependency Endpoint API: bundler railties actionmailer activeresource activerecord actionpack activesupport rake actionwebservice ffi sprockets tilt sass coffee-script multi_json execjs therubyracer thor&lt;br /&gt;Fetching from: http://rubygems.org/api/v1/dependencies?gems=bundler,railties,actionmailer,activeresource,activerecord,actionpack,activesupport,rake,actionwebservice,ffi,sprockets,tilt,sass,coffee-script,multi_json,execjs,therubyracer,thor&lt;br /&gt;HTTP Success&lt;br /&gt;&lt;br /&gt;etc...&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;おっと、これで Bundler 1.1 がどう動いているかわかりそうだ。短いリストで指定された gem の依存関係情報を得るために、RubyGems.org が提供する HTTP の API を呼んでいる。source index 全体をダウンロードはしないわけだ。どれかの URL をブラウザに貼り付けてみれば、指定された gem の依存関係を表す、JSON に似た何やら複雑なフォーマットのデータが返されるのがわかるだろう。これは実は JSON ではなく、Ruby の &lt;a class="pat_a" href="http://ruby-doc.org/core-1.8.7/Marshal.html"&gt;Marshal ライブラリ&lt;/a&gt;が生成した文字列だ。&lt;br&gt;&lt;br&gt;RubyGems.org の API が動作する感覚をつかむために、&lt;a class="pat_a" href="http://httparty.rubyforge.org/"&gt;HTTParty&lt;/a&gt; と Marshal を使って、指定した gem の依存関係を表示する簡単なスクリプトを書いてみた。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span style="color: white"&gt;require &lt;span style="color: #00FF00"&gt;'rubygems'&lt;/span&gt;&lt;br /&gt;require &lt;span style="color: #00FF00"&gt;'httparty'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: #FF5C00"&gt;class&lt;/span&gt; &lt;span style="color: #A9A871"&gt;RubyGemsApi&lt;/span&gt;&lt;br /&gt;  include HTTParty&lt;br /&gt;  base_uri &lt;span style="color: #00FF00"&gt;'rubygems.org'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span style="color: #FF5C00"&gt;def&lt;/span&gt; &lt;span style="color: #6C9CBD"&gt;self&lt;/span&gt;.&lt;span style="color: #F7CD00"&gt;info_for&lt;/span&gt;(gems)&lt;br /&gt;    res = get(&lt;span style="color: #00FF00"&gt;'/api/v1/dependencies'&lt;/span&gt;, &lt;span style="color: #009C9B"&gt;:query&lt;/span&gt; =&gt; { &lt;span style="color: #009C9B"&gt;:gems&lt;/span&gt; =&gt; gems })&lt;br /&gt;    Marshal.load(res)&lt;br /&gt;  &lt;span style="color: #FF5C00"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span style="color: #FF5C00"&gt;def&lt;/span&gt; &lt;span style="color: #6C9CBD"&gt;self&lt;/span&gt;.&lt;span style="color: #F7CD00"&gt;display_info_for&lt;/span&gt;(gems)&lt;br /&gt;    info_for(gems).each &lt;span style="color: #FF5C00"&gt;do&lt;/span&gt; |info|&lt;br /&gt;      puts &lt;span style="color: #00FF00"&gt;"#{info[&lt;span style="color: #009C9B"&gt;:name&lt;/span&gt;]} version #{info[&lt;span style="color: #009C9B"&gt;:number&lt;/span&gt;]} dependencies: #{info[&lt;span style="color: #009C9B"&gt;:dependencies&lt;/span&gt;].inspect}"&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #FF5C00"&gt;end&lt;br /&gt;  end&lt;br /&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;RubyGemsApi.display_info_for(&lt;span style="color: #6C9CBD"&gt;ARGV&lt;/span&gt;[&lt;span style="color: #009C9B"&gt;0&lt;/span&gt;])&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;例として私の大好きな gem である "uglifier" に対してこれを走らせてみる。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ ruby parse_rubygems_api.rb uglifier&lt;br /&gt;&lt;span class="pat_output"&gt;uglifier version 1.0.3 dependencies: [["multi_json", "&gt;= 1.0.2"], ["execjs", "&gt;= 0.3.0"]]&lt;br /&gt;uglifier version 1.0.2 dependencies: [["multi_json", "&gt;= 1.0.2"], ["execjs", "&gt;= 0.3.0"]]&lt;br /&gt;uglifier version 1.0.1 dependencies: [["multi_json", "&gt;= 1.0.2"], ["execjs", "&gt;= 0.3.0"]]&lt;br /&gt;uglifier version 1.0.0 dependencies: [["multi_json", "&gt;= 1.0.2"], ["execjs", "&gt;= 0.3.0"]]&lt;br /&gt;uglifier version 0.5.4 dependencies: [["multi_json", "&gt;= 1.0.2"], ["execjs", "&gt;= 0.3.0"]]&lt;br /&gt;uglifier version 0.5.3 dependencies: [["multi_json", "&gt;= 1.0.2"], ["execjs", "&gt;= 0.3.0"]]&lt;br /&gt;uglifier version 0.5.2 dependencies: [["multi_json", "&gt;= 0"], ["execjs", "&gt;= 0.3.0"]]&lt;br /&gt;uglifier version 0.5.1 dependencies: [["json", "&gt;= 0"], ["execjs", "&gt;= 0"]]&lt;br /&gt;uglifier version 0.5.0 dependencies: [["json", "&gt;= 0"], ["execjs", "~&gt; 0.1.0"]]&lt;br /&gt;uglifier version 0.4.0 dependencies: [["therubyracer", "~&gt; 0.8.0"]]&lt;br /&gt;uglifier version 0.3.0 dependencies: [["therubyracer", "&gt;= 0.8.0"]]&lt;br /&gt;uglifier version 0.2.0 dependencies: []&lt;br /&gt;uglifier version 0.1.1 dependencies: []&lt;br /&gt;uglifier version 0.1.0 dependencies: []&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;レスポンスには最新版だけじゃなく、gem の各バージョン毎の依存関係が含まれているのに気づいて欲しい。これが必要なのは、Bundler の依存解決アルゴリズムが gem の古いバージョンを使う可能性があるからだ（バンドルしている他の gem の内容により、動作が違ってくる）。&lt;br&gt;&lt;br&gt;gem 名をコンマで区切ったリストを指定することもでき、例えば上の方で --verbose を指定した時のリストを使えばこうだ。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ ruby parse_rubygems_api.rb rails,sqlite3,json,sass-rails,coffee-rails,uglifier,jquery-rails&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;この HTTP API の呼び出しは非常に速い――1秒未満だ――うえに、Bundler が欲する情報を全て提供し、それ以上のことは何もしない。&lt;br&gt;&lt;br&gt;&lt;h2&gt;依存 gem をダウンロードする&lt;br&gt;Bundler 1.1 のアルゴリズムを視覚化する&lt;/h2&gt;&lt;br&gt;　さっきと同じで、簡単な Gemfile を使ってみよう（この Gemfile は3週間前の &lt;a class="pat_a" href="http://patshaughnessy.net/2011/9/24/how-does-bundler-bundle"&gt;How does Bundler bundle&lt;/a&gt; で使ったものだ）。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span style="color: white"&gt;source &lt;span style="color: #00FF00"&gt;'http://rubygems.org'&lt;/span&gt;&lt;br /&gt;gem &lt;span style="color: #00FF00"&gt;'uglifier’&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;そして、この Gemfile の内容を表現するシンプルな図を描こう。つまり、一つの gem だけだ。&lt;br&gt;&lt;br&gt;&lt;img src="http://4.bp.blogspot.com/-C_DHemaG3CY/TvVy3TUrE4I/AAAAAAAAAaM/otO4uPQhwpY/s451/one.png" alt="" width="451" height="100" /&gt;&lt;br&gt;&lt;br&gt;次に、この Gemfile のあるディレクトリで &lt;span class="pat_command"&gt;bundle update --verbose&lt;/span&gt; を実行し、出力を見てみる。ただし今度は、出力テキストの合間に図を挟み込み、Bundler の依存 gem 取得アルゴリズムが実際に何をしているかを示そう。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;$ bundle update --verbose&lt;br /&gt;&lt;span class="pat_output"&gt;Fetching gem metadata from http://rubygems.org/&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;&lt;img src="http://2.bp.blogspot.com/-UsyOt8jMUZ4/TvVy3bR9u-I/AAAAAAAAAaY/8F6zrjQkAgA/s451/two.png" alt="" width="451" height="157" /&gt;&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span class="pat_output"&gt;Query List: ["uglifier"]&lt;br /&gt;Query Gemcutter Dependency Endpoint API: uglifier&lt;br /&gt;Fetching from: http://rubygems.org/api/v1/dependencies?gems=uglifier&lt;br /&gt;HTTP Success&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;ここで最初に起こっているのは、Gemfile の中に唯一入っている gem である "uglifier" の依存関係を決定するための HTTP リクエストだ。この HTTP リクエストの結果は、上にある parse_rubygems_api.rb スクリプトの出力でわかる。uglifier のそれぞれ違うバージョンの中に出てくる、4つの gem だ。&lt;br&gt;&lt;br&gt;&lt;img src="http://1.bp.blogspot.com/-5pi7aNIZJWI/TvVy3hf71jI/AAAAAAAAAak/kKVDwNCuYsY/s584/three.png" alt="" width="584" height="249" /&gt;&lt;br&gt;&lt;br&gt;最新の uglifier は json、execjs、multi_json に依存していて、ある古いバージョンでは "therubyracer" gem に依存している。&lt;br&gt;&lt;br&gt;その次に Bundler がする事は、2回目の HTTP リクエストを RubyGems.org へ送り、これら4つの gem の依存関係を要求することだ。&lt;br&gt;&lt;br&gt;&lt;img src="http://3.bp.blogspot.com/-pIGB_APF_S8/TvVy38E0OzI/AAAAAAAAAaw/PZFVnb7S1S0/s570/four.png" alt="" width="570" height="308" /&gt;&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span class="pat_output"&gt;Query List: ["multi_json", "execjs", "json", "therubyracer"]&lt;br /&gt;Query Gemcutter Dependency Endpoint API: multi_json execjs json therubyracer&lt;br /&gt;Fetching from: http://rubygems.org/api/v1/dependencies?gems=multi_json,execjs,json,therubyracer&lt;br /&gt;HTTP Success&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;興味があるなら、parse_rubygems_api.rb を実行してこのリクエストの結果を見ることも出来る。以下は RubyGems.org が返す結果の図だ。&lt;br&gt;&lt;br&gt;&lt;img src="http://4.bp.blogspot.com/-G6o5ibE-sE4/TvVy4G-s1GI/AAAAAAAAAa8/1K1FKE_5OAk/s584/five.png" alt="" width="584" height="353" /&gt;&lt;br&gt;&lt;br&gt;今度は "execjs" gem がいくつかのバージョンの "multi_json" へ依存している事と、"therubyracer" が "libv8" に依存していることがわかる。そして Bundler は RubyGems.org への3回目の HTTP リクエスト送信へと続き、libv8 の依存関係を得る。このリクエストに multi_json は含まれない。なぜなら、既にその情報は持っているからだ。&lt;br&gt;&lt;br&gt;&lt;img src="http://2.bp.blogspot.com/-kgGnDXtYepI/TvVy-LpulzI/AAAAAAAAAbI/Y2oDQxiyGsg/s698/six.png" alt="" width="698" height="415" /&gt;&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span class="pat_output"&gt;Query List: ["libv8"]&lt;br /&gt;Query Gemcutter Dependency Endpoint API: libv8&lt;br /&gt;Fetching from: http://rubygems.org/api/v1/dependencies?gems=libv8&lt;br /&gt;HTTP Success&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;今度は RubyGems.org が空のセットを返す。libv8 は一つも依存する gem を持たないということだ。&lt;br&gt;&lt;br&gt;&lt;img src="http://3.bp.blogspot.com/-WFtxbJ37YRQ/TvVy-We6qdI/AAAAAAAAAbU/5v6i9FYDn5k/s699/seven.png" alt="" width="699" height="465" /&gt;&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span class="pat_output"&gt;Query List: []&lt;br /&gt;Unmet Dependencies:&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;これで Bundler は必要な全依存情報を手に入れたので依存解決アルゴリズムの実行へと進み、そして最後に、たった今新しくなったバンドルに含まれている gem を列挙する。&lt;br&gt;&lt;br&gt;&lt;div class="pat_coderay"&gt;&lt;div class="pat_code"&gt;&lt;pre class="pat_code_pre"&gt;&lt;br /&gt;&lt;span class="pat_output"&gt;Using multi_json (1.0.3) from /Users/pat/.rvm/gems/ruby-1.8.7-p352/specifications/multi_json-1.0.3.gemspec&lt;br /&gt;Using execjs (1.2.9) from /Users/pat/.rvm/gems/ruby-1.8.7-p352/specifications/execjs-1.2.9.gemspec&lt;br /&gt;Using uglifier (1.0.3) from /Users/pat/.rvm/gems/ruby-1.8.7-p352/specifications/uglifier-1.0.3.gemspec&lt;br /&gt;Using bundler (1.1.rc) from /Users/pat/.rvm/gems/ruby-1.8.7-p352/specifications/bundler-1.1.rc.gemspec&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;b&gt;関連記事：&lt;a href="http://keijinsonyaban.blogspot.com/2011/12/bundler-11_24.html"&gt;【翻訳】速くなったのはいいとして、Bundler 1.1 の他の新機能は？&lt;/a&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;style type="text/css"&gt;h1 {  font-size: 2.5em;}h2 {  font-size: 2em;  line-height: 1.1em;}h3 {  font-size: 1.7em;}h4 {  font-size: 1.5em;}.pat_command {  font-family: Monaco;  background-color: #FCC;  padding: 2px;}.pat_coderay {  background-color: black;  border: 1px solid black;}.pat_code {  background-color: #FCC;  padding: 2px;}.pat_code_pre {  background-color: black;  margin: 0px;  padding: 7px;  font-family: Monaco;  line-height: 1.5em;  border: 1px solid #BCBE9F;  color: #FFAAAA;  display: block;  overflow: auto;}.pat_output {  color: white;}a:link.pat_a {  color: #0007ff;}a:visited.pat_a {  color: #551a8b;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-6793968927849122066?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/6793968927849122066/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/12/bundler-11.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6793968927849122066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6793968927849122066'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/12/bundler-11.html' title='【翻訳】なぜ Bundler 1.1 は速くなるのか'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-C_DHemaG3CY/TvVy3TUrE4I/AAAAAAAAAaM/otO4uPQhwpY/s72-c/one.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-3874428817606243758</id><published>2011-05-18T19:56:00.008+09:00</published><updated>2011-05-22T05:31:28.963+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><title type='text'>【翻訳】Gitをボトムアップから理解する</title><content type='html'>John Wiegleyさんの "Git from the bottom up" を翻訳しました。&lt;br /&gt;元PDFはこちらからダウンロードできます： &lt;a href="http://newartisans.com/2008/04/git-from-the-bottom-up/"&gt;http://newartisans.com/2008/04/git-from-the-bottom-up/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;元記事のライセンスがクリエイティブコモンズのBY-SAであったため、この翻訳もBY-SAとなります。&lt;br /&gt;ライセンスを守って自由にご利用ください。（詳しくは記事内の最初にも書いてあります）&lt;br /&gt;&lt;br /&gt;翻訳ミスの指摘や改善の提案等があればブログコメントやTwitter(&lt;a href="http://twitter.com/oshow"&gt;@oshow&lt;/a&gt;)などで遠慮なくどうぞ。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #FFFFFF; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 750px; margin: 0 auto 0 auto; padding: 0px 25px 20px 25px; -moz-box-shadow: 1px 1px 3px #000; -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000; line-height: 1.4em; border: 2px solid black; line-height: 1.5em;"&gt;&lt;h1 class="jw_h"&gt;Git をボトムアップから理解する&lt;/h1&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;Wed, 2 Dec 2009&lt;br /&gt;by John Wiegley&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;　私が Git を理解しようと調査した時、高級なコマンドの視点から眺めるよりボトムアップ式に理解することが役立った。そしてボトムアップ視点で見る Git がこんなにも美しくシンプルであるなら、私が調べたことを他の人も興味を持って読んでくれるのではないか、そうして私が経験した苦労を避けられるのではと考えた。&lt;br /&gt;&lt;br /&gt;この文書にある例には、Git 1.5.4.5 を使用している。&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h"&gt;目次&lt;/h2&gt;&lt;ol style="width: 350px"&gt;&lt;a href="#ct1"&gt;&lt;li&gt;ライセンス&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct2"&gt;&lt;li&gt;導入&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct3"&gt;&lt;li&gt;リポジトリ：ディレクトリ内容の追跡&lt;/li&gt;&lt;/a&gt; &lt;ul&gt;&lt;a href="#ct3_1"&gt;&lt;li&gt;blob の紹介&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct3_2"&gt;&lt;li&gt;blob は tree が保管する&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct3_3"&gt;&lt;li&gt;tree はどのように作られるか&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct3_4"&gt;&lt;li&gt;コミットの美&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct3_5"&gt;&lt;li&gt;コミットを別名で言うと…&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct3_6"&gt;&lt;li&gt;ブランチングと rebase の力&lt;/li&gt;&lt;/a&gt; &lt;/ul&gt;&lt;a href="#ct4"&gt;&lt;li&gt;インデックス：仲介者を知ろう&lt;/li&gt;&lt;/a&gt; &lt;ul&gt;&lt;a href="#ct4_1"&gt;&lt;li&gt;一歩先のインデックス&lt;/li&gt;&lt;/a&gt; &lt;/ul&gt;&lt;a href="#ct5"&gt;&lt;li&gt;リセットすること、またはリセットしないこと&lt;/li&gt;&lt;/a&gt; &lt;ul&gt;&lt;a href="#ct5_1"&gt;&lt;li&gt;mixed reset の実行&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct5_2"&gt;&lt;li&gt;soft reset の実行&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct5_3"&gt;&lt;li&gt;hard reset の実行&lt;/li&gt;&lt;/a&gt; &lt;/ul&gt;&lt;a href="#ct6"&gt;&lt;li&gt;鎖をつなぐ最後の輪：stash と reflog&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct7"&gt;&lt;li&gt;まとめ&lt;/li&gt;&lt;/a&gt; &lt;a href="#ct8"&gt;&lt;li&gt;参考文献&lt;/li&gt;&lt;/a&gt; &lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct1"&gt;1. ライセンス&lt;/h2&gt;&lt;br /&gt;　この文書は米国クリエイティブ・コモンズライセンス 3.0 の BY-SA 条件下で提供される。以下の URL を参照のこと：&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;a href="http://creativecommons.org/licenses/by-sa/3.0/us/"&gt;http://creativecommons.org/licenses/by-sa/3.0/us/&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;要するに、著者情報が維持される限り、あなたはこの文書のコンテンツを個人目的、商業目的、その他のどんな目的にも利用できる。同様に、オリジナルの文書と同じ条件で頒布される限り、この文書の改変、派生作品の制作、翻訳は自由に行える。&lt;br /&gt;（訳注：ということで、この翻訳も CC 3.0 の BY-SA で提供されます。すなわち、あなたはこの翻訳を上の条件で扱って良いということです。翻訳者名は O-Show でお願いします）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct2"&gt;2. 導入&lt;/h2&gt;&lt;br /&gt;　Git の世界へようこそ。本文書がこの強力なコンテンツ・トラッキングシステムをより理解するための助けになること、そしてその根底にあるちょっとしたシンプルさ――外側から見たら目眩がしそうなオプション群だけれど――を明らかにする助けになるのを願っている。&lt;br /&gt;&lt;br /&gt;本題に入る前にまず、本稿中で繰り返し現れる、触れておくべき用語がいくつかある：&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;repository&lt;/strong&gt;&lt;br /&gt;　&lt;strong&gt;リポジトリ&lt;/strong&gt; (repository) はコミットの集合であり、各コミットはプロジェクトにおいて過去に存在したワーキングツリーのアーカイブだ。コミットは過去あなたのマシン上にあったのか、それとも他の誰かのマシン上にあったかは関係ない。またリポジトリは、現在のワーキングツリーがどのブランチまたはコミットから由来しているのかを特定する、HEAD (以下で触れる) というものを定義する。さらに、ブランチやタグという、コミットを名前で把握するためのものも含んでいる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;the index&lt;/strong&gt;&lt;br /&gt;　あなたが使用してきたであろう他の似たツールと違い、Git はワーキングツリーからリポジトリへ変更を直接コミットしない。代わりに、変更はまず&lt;strong&gt;インデックス&lt;/strong&gt; (index) と呼ばれる場所へ登録される。コミットする (あなたが承認した変更をいっぺんに全て記録する) 前に、一つずつ、あなたの変更を「確認する」方法だと考えるといい。インデックスと呼ぶ代わりに「ステージングエリア」と呼ぶほうが理解の助けになるかもしれない。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;working tree&lt;/strong&gt;&lt;br /&gt;　&lt;strong&gt;ワーキングツリー&lt;/strong&gt; (working tree) は、それに関連するリポジトリを持った、ファイルシステム上のあるディレクトリのことだ (普通は中に .git という名前のサブディレクトリが存在することでわかる)。ワーキングツリーには全てのファイルとサブディレクトリが含まれている。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;commit&lt;/strong&gt;&lt;br /&gt;　&lt;strong&gt;コミット&lt;/strong&gt;はある時点でのワーキングツリーのスナップショットだ。そのコミットをする時点の HEAD (以下で見る) の状態が、そのコミットの親になる。これこそが「リビジョン履歴」という概念を作成することにあたる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;branch&lt;/strong&gt;&lt;br /&gt;　&lt;strong&gt;ブランチ&lt;/strong&gt;はコミットのただの別名であり (かつそれ以上に、ある時点のコミット群について述べるための物でもあるだろう)、またリファレンスとも呼ばれる。リポジトリの歴史を定義するコミットの系統図であり、従って「開発における枝分かれ」を表現する典型的概念である。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;tag&lt;/strong&gt;&lt;br /&gt;　&lt;strong&gt;タグ&lt;/strong&gt;もまたブランチと同様にコミットの別名であるが、常に同じコミットを指すということと、自身を説明するテキストを持ちうるという点が異なる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;master&lt;/strong&gt;&lt;br /&gt;　ほとんどのリポジトリにおける開発のメインラインは &lt;strong&gt;「master」&lt;/strong&gt; と呼ばれるブランチ上で行われる。通常これがデフォルトだが、決して特殊なブランチではない。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;HEAD&lt;/strong&gt;&lt;br /&gt;　&lt;strong&gt;HEAD&lt;/strong&gt; は現在チェックアウトされているものを定義するために、リポジトリで使われる。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;もしブランチをチェックアウトしているなら、HEAD はそのブランチ (名) を指し、次のコミット操作の後ではその名前のブランチがアップデートされることを表す。&lt;/li&gt;&lt;li&gt;もし特定のコミットをチェックアウトしているなら、HEAD はただそのコミットだけを指す。これは detached HEAD と呼ばれ、例えば、タグ名でチェックアウトするとそういうことが起こる。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Git における一般的な流れはこうだ。リポジトリを作成した後、あなたの作業はワーキングツリーで行われる。仕事が1段落したら――バグ修正が完了したり、労働時間の終わりだったり、全てのコンパイルが通った時などに――逐次変更をインデックスに追加する。コミットしたい全てのものがインデックスに追加されたら、その内容をリポジトリに記録する。通常のプロジェクトのライフサイクルを示す簡単な図は以下のとおりだ：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://2.bp.blogspot.com/-JV1wRmXO4Jw/TdOfCqbqRbI/AAAAAAAAASw/YTQRDGhbzWE/s581/4_ja.png" alt="repository-workingtree-index" width="581" height="309" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;この基本的な構図を頭に置きながら (*1)、以下のセクションでは Git の操作においてこれらの各実体の違いが如何に重要かを説明したいと思う。&lt;br /&gt;&lt;br /&gt;(*1) 本当は、チェックアウトはリポジトリからインデックスへのコピーを引き起こし、それからワーキングツリーへ書きだされる。しかしチェックアウト操作におけるこのインデックスの使われ方をまだ見ていないので、それは図の中であまり分かりやすい表現にならないと思った (ので省いた)。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct3"&gt;3. リポジトリ：ディレクトリ内容の追跡&lt;/h2&gt;&lt;br /&gt;　以上のように、Git がすることはかなり原始的だ。「ディレクトリのスナップショットを保全する」。この基本的なタスクを見ていくことで、多くの内部的デザインが理解可能だ。&lt;br /&gt;&lt;br /&gt;Git リポジトリのデザインは様々な点で Unix ファイルシステムの構造を反映している。すなわち、ファイルシステムはルートディレクトリから始まり、ルート以下にはさらに他のディレクトリがあり、それらディレクトリのほとんどが葉となるノード、つまりファイル (これがデータを含んでいる) を持つ。これらのファイルの内容に関するメタデータとしては、まずディレクトリ名があり、さらに i-node というファイルの内容への参照 (ファイルサイズ、ファイルタイプ、権限) に保管される。各 i-node は関連するファイルの内容を識別する一意の数字を持つ。そして複数のディレクトリエントリがある特定の i-node を指すこともある (例：ハードリンク) 。ファイルシステム上に保存された内容を「所有している」のは i-node だと言えるだろう。&lt;br /&gt;&lt;br /&gt;内部的に Git の構造は著しく Unix ファイルシステムに似ているものの、１・２個の主要な違いがある。第一に、ファイルの内容を blob というもので表現する。blob はまた、ディレクトリによく似た tree と呼ばれるものにとっての葉にあたるノードにもなる。ちょうど i-node が、システムが振った数字で一意に特定されるように、blob は自身のサイズと内容から計算される SHA-1 ハッシュによって名付けられる。これは i-node と同じくただの任意の数字だが、2つの追加的な特性がある。一つは、blob の内容が変更されていないことを証明する。もう一つは、同じ内容ならば常に同じ blob として表現される。それがどこに現れたとしてもだ。コミットをまたいでも、リポジトリをまたいでも――インターネット越しだとしても。もし複数の tree が同じ blob を参照していたら、これはまさにハードリンクに似ている。その blob は、少なくとも一つのリンクが残っている限り、あなたのリポジトリから削除されたりはしない。&lt;br /&gt;&lt;br /&gt;Git の blob と、ファイルシステムにおけるファイルの違いは、blob は自身の内容についてのメタデータを一切保管しないことだ。そのような情報は全て、その blob を保持する tree の方が持つ。ある tree は、その blob の内容で "foo" という名前のファイルが 2004 年の 8 月に作成されたということを知っており、また他の tree は同じ内容が "bar" という名前で 5 年前に作成されたと知っているかもしれない。普通のファイルシステムでは、同じ内容だがそのような異なるメタデータを持つ２つのファイルは、常に２つの独立したファイルとして表現されるだろう。この違いはなぜだろう？　主として、ファイルシステムは変更されるファイルをサポートするようデザインされているが、Git はそうではないからだ。Git リポジトリではデータが不変 (immutable) であるという事実が、これら全ての動作と、そのような異なるデザイン要請を決めている。そして結局のところ、このデザインが遥かにコンパクトな収容力をもたらす。一意の内容を持つ全てのオブジェクトは、それがどこに位置していたとしても共有され得るからだ。&lt;br /&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct3_1"&gt;blobの紹介&lt;/h3&gt;　基本的な構想は見えたので、いくつかの実例に入っていく。まずサンプルの Git リポジトリを作成する事から始め、そのリポジトリで Git がどのように動作するかをボトムアップからお見せするつもりだ。　以下、必要ならば適宜読み替えて欲しい。&lt;br /&gt;&lt;pre class="waku_a"&gt;$ mkdir sample; cd sample&lt;br /&gt;$ echo 'Hello, world!' &amp;gt; greeting &lt;br /&gt;&lt;/pre&gt;ここではファイルシステム上に "sample" という名前の新しいディレクトリを作成し、そこに平凡な内容のファイルを入れた。まだリポジトリ作成すらしていないが、Git が何をしていくかを理解するために、もう Git コマンドを使い始めることもできる。まず、Git がどんなハッシュ ID を使って greeting というテキストを格納するのかを知りたいとしよう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git hash-object greeting&lt;br /&gt;&lt;span class="jw_output"&gt;af5626b4a114abcb82d63db7c8082c3c4756e51b&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;あなたのシステム上でこのコマンドを走らせたら、あなたの方も同じハッシュ ID が表示されるはずだ。私たちは２つの異なるリポジトリ (もしかしたら別世界に存在するかも) を作成しているのだが、２つのリポジトリ中の greeting blob は同じハッシュ ID を持つことになる。私はあなたのリポジトリから私の方へコミットを引っ張って来ることができるし、Git は私たちが同じ内容を追跡しているのだと気づくだろう――つまり1つのコピーだけが格納される！　とてもクールだ。&lt;br /&gt;&lt;br /&gt;次のステップは、新しいリポジトリを初期化してそれにファイルをコミットすることだ。今はオールインワンのやり方でこれを実行するが、水面下で何が起っているか理解するため、またここへ戻ってくるつもりだ。&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git init&lt;br /&gt;$ git add greeting&lt;br /&gt;$ git commit -m "Added my greeting"&lt;br /&gt;&lt;/pre&gt;ここでのポイントは、blob はまさに私たちが期待するように、上記で決定されたハッシュ ID を持ってシステム上に保存されるということだ。また Git が必要とするハッシュ ID の桁数は、リポジトリ中でそれを一意に特定できる長さだけとなる。通常はたった 6 桁か 7 桁で充分だ：&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git cat-file -t af5626b&lt;br /&gt;&lt;span class="jw_output"&gt;blob&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="waku_a"&gt;$ git cat-file blob af5626b&lt;br /&gt;&lt;span class="jw_output"&gt;Hello, world!&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;そらきた！　私はあの blob がどのコミットに保持されているのかも、何の tree の中にあるかも調べていない。でも、仮定されていた唯一の情報 (ハッシュ ID) に基づいて、存在することが確認できた。リポジトリがどれだけ長く存在しても、ファイルがその中のどこに格納されていても、この blob は常に同じ識別子を持つだろう。これらの内容は、今や確認可能な形で保存されている。そう永遠にだ。&lt;br /&gt;&lt;br /&gt;このように、blob は Git での基本的なデータ単位を表す。言ってみれば、Git の全てのシステムは blob を管理するためにあるのだ。&lt;br /&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct3_2"&gt;blob は tree が保管する&lt;/h3&gt;　あなたのファイルの内容は blob に格納されるが、blob には何か特徴があるわけではない。blob は名前を持たず、構造も持たない――まさに「blob (カタマリ)」というわけだ。&lt;br /&gt;&lt;br /&gt;Git はファイルの構造と名前を表現するために、blob を tree へ葉ノードとしてくっつける。今のところちょっと見ただけでは、どの tree に目的の blob があるのかを見つけることはできない。多くの、とても多くの所有者 (tree) がいるかもしれないからだ。しかし、さっきの blob はたった今作ったコミットが保持する tree のどこかに必ず存在するはずだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git ls-tree HEAD&lt;br /&gt;&lt;span class="jw_output"&gt;100644 blob af5626b4a114abcb82d63db7c8082c3c4756e51b greeting&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;そらきた！　この最初のコミットは greeting ファイルをリポジトリへ追加したものだ。このコミットは、Git の tree を一つ含み、それはたった1つの葉を持つ。つまり greeting の内容を表す blob だ。&lt;br /&gt;&lt;br /&gt;&lt;span class="jw_in"&gt;ls-tree&lt;/span&gt; に HEAD を渡すことで、件の blob を含んだ tree があるということはわかったが、その HEAD コミットによって参照される実際の tree オブジェクトはまだ見ることができていない。以下のように、違う部分にライトを当てるコマンドならば tree オブジェクトを見つけられる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git rev-parse HEAD&lt;br /&gt;&lt;span class="jw_output"&gt;588483b99a46342501d99e3f10630cfc1219ea32&lt;/span&gt; &lt;span class="jw_cm"&gt;# これはあなたのシステム上では別物になる&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="waku_a"&gt;$ git cat-file -t HEAD&lt;br /&gt;&lt;span class="jw_output"&gt;commit&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="waku_a"&gt;$ git cat-file commit HEAD&lt;br /&gt;&lt;span class="jw_output"&gt;tree 0563f77d884e4f79ce95117e2d686d7d6e282887&lt;br /&gt;author John Wiegley &amp;lt;johnw@newartisans.com&amp;gt; 1209512110 -0400&lt;br /&gt;committer John Wiegley &amp;lt;johnw@newartisans.com&amp;gt; 1209512110 -0400&lt;br /&gt;&lt;br /&gt;Added my greeting &lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;最初のコマンドは HEAD というエイリアスをそれが参照するコミットへとデコードし、二番目のコマンドはオブジェクトの種類を確認する。三番目のコマンドはそのコミットが保持する tree のハッシュ ID を表示しているが、同様にコミットに格納された他の情報も見せている。コミットのハッシュ ID は私のリポジトリ特有のものだ――なぜならばそれは、私の名前と、コミットを作成した時の日付を含むからだ――しかし、tree のハッシュ ID はあなたの手元と私のものは共通であるはずだ。同じ内容の blob を同じ名前で保持しているのだから。&lt;br /&gt;&lt;br /&gt;これが本当に同じ tree オブジェクトであるということを確かめてみよう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git ls-tree 0563f77&lt;br /&gt;&lt;span class="jw_output"&gt;100644 blob af5626b4a114abcb82d63db7c8082c3c4756e51b greeting&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;以上、ご覧の通りだ。私のリポジトリはただ一つのコミットを含み、そのコミットは 1 個の blob を持つ 1 個の tree を参照している――blob は私が記録したい内容を含んでいる。これが本当にそうであるか確かめられるコマンドがもう一つある：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ find .git/objects -type f | sort&lt;br /&gt;&lt;span class="jw_output"&gt;.git/objects/05/63f77d884e4f79ce95117e2d686d7d6e282887&lt;br /&gt;.git/objects/58/8483b99a46342501d99e3f10630cfc1219ea32&lt;br /&gt;.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b &lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;この出力からわかるのは、私のリポジトリは全体で3つのオブジェクトを含んでおり、それぞれが以前の例で現れたハッシュ ID を持っているということだ。好奇心を満たすために、最後にこれらのオブジェクトのタイプを調べてみよう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git cat-file -t 588483b99a46342501d99e3f10630cfc1219ea32&lt;br /&gt;&lt;span class="jw_output"&gt;commit&lt;/span&gt;&lt;br /&gt;$ git cat-file -t 0563f77d884e4f79ce95117e2d686d7d6e282887&lt;br /&gt;&lt;span class="jw_output"&gt;tree&lt;/span&gt;&lt;br /&gt;$ git cat-file -t af5626b4a114abcb82d63db7c8082c3c4756e51b&lt;br /&gt;&lt;span class="jw_output"&gt;blob&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;これらのオブジェクトのそれぞれの簡単な内容を見る &lt;span class="jw_in"&gt;git show&lt;/span&gt; コマンドを使うこともできたが、それは読者の練習のために残しておくこととしよう。&lt;br /&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct3_3"&gt;tree はどのように作られるか&lt;/h3&gt;　あらゆるコミットが tree を1つは保持するが、tree はどのように作られるのだろうか？　私たちは blob が、ファイルの内容をその中へと詰め込むことで作成されるということを知っている――そして blob は tree に所有されることも知っている――わけだが、blob を保持する tree がどう作られるか、あるいは tree がその親となるコミットへどうリンクされるか、というのはまだ見たことがない。&lt;br /&gt;&lt;br /&gt;再び新しいサンプルリポジトリを始めよう。ただし、今度は手作業でだ。そうすれば裏側で何が起っているのか正確に掴むことができるだろう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ rm -fr greeting .git&lt;br /&gt;$ echo 'Hello, world!' &amp;gt; greeting&lt;br /&gt;$ git init&lt;br /&gt;$ git add greeting&lt;br /&gt;&lt;/pre&gt;あなたが index へファイルを追加するとき、全ては始まる。さしあたり、index はファイルから blob を作成するために最初に使われるものだと思って欲しい。greeting ファイルを追加した時、リポジトリには変化が起っている。この変化はまだコミットとして見ることはできないが、何が起っているかを確認することはできる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git log &lt;span class="jw_cm"&gt;# これは失敗する。まだコミットは存在しない！&lt;/span&gt;&lt;br /&gt;&lt;span class="jw_output"&gt;fatal: bad default revision 'HEAD'&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="waku_a"&gt;$ git ls-files --stage &lt;span class="jw_cm"&gt;# index によって参照される blob を一覧表示する&lt;/span&gt;&lt;br /&gt;&lt;span class="jw_output"&gt;100644 af5626b4a114abcb82d63db7c8082c3c4756e51b 0 greeting&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;これはなんだろう？　私はまだリポジトリへ何もコミットしていないが、オブジェクトが既に一つ生まれている。このオブジェクトは私がこの記事の始めでやったのと同じハッシュ ID を持っているから、きっと greeting ファイルの内容を表しているはずだ。この時点でハッシュ ID に対して &lt;span class="jw_in"&gt;cat-file -t&lt;/span&gt; を使うこともでき、そうしたらそれが blob であることもわかっただろう。実際それは、さっきのサンプルリポジトリを作ったときに最初に手に入れたと同じ物だ。同じファイルは常に同じ blob になる (万が一私が充分に伝えきれていなかった場合のために、もう一度強調しておこう)。&lt;br /&gt;&lt;br /&gt;この blob はまだ tree によって参照されていないし、どのコミットにも属していない。現在、.git/index という名前のファイル (現在の index にまとめられている blob と tree を参照するファイル) から参照されているだけだ。なので、この中ぶらりの blob のために tree を作成しよう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git write-tree &lt;span class="jw_cm"&gt;# 一つの tree として index の内容を記録する&lt;/span&gt;&lt;br /&gt;&lt;span class="jw_output"&gt;0563f77d884e4f79ce95117e2d686d7d6e282887&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;この値は見たことがあるだろう。同じ blob (とサブtree) を含んだ tree は、常に同じハッシュ ID を持つ。まだコミットオブジェクトはないのだが、blob を保持した tree オブジェクトがもうリポジトリの中に存在している。低レベルの &lt;span class="jw_in"&gt;write-tree&lt;/span&gt; コマンドの目的は、index の内容を全て取り、コミットを作るために新しい tree の中へそれらを詰め込むことだ。&lt;br /&gt;&lt;br /&gt;この tree を直接使用して、新しいコミットオブジェクトを手動で作成することができる。&lt;span class="jw_in"&gt;commit-tree&lt;/span&gt; コマンドを走らせるのだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ echo "Initial commit" | git commit-tree 0563f77&lt;br /&gt;&lt;span class="jw_output"&gt;5f1bc85745dcccce6121494fdd37658cb4ad441f&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;生の &lt;span class="jw_in"&gt;commit-tree&lt;/span&gt; コマンドは tree のハッシュ ID を取り、それを保持するコミットオブジェクトを作成する。もしコミットに親を持たせたかったら、&lt;span class="jw_in"&gt;-p&lt;/span&gt; オプションを使って、明示的に親のコミットのハッシュ ID を指定しなければならない。またここで注意することは、ハッシュ ID はあなたのシステム上に現れるものと異なるということだ。これは、私のコミットオブジェクトには私の名前とコミットを作成した日付が使われているからであり、これら二つの詳細は常にあなたのものとは違うはずだ。&lt;br /&gt;&lt;br /&gt;しかし、まだ作業は終っていない。現在のブランチの新しい HEAD としてそのコミットを登録していないからだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ echo 5f1bc85745dcccce6121494fdd37658cb4ad441f &amp;gt; .git/refs/heads/master&lt;/pre&gt;このコマンドは Git に「"master" という名前のブランチはさきほどの最新のコミットを指すようにしてくれ」と伝える。これとは別のもっと安全な方法は、&lt;span class="jw_in"&gt;update-ref&lt;/span&gt; コマンドを使うことだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git update-ref refs/heads/master 5f1bc857&lt;/pre&gt;master を作成した後、それに対して私たちのワーキングツリーを関連付けなければならない。通常、これはブランチをチェックアウトした時はいつも起こることだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git symbolic-ref HEAD refs/heads/master&lt;/pre&gt;このコマンドは master ブランチに対して、シンボリックに HEAD を関連付ける。これが重要で、なぜなら、ワーキングツリーからの将来のどのコミットも自動的に refs/heads/master の値を更新することになるからだ。&lt;br /&gt;&lt;br /&gt;こんなに単純であるとは信じ難いのだが、もう私の真新しいコミットを見るために &lt;span class="jw_in"&gt;git log&lt;/span&gt; を使うことができる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git log&lt;br /&gt;&lt;span class="jw_output"&gt;commit 5f1bc85745dcccce6121494fdd37658cb4ad441f&lt;br /&gt;Author: John Wiegley &amp;lt;johnw@newartisans.com&amp;gt;&lt;br /&gt;Date: Mon Apr 14 11:14:58 2008 -0400&lt;br /&gt;&lt;br /&gt;Initial commit &lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;傍注：もし refs/heads/master が新しいコミットを指すように私がセットしなかったら、そのコミットは "unreachable (到達不可能)" になると考えられる。現在そのコミットを参照しているものが何もないし、到達可能なコミットの親でもないからだ。このような場合、コミットオブジェクトはそれが持つ tree と全ての blob と一緒に、いつかの時点でリポジトリから削除されるだろう (これは &lt;span class="jw_in"&gt;git gc&lt;/span&gt; と呼ばれるコマンドによって自動的に行われ、あなたが手でやることは滅多にない)。refs/heads の中に名前をリンクさせたコミット、つまり上でやったようものは reachable (到達可能) なコミットになるので、その時点からリポジトリに保管されることが確実になる。&lt;br /&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct3_4"&gt;コミットの美&lt;/h3&gt;　いくつかのバージョン管理システムでは "ブランチ" を特別なものとして作成し、しばしば "メインライン" や "trunk" といったものからはっきり区別する。またブランチはまるでコミットとは非常に異なるものであるかのようにその概念を議論する。しかし、Git ではブランチは異なった実体として存在するわけではない。ただ blob、tree、そしてコミット (*2) があるだけだ。コミットは一つ以上の親を持てるし、それらの親コミットも親を持てるので、これはある単独のコミットがブランチのように扱われることを許可する。なぜならばそれは、そこに至るまでの全ての履歴を知っているからだ。&lt;br /&gt;&lt;br /&gt;(*2) ああ、Git にはタグもあるが、これはただのコミットへの参照であり、ここでは無視する。&lt;br /&gt;&lt;br /&gt;あなたは &lt;span class="jw_in"&gt;branch&lt;/span&gt; コマンドを使うことで、いつでも、一番最新として参照されているコミットを調べることができる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git branch -v&lt;br /&gt;&lt;span class="jw_output"&gt;* master 5f1bc85 Initial commit&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;さあご一緒に。「ブランチはコミットに対する参照名以外の何者でもない」。このように、ブランチとタグは (タグの方は自身についての説明を持つことができるということだけを除いて) 同一であり、まさにそれらは参照されるコミットだ。ブランチはただの名前だが、タグは説明的だ…そう、”タグ” なのだ。&lt;br /&gt;&lt;br /&gt;だが本来は、私たちはエイリアスを使う必要は全くない。例えば、もしそうしたいなら、コミットのハッシュ ID だけを使ってリポジトリ内の全てを参照できる。さて試しに、指定したコミットへワーキングツリーをセットしなおしてみよう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git reset --hard 5f1bc85&lt;/pre&gt;&lt;span class="jw_in"&gt;--hard&lt;/span&gt; オプションはワーキングツリーの現在の全ての変更内容を、それが次のコミットのために登録されているかどうかに関係なく、消去する (このコマンドについては後でより詳しく触れる)。同じことをするもっと安全な方法としては、&lt;span class="jw_in"&gt;git checkout&lt;/span&gt; がある：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout 5f1bc85&lt;/pre&gt;ここでの違いは、ワーキングツリーの変更されたファイルは保護されることだ。もし &lt;span class="jw_in"&gt;checkout&lt;/span&gt; コマンドに &lt;span class="jw_in"&gt;-f&lt;/span&gt; オプションを渡したら、&lt;span class="jw_in"&gt;reset --hard&lt;/span&gt; をしたのと同じことになる。ただし、&lt;span class="jw_in"&gt;checkout&lt;/span&gt; がワーキングツリーだけを変更するのに対して、&lt;span class="jw_in"&gt;reset --hard&lt;/span&gt; は現在のブランチの HEAD を、指定したバージョンの tree を参照するように変更する、という点を除けば。&lt;br /&gt;&lt;br /&gt;コミットベースのシステムの他の嬉しさは、最も複雑なバージョン管理の用語でさえ、一つの語彙を使って言い直すことができることだ。例えば、コミットが複数の親を持つなら、それは "マージコミット" だ――複数のコミットを一つのコミットへマージしたのだから。あるいは、あるコミットが複数の子を持つなら、それは "branch" の祖先であることを表す、など。実際、こういうものと Git の間には違いがない。つまり Git では、世界はシンプルなコミットオブジェクトの集合であり、それぞれのコミットオブジェクトが他の tree や blob を参照する tree を保持し、blob にはデータが保管されている。これよりも複雑な全ては、単に用語的な飾りにすぎない。&lt;br /&gt;&lt;br /&gt;ここに、これら全てのピースがどう組合わさるかの図がある：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://4.bp.blogspot.com/-y3ZcprOwfT0/TdOfCxJnjhI/AAAAAAAAAS4/E7LaTVVBwK0/s514/12_ja.png" alt="commit-tree-blob" width="514" height="391" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct3_5"&gt;コミットを別名で言うと...&lt;/h3&gt;　コミットを理解することは Git を理解する鍵だ。あなたの心がコミットのトポロジをただ受容する時、ブランチ、タグ、ローカル＆リモートリポジトリ等の混乱は置き去りにされ、あなたは叡智ある禅・ブランチングの地平へと達したのを知るだろう。願わくばその体験があなたの腕を切り落とす (*3) 必要がないことを――もし今頃それを考えていたならば、だけれども。&lt;br /&gt;&lt;br /&gt;(*3) 参照：密教僧の恵果（空海の師）のエピソードより。&lt;br /&gt;&lt;br /&gt;コミットが鍵ならば、コミットの指定方法を把握することが熟達への入り口だ。コミットの呼び方にはたくさんの、本当にたくさんの方法があり、コミットの範囲や、コミットによって保持されるオブジェクトさえも Git コマンドのほとんどで受け付けられる。基本以上の使い方の一覧を見てみよう：&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;ブランチ名&lt;/strong&gt;&lt;br /&gt;　以前述べたように、どのブランチ名も "branch" 上の最新コミットへの単なるエイリアスにすぎない。そのブランチがチェックアウトされているなら、これは HEAD という単語を使うのと同じである。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;タグ名&lt;/strong&gt;&lt;br /&gt;　タグ名というエイリアスは、コミットの呼び名であるという観点からはブランチ名と同一だ。二つの間の主要な違いは、タグのエイリアス先は変わることがないのに対して、ブランチのエイリアス先はそのブランチで新しいコミットが作られる度に変わるということだ。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;HEAD&lt;/strong&gt;&lt;br /&gt;　現在チェックアウトされているコミットは常に HEAD と呼ばれる。もし特定のコミットを――ブランチ名を使う代わりに――チェックアウトしたら、HEAD はそのコミットだけを指し、現在どのブランチ上にもいないという状態になる。注意すべきはこのケースは特別なものであり、"using a detached HEAD (孤立した HEAD を使っています)" と言われてしまう。(きっといつもこれで言われているジョークがある…)&lt;br /&gt;&lt;br /&gt;(訳注：detached HEAD ＝ 頭がちょんぎれた！　というジョークでしょうか？)&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;c82a22c39cbc32...&lt;/strong&gt;&lt;br /&gt;　コミットは完全な 40 文字の SHA1 ハッシュ ID を使って常に参照され得る。同じコミットを指すのならもっと他の便利な方法があるので、これは普通カットアンドペーストする時に使われる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;c82a22c&lt;/strong&gt;&lt;br /&gt;　ハッシュ ID でコミットを指定するなら、リポジトリ中でそれが唯一だと参照できるだけの桁を使う必要がある。たいてい、6文字か7文字あれば充分だ。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name^&lt;/strong&gt;&lt;br /&gt;　キャレット文字を使うことで、コミットの親コミットが参照される。もしコミットが2つ以上の親を持つならば、最初のものが使われる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name^^&lt;/strong&gt;&lt;br /&gt;　複数のキャレットを用いることもできる。このエイリアスは、与えられたコミット名の「親の親」を表す。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name^2&lt;/strong&gt;&lt;br /&gt;　もし複数の親を持つコミット (マージコミットのような) ならば、name^N を使って N 番目の親を参照できる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name~10&lt;/strong&gt;&lt;br /&gt;　あるコミットの N 番目の祖先は、チルダ (~) のあとにその順番の数を加えたものを使うことで参照される。この用法は &lt;span class="jw_in"&gt;rebase -i&lt;/span&gt; において一般的だ。例えば、「最新のコミットたちを見せて欲しい」という意味で使える。また、これは name^^^^^^^^^^ と同じになる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name:path&lt;/strong&gt;&lt;br /&gt;　コミットが持つファイルツリー中のとあるファイルを参照するために、コロンの後にファイル名を指定できる。これは &lt;span class="jw_in"&gt;git show&lt;/span&gt;、あるいは2つのコミット間でファイル差分を見るのに役立つ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git diff HEAD^1:Makefile HEAD^2:Makefile&lt;/pre&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name^{tree}&lt;/strong&gt;&lt;br /&gt;　コミット自身ではなく、そのコミットが持つ tree の方を参照できる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name1..name2&lt;/strong&gt;&lt;br /&gt;　これ以降のエイリアスはコミットの範囲を示す。コミット範囲は、特定の期間のあいだで何が起こったかを見るための &lt;span class="jw_in"&gt;git log&lt;/span&gt; のようなコマンドでこの上なく役に立つ。&lt;br /&gt;上の構文は name2 から name1 までの到達可能な全てのコミットを表すが、name1 (が指すコミット) を含まない。もし name1 か name2 が省略されたら、そこには HEAD が使用される。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;name1...name2&lt;/strong&gt;&lt;br /&gt;　"3ドット"の範囲は上記の2ドットバージョンとかなり違う。&lt;span class="jw_in"&gt;git log&lt;/span&gt; のようなコマンドでは、name1 だけ、あるいは name2 だけから参照される全てのコミットを表すが、両方から参照されるコミットは表さない。結果として (name がブランチだとすると) 両方のブランチでユニークな全てのコミットをリストすることになる。&lt;br /&gt;&lt;br /&gt;&lt;span class="jw_in"&gt;git diff&lt;/span&gt; のようなコマンドでは、表現される範囲は「name2」と「name1 と name2 の共通の祖先」の間になる。これは、&lt;span class="jw_in"&gt;git log&lt;/span&gt; では name1 で導入された変更が表示されないのと異なる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;master..&lt;/strong&gt;&lt;br /&gt;　この用法は "master..HEAD" と同等だ。さきほどの用法にも含まれていたが、あえてここでも例として追加した。なぜならば、現在のブランチで作成した変更をレビューするときに、この種のエイリアスを頻繁に使用するからだ。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;..master&lt;/strong&gt;&lt;br /&gt;　これもだ。&lt;span class="jw_in"&gt;git fetch&lt;/span&gt; し終わって、最後にした &lt;span class="jw_in"&gt;rebase&lt;/span&gt; あるいは &lt;span class="jw_in"&gt;merge&lt;/span&gt; からどんな変更が起こったかを見たい時に特に役立つ。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;--since="2 weeks ago"&lt;/strong&gt;&lt;br /&gt;　指定日からの全てのコミットを指す。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;--until=”1 week ago”&lt;/strong&gt;&lt;br /&gt;　指定日までの全てのコミットを指す。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;--grep=pattern&lt;/strong&gt;&lt;br /&gt;　コミットメッセージが正規表現パターンにマッチする全てのコミットを指す。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;--committer=pattern&lt;/strong&gt;&lt;br /&gt;　コミッタ (コミットをした人) がパターンにマッチする全てのコミットを指す。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;--author=pattern&lt;/strong&gt;&lt;br /&gt;　author がパターンにマッチする全てのコミットを指す。コミットの author とは、そのコミットの変更を作成した人のことだ。ローカルな開発ではこれは常にコミッタと同じになるが、パッチが e-mail で送られている時は、author とコミッタは普通別になる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;--no-merges&lt;/strong&gt;&lt;br /&gt;　指定した範囲中で、ただ一つだけの親を持つ全てのコミットを指す――すなわち、全てのマージコミットを無視する。&lt;br /&gt;&lt;br /&gt;これらのオプションの大半は、混ぜたりかけ合わせたりできる。ここに、以下で説明するログエントリを表示する例を示す。現在のブランチでの変更 (ブランチは master から派生している) で、かつ自分が変更したもので、過去一ヶ月の間の、"foo"というテキストをコミットメッセージに含むもの。すると以下になる。&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git log --grep='foo' --author='johnw' --since="1 month ago" master..&lt;/pre&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct3_6"&gt;ブランチングと rebase の力&lt;/h3&gt;　コミットを操作するための最も有能な Git コマンドは、無邪気にも名付けられた &lt;span class="jw_in"&gt;rebase&lt;/span&gt; コマンドだ。基本的に、あなたが作業をするブランチは全て、一つ以上の「ベースコミット」を持っている。ブランチがそこで生まれたコミットのことだ。例として、以下のよくあるシナリオを見ていこう。注意しておくと、矢印は過去を遡って指している。なぜならば各コミットはその親を参照しているのであって、子ではないからだ。したがって、D と Z のコミットがそれぞれのブランチの HEAD を表している：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://3.bp.blogspot.com/-vJbAG4LIGoM/TdOfDD-5nMI/AAAAAAAAATA/d9vAHrPjxJU/s314/15.png" alt="basic-history" width="314" height="129" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;この場合、稼働中のブランチは２つの「ヘッド」を示している。D と Z、両方のブランチが A という共通の親を持つ。&lt;span class="jw_in"&gt;git show-branch&lt;/span&gt; の出力がまさにこの情報を見せてくれる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git branch&lt;br /&gt;&lt;span class="jw_output"&gt;  Z&lt;br /&gt;* D&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="waku_a"&gt;$ git show-branch&lt;br /&gt;&lt;span class="jw_output"&gt;!  [Z] Z&lt;br /&gt; * [D] D&lt;br /&gt;--&lt;br /&gt; * [D] D&lt;br /&gt; * [D^] C&lt;br /&gt; * [D~2] B&lt;br /&gt;+  [Z] Z&lt;br /&gt;+  [Z^] Y&lt;br /&gt;+  [Z~2] X&lt;br /&gt;+  [Z~3] W&lt;br /&gt;+* [D~3] A&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この出力を読むには少しの慣れが必要だが、本質的には上記の図と変わるところはない。ここでは、以下のようなことを伝えている：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ブランチが最初の分岐を体験したのはコミット A の時だ (またそれは D~3 として知られていて、そして、あなたがそう思うなら Z~4 とも言える)。コミット^ という構文はコミットの親を指すのに使われ、コミット~3 は3つ上の親、または曾祖父を指す。&lt;/li&gt;&lt;li&gt;これは下から上に読んで行く。最初の列 (＋の印) は Z という名前のブランチが分岐したことを示していて、それは4つのコミットを持つ。W、X、Y、そして Z だ。&lt;/li&gt;&lt;li&gt;二番目の列 (アスタリスクの印) は現在のブランチで発生したコミットを示す。すなわち３つのコミットの B、C、そして D だ。&lt;/li&gt;&lt;li&gt;出力の一番上、線で区切られることで下部と分離している部分は、表示されるブランチたちを識別する。ブランチにラベルされている印が、そのブランチに属するコミットへとラベルづけされるように列が配置されている。&lt;/li&gt;&lt;/ul&gt;今、実行したいと思うアクションがあり、ワーキングブランチの Z をメインブランチの D になるように持っていきたい。言い換えれば B、C そして D でやった作業を Z へ取り込みたい。&lt;br /&gt;&lt;br /&gt;他のバージョン管理システムでは、この手のことは「ブランチのマージ」を使用して済ます事になる。実際、ブランチのマージは Git でも実行可能だ。マージの使用は、Z が 公開されたブランチであり、そのコミット履歴を変えたくないという場合には、今も必要とされる。実行するコマンドはこうだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout Z &lt;span class="jw_cm"&gt;# Z ブランチへ切り替え&lt;/span&gt;&lt;br /&gt;$ git merge D &lt;span class="jw_cm"&gt;# B、C、Dのコミットを Z へマージ&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これがその後のリポジトリの状態だ：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://1.bp.blogspot.com/-5Xxb7NmJCjI/TdOfDMozKCI/AAAAAAAAATI/BRYEjc0_3oM/s424/16.png" alt="merged-history" width="424" height="138" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;いま Z ブランチをチェックアウトするなら、それは以前の Z (現在は Z^ として指す) の内容に、D の内容をマージしたものが含まれているだろう。(注意：実際のマージ操作では、D と Z の状態の間の全ての衝突を解決している必要がある)&lt;br /&gt;&lt;br /&gt;新しい Z ブランチは現在 D からの変更を含んでいるが、Z と D をマージしたことを表す新しいコミットも含んでいる。そのコミットは今 Z' として表示されている。これは何も新しいものを追加しないコミットだが、D と Z をまとめる操作を終えたことを表す。ある意味ではそれは「メタコミット」と言える。なぜならばその内容は単にリポジトリ中で作業したことに関係していて、ワーキングツリーには何も新しいことをしていないからだ。&lt;br /&gt;&lt;br /&gt;しかしながら、Z ブランチをそのまま D の上に移植し、Z が前方になるよういっぺんに移動させてしまう方法がある。パワフルな &lt;span class="jw_in"&gt;rebase&lt;/span&gt; コマンドを使うのだ。ここに、私たちが目指す図がある：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://4.bp.blogspot.com/-LBCMS7ywJes/TdOfDXKNSSI/AAAAAAAAATQ/O-A6mmtcW2k/s471/17.png" alt="rebased-history" width="471" height="136" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;この状態は最も直接に私たちがしたいことを表している。私たちのローカルリポジトリでは、開発ブランチの Z がメインブランチ D の最新の仕事に基づくようになる。なぜ「rebase」とそのコマンドが呼ばれるのかは、それが指定したブランチのベースになるコミットを変更するからだ。もしあなたがそれを毎回のように走らせるなら、ワーキングブランチ上のパッチたちを制限なく前に進ませ、常にメインブランチと共に最新の状態に置くことができる。しかも、開発ブランチへ不必要なマージコミットを追加しなくて済む (*4)。ここでは、上で実行したマージ操作と比較できるよう、コマンドを実行している：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout Z &lt;span class="jw_cm"&gt;# Z ブランチへ切り替える&lt;/span&gt;&lt;br /&gt;$ git rebase D &lt;span class="jw_cm"&gt;# Z のベースコミットを D の地点へ変更する&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これがなぜローカルブランチのためだけなのだろう？　なぜならあなたが &lt;span class="jw_in"&gt;rebase&lt;/span&gt; をする度に、ブランチ内の全てのコミットを潜在的に変更してしまうからだ。以前に、W が A を分岐元にしていた時、それは A から W へ内容を変化させるために必要な変更だけを含んでいた。しかしながら、&lt;span class="jw_in"&gt;rebase&lt;/span&gt; が 走ったあとは、W は D から W' へ内容を変化させるために必要な変更を含むように書き換えられてしまう。そして W から X への内容の変化すらも変更されてしまう。なぜならば A+W+X は現在 D+W'+X' だからだ――Y 以降も同じだ。もしこれが、ブランチの変更が他の人々に見られているならば、そしてあなたの下流の利用者の誰かが Z から分岐した彼ら自身のローカルブランチを作成しているならば、彼らのブランチは今、新しい Z' ではなく古い Z を指しているだろう。&lt;br /&gt;&lt;br /&gt;一般に、以下の経験則が利用できる。もしそこから他のブランチが分岐したことがないようなローカルブランチを持っているなら、&lt;span class="jw_in"&gt;rebase&lt;/span&gt; を使い、その他の全てのケースでは &lt;span class="jw_in"&gt;merge&lt;/span&gt; を使う。あなたのローカルブランチの変更をメインブランチへ &lt;span class="jw_in"&gt;pull&lt;/span&gt; し戻す用意が出来ているときも、&lt;span class="jw_in"&gt;merge&lt;/span&gt; は役に立つ。&lt;br /&gt;&lt;br /&gt;(*4) これを使用しない、そして代わりにマージを使う正当な理由が存在することに注意しよう。選択はあなたの状況に依存する。&lt;span class="jw_in"&gt;rebase&lt;/span&gt; の一つの悪い面は、rebase されたワーキングツリーはコンパイルに通っても、中間のコミットのコンパイルが通るかはもはや何の保証もないということだ。新しい rebase された状態でそれらがコンパイルされたことはないからだ。歴史的正当性があなたにとって重要なら、&lt;span class="jw_in"&gt;merge&lt;/span&gt; を好んで使うこと。(訳注：これに対する反論→&lt;a href="http://keijinsonyaban.blogspot.com/2011/01/rebase.html"&gt;【翻訳】Rebaseは安全である&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;h4 class="jw_h"&gt;対話的リベース&lt;/h4&gt;　上記のように &lt;span class="jw_in"&gt;rebase&lt;/span&gt; が実行されたとき、Z ブランチを D コミット (すなわち、D ブランチの HEAD) の上へリベースするために、W から Z までの全てのコミットが自動的に書き換えられる。しかし、どのように書き換えが行われるかをあなたが完全に取り仕切ることもできる。&lt;span class="jw_in"&gt;rebase&lt;/span&gt; に &lt;span class="jw_in"&gt;-i&lt;/span&gt; オプションを与えると、Z ローカルブランチ内のコミット毎に何が行われるかを選択するための編集バッファが開くことになる：&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;pick&lt;/strong&gt;&lt;br /&gt;　これは、あなたが対話的モードを使わなかった場合の、ブランチ内の各コミットへ選択されるデフォルトの振る舞いだ。当該コミットは自身 (今書き換えられている) の親コミットへ再適用されることを意味する。発生したコンフリクトに関係するコミット毎に、&lt;span class="jw_in"&gt;rebase&lt;/span&gt; コマンドはあなたにそれらを解決する機会を与える。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;squash&lt;/strong&gt;&lt;br /&gt;　squash を指定されたコミットは、自身の内容を、それの一つ前のコミットの内容の中へ「折り込まれる」ことになる。これは何回でも行われる場合がある。もし上記の例のブランチを対象に、全てのコミットを squash にしたら (一番目のコミットは除く。そのコミットは &lt;strong&gt;squash&lt;/strong&gt; されるために &lt;strong&gt;pick&lt;/strong&gt; でなければならない)、新しい Z ブランチはただ一つだけのコミットを含んで、D の上へ追加されることになる。あなたが複数のコミットに渡って変更をばらまいているが、それら全てを一つのコミットに見せるように履歴を書き換えたいならば、これは役に立つ。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;edit&lt;/strong&gt;&lt;br /&gt;　&lt;strong&gt;edit&lt;/strong&gt; としてコミットをマークすると、&lt;span class="jw_in"&gt;rebase&lt;/span&gt; のプロセスはそのコミットの所で停止し、そのコミットを反映したワーキングツリーと共に、シェルがあなたの元に残される。その時 index は、あなたがそのコミットを作成する際に登録された変更を全て含んでいる。従ってあなたはなんでもしたいように変更できる。変更のやり直し、変更を元に戻す、その他。そしてコミットをした後、&lt;span class="jw_in"&gt;rebase --continue&lt;/span&gt; を走らせると、そのコミットはまるで元からそういう変更だったかのように書き換えられる。&lt;br /&gt;&lt;br /&gt;&lt;strong style="text-decoration: underline"&gt;(drop)&lt;/strong&gt;&lt;br /&gt;　もし対話的リベース時の編集バッファ中の一覧からコミットを削除する、あるいはコメントアウトするなら、そのコミットは単にまるでチェックインされていなかったかのように見えなくなる。ブランチ内の後ろのコミットがそれらの変更に依存していたとしたら、これはマージの衝突を起こしうることに注意すること。&lt;br /&gt;&lt;br /&gt;このコマンドのパワーは最初理解しにくいのだが、それはあなたにどんなブランチの形をも、事実上無制限にコントロールすることを許可する。これは以下のことに使用できる：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;複数のコミットを一つのコミットにまとめる。&lt;/li&gt;&lt;li&gt;コミットの順番を変える。&lt;/li&gt;&lt;li&gt;現在は後悔している正しくない変更を取り除く。&lt;/li&gt;&lt;li&gt;ブランチのベースを、リポジトリ中の他のコミットへ移す。&lt;/li&gt;&lt;li&gt;あるコミットを、コミットしてだいぶ後になってから訂正する。&lt;/li&gt;&lt;/ul&gt;この時点で &lt;span class="jw_in"&gt;rebase&lt;/span&gt; の man ページを読むことをお勧めする。この野獣の真のパワーを開放するかもしれない方法のいくつかの良い例を含んでいるからだ。このツールがどのように潜在能力を発揮するかについての最後のセンスをあなたに与えるために、以下のシナリオを考えてみて欲しい。第二のブランチの L を新しい Z の頭に移したいのだとしたらどうするだろうか：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://2.bp.blogspot.com/-NcaBaSfBh_Y/TdOfOuD26PI/AAAAAAAAATY/CkeaBNC2C6E/s420/19_1.png" alt="basic-history2" width="420" height="196" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;この図を見てみると、開発のメインラインとして D があり、その３つ前のコミットから試作開発のための Z ブランチが分岐している。これら両方の真ん中の地点、C と X がそれぞれのブランチの HEAD だったとき、最終的に L となる他の試作ブランチを開始することを決めた。現在、L のコードが良い感じだとわかったが、メインラインへマージし戻すほどにはあまり良くない。なのでそれらの変更を Z 開発ブランチへ移動させることに決め、結局そこでやった全ての事が一つのブランチになるようにする。ああ、そして今それをやろうって時に、コミット J のコピーライトの日付をすぐにでも編集したくなった。私たちがその変更を作成したとき、2008年のままだったのを忘れていたからだ！　この絡まりをほどくのに必要なコマンドはこうだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout L&lt;br /&gt;$ git rebase -i Z&lt;br /&gt;&lt;/pre&gt;発生する全ての衝突を解決したら、現在はこのようなリポジトリになる：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://4.bp.blogspot.com/-LbZ4rdtbnbM/TdOfO0RHMpI/AAAAAAAAATg/iq4HIXVB_CA/s520/19_2.png" alt="rebased-history2" width="520" height="174" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;お分かりのように、ローカル開発での話ならば、&lt;span class="jw_in"&gt;rebase&lt;/span&gt; はあなたのコミットがどのようにリポジトリに現れるかを無制限にコントロールする力を与えてくれる。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct4"&gt;4. インデックス：仲介者を知ろう&lt;/h2&gt;&lt;br /&gt;　ファイルシステム上に保管されているデータファイルと、リポジトリに保管されている Git の blob の間には、なにやら奇妙な存在が立ちはだかっている。Git のインデックスだ。コイツを理解することを困難にしている部分は、それが不運な名前を持っているということだろう。新しく作成された tree や blob のセット (&lt;span class="jw_in"&gt;git add&lt;/span&gt; を実行した時に作成される) を参照するという意味では、これは index と言える。これら新しいオブジェクトは、あなたのリポジトリへコミットするという目的で、新しい tree へすぐにまとめられるだろう――だがその時まで、それらは index にだけ参照される。もし &lt;span class="jw_in"&gt;git reset&lt;/span&gt; によって index から変更を取り外すと、未来のいつかの時点で削除される孤立した blob を持つことになる。&lt;br /&gt;&lt;br /&gt;index はただ本当に、次のコミットのためのステージングエリアであり、それがなぜ存在するかの良い理由もある。それは CVS や Subversion ユーザにとって慣れないかもしれないが、Darcs ユーザにとっては全くもって身近な開発モデルをサポートする。ステージで次のコミットを組み立てる能力だ。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://1.bp.blogspot.com/-sY5EIAwW--k/TdOfPB7D4II/AAAAAAAAATo/P9N6FxUN7Yc/s466/20_ja.png" alt="index-is-next-commit" width="466" height="380" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;まず最初に、index をほぼ完全に無視する方法があると言わせて欲しい。つまり &lt;span class="jw_in"&gt;git commit&lt;/span&gt; に &lt;span class="jw_in"&gt;-a&lt;/span&gt; フラグを渡すのだ。例えば Subversion で作業する方法を考えてみよう。&lt;span class="jw_in"&gt;svn status&lt;/span&gt; と タイプする時、あなたが見ることになるのは、次の &lt;span class="jw_in"&gt;svn commit&lt;/span&gt; の呼び出しであなたのリポジトリに適用されるだろうアクションのリストだ。ある意味で、この「次のアクションのリスト」は一種の非公式の index で、ワーキングツリーの状態と HEAD の状態を比べることで決定される。もし foo.c というファイルが変更されているならば、次のコミットでそれらの変更が保存されるだろう。もしある未知のファイルの横にクエスチョンマークがあれば、それは無視される。しかし、&lt;span class="jw_in"&gt;svn add&lt;/span&gt; で追加された新しいファイルは、リポジトリに追加されることになる。&lt;br /&gt;&lt;br /&gt;これは &lt;span class="jw_in"&gt;git commit -a&lt;/span&gt; を使った場合に起こる事と違いがない。新しい、未知のファイルは無視されるが、&lt;span class="jw_in"&gt;git add&lt;/span&gt; で追加された新しいファイルなら、ファイルにしたどんな変更もリポジトリに追加される。この作用は Subversion が実行するやり方とほとんど同じだ。&lt;br /&gt;&lt;br /&gt;本当の違いは、Subversion の場合では、あなたの「次のアクションのリスト」は常に現在のワーキングツリーを見て決定されるということだ。Git では、「次のアクションのリスト」は index の内容であり、次の HEAD の状態になるであろうものを表現し、そしてコミットを実行する前に直接操作することができる。これは、前もってその変更をステージさせてくれることによって、何が起きるかについてコントロールする追加のレイヤーを与えてくれるということだ。&lt;br /&gt;&lt;br /&gt;まだ理解がクリアでないなら、以下の例について考えてみよう。あなたは信頼できるソースファイル、foo.c を持ち、それに対して無関係の二つのセットの変更を行なった。あなたがしたいことは、それらの変更を分割して二つの異なるコミットにし、それぞれに別の説明をつけたい。Subversion なら、これについてあなたがするだろう事はこうだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ svn diff foo.c &amp;gt; foo.patch&lt;br /&gt;$ vi foo.patch&lt;br /&gt;&lt;span class="jw_message"&gt;＜foo.patch を編集し、後でコミットしたい変更を維持する＞&lt;/span&gt;&lt;br /&gt;$ patch -p1 -R &amp;lt; foo.patch &lt;span class="jw_cm"&gt;# 二番目の変更セットを取り除く&lt;/span&gt;&lt;br /&gt;$ svn commit -m "First commit message"&lt;br /&gt;$ patch -p1 &amp;lt; foo.patch &lt;span class="jw_cm"&gt;# 残りの変更を再適用する&lt;/span&gt;&lt;br /&gt;$ svn commit -m "Second commit message"&lt;br /&gt;&lt;/pre&gt;これが楽しく感じる？　なら今度は複雑かつ動的な変更のセットで複数回繰り返してみることだ。次は Gitで、index を使った方法だ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git add --patch foo.c&lt;br /&gt;&lt;span class="jw_message"&gt;＜最初にコミットしたいハンクを選択する＞&lt;/span&gt;&lt;br /&gt;$ git commit -m "First commit message"&lt;br /&gt;$ git add foo.c &lt;span class="jw_cm"&gt;# 残りの変更を add する&lt;/span&gt;&lt;br /&gt;$ git commit -m "Second commit message"&lt;br /&gt;&lt;/pre&gt;その上、これはもっと簡単にできるのだ！　もしあなたが Emacs が好きなら、Christian Neukirchan 作の最上級のツール gitsum.el (*5) がこの退屈なプロセスを美しくしてくれる。私は最近それを使って、合成されてしまっている変更を11の別のコミットへ分離した。ありがとう、Christian！&lt;br /&gt;&lt;br /&gt;(*5) &lt;a href="http://chneukirchen.org/blog/archive/2008/02/introducing-gitsum.html"&gt;http://chneukirchen.org/blog/archive/2008/02/introducing-gitsum.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct4_1"&gt;一歩先のインデックス&lt;/h3&gt;　なになに、index だって…。それがあれば変更のセットを事前ステージングでき、したがって、それをリポジトリへコミットする前に繰り返しパッチを組み上げることができるのか。さて、そんなコンセプトを以前もどこかで聞いたような…。&lt;br /&gt;&lt;br /&gt;「Quilt！」と考えているなら、あなたはまさに正しい。実際、index は Quilt (*6) と少ししか違わない。index の方は、一度にただ一つだけのパッチが構築されるという制限が追加されているだけだ。&lt;br /&gt;&lt;br /&gt;(*6) &lt;a href="http://savannah.nongnu.org/projects/quilt"&gt;http://savannah.nongnu.org/projects/quilt&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;しかし、さっきの foo.c の中に2セットの変更があるのではなく4セットあったらどうなる？　プレーンな Git では、一つ解きほぐしてコミットし、そしてまた次のを解きほぐす、としなければならないだろう。index を使えばこれははるかに簡単になるが、それらをコミットする前に、それらの変更の各々を様々な組み合わせでテストしたいとしたらどうする？　すなわち、パッチに A、B、C、D とラベル付けしたとして、どの変更が本当に正しいものか決める前に、A+B でテストし、次が A+C、次がA+D…というようにテストしたいとしたら？&lt;br /&gt;&lt;br /&gt;複数の変更を休みなく選んで組み合わせるような仕組みは、Git 自身には存在しない。もちろん、複数ブランチはあなたに並行的な開発をさせることができるし、index は複数の変更を一連のコミットになるようステージングさせてくれるが、その二つを一度にすることはできない。一連のパッチを、その中から同時に使用・不使用を抜粋してステージングし、最終的にそれらをコミットする前に、一斉にパッチの統合を検証すること、をだ。&lt;br /&gt;&lt;br /&gt;あなたがこういった事をするのに必要なものは、一度に1コミットするよりも深みのある index だろう。これはまさに Stacked Git (*7) が提供するものだ。&lt;br /&gt;&lt;br /&gt;(*7) &lt;a href="http://procode.org/stgit"&gt;http://procode.org/stgit&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以下は、素の Git を使ってワーキングツリーの中で2つの異なるパッチをコミットする時のやり方だ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git add -i &lt;span class="jw_cm"&gt;# 最初の変更セットを選択する&lt;/span&gt;&lt;br /&gt;$ git commit -m "First commit message"&lt;br /&gt;$ git add -i &lt;span class="jw_cm"&gt;# 二番目の変更セットを選択する&lt;/span&gt;&lt;br /&gt;$ git commit -m "Second commit message"&lt;br /&gt;&lt;/pre&gt;これはうまく動作するが、二番目のコミットを単独でテストする目的で一番目のコミットを選択的に適用しない、ということができない。以下のようにしなければならないだろう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git log &lt;span class="jw_cm"&gt;# 一番目のコミットのハッシュIDを見つける&lt;/span&gt;&lt;br /&gt;$ git checkout -b work &amp;lt;最初のコミットのハッシュ ID&amp;gt;^&lt;br /&gt;$ git cherry-pick &amp;lt;２番目のコミットのハッシュ ID&amp;gt;&lt;br /&gt;&lt;span class="jw_message"&gt;＜...  テストを走らせる ...＞&lt;/span&gt;&lt;br /&gt;$ git checkout master &lt;span class="jw_cm"&gt;# master ブランチへ戻る&lt;/span&gt;&lt;br /&gt;$ git branch -D work &lt;span class="jw_cm"&gt;# 一時的なブランチを削除する&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;明らかに、もっといい方法があるはずだ！　&lt;span class="jw_in"&gt;stg&lt;/span&gt; コマンドがあれば、両方のパッチをキューに入れ、好きな順番でそれらを再適用でき、単独または組み合わせてのテストをしたりできる。以下で &lt;span class="jw_in"&gt;stg&lt;/span&gt; コマンドを使って、前の例で利用した同じ二つのパッチをキューに入れている：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ stg new patch1&lt;br /&gt;$ git add -i &lt;span class="jw_cm"&gt;# 一番目の変更セットを選択&lt;/span&gt;&lt;br /&gt;$ stg refresh --index&lt;br /&gt;$ stg new patch2&lt;br /&gt;$ git add -i &lt;span class="jw_cm"&gt;# 二番目の変更セットを選択&lt;/span&gt;&lt;br /&gt;$ stg refresh --index&lt;br /&gt;&lt;/pre&gt;今、二番目だけをテストするために一番目のパッチを選択的に非適用状態にしたいとする。それは非常に簡単だ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ stg applied&lt;br /&gt;&lt;span class="jw_output"&gt;patch1&lt;/span&gt;&lt;br /&gt;&lt;span class="jw_output"&gt;patch2&lt;/span&gt;&lt;br /&gt;&lt;span class="jw_message"&gt;＜...  両方のパッチを使ってテスト ...＞&lt;/span&gt;&lt;br /&gt;$ stg pop patch1&lt;br /&gt;&lt;span class="jw_message"&gt;＜...  patch2 だけを使ってテスト ...＞&lt;/span&gt;&lt;br /&gt;$ stg pop patch2&lt;br /&gt;$ stg push patch1&lt;br /&gt;&lt;span class="jw_message"&gt;＜...  patch1 だけを使ってテスト ...＞&lt;/span&gt;&lt;br /&gt;$ stg push -a&lt;br /&gt;$ stg commit -a &lt;span class="jw_cm"&gt;# 全てのパッチをコミットする&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;これは、一時的なブランチを作り、コミットのハッシュ ID を指定して &lt;span class="jw_in"&gt;cherry-pick&lt;/span&gt; を適用するよりも確実に簡単だ。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct5"&gt;5. リセットすること、またはリセットしないこと&lt;/h2&gt;&lt;br /&gt;　Git の中でマスターすることがより難しいコマンドの一つが、&lt;span class="jw_in"&gt;git reset&lt;/span&gt; だ。それは他のコマンドよりも使用者に噛み付きがちのように思える。名前から理解できるように、それはワーキングツリーと、HEAD の参照の両方を潜在的に変更してしまえる。なので、このコマンドの簡単なレビューが役立つだろうと思う。&lt;br /&gt;&lt;br /&gt;そもそも &lt;span class="jw_in"&gt;git reset&lt;/span&gt; は「参照エディタ」であり、「index エディタ」であり、「ワーキングツリーエディタ」だ。とてもたくさんの仕事をする能力があることが混乱の一因になっている。これら3つのモードの間の違いを調査し、そして Git のコミットのモデルの中にそれらがどうフィットするかを調べてみよう。&lt;br /&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct5_1"&gt;mixed reset の実行&lt;/h3&gt;　もし &lt;span class="jw_in"&gt;--mixed&lt;/span&gt; オプションを使うなら (あるいは、これがデフォルトなので、何もオプションをつけないなら)、&lt;span class="jw_in"&gt;git reset&lt;/span&gt; は与えられたコミットにマッチするように HEAD の参照を切り替えるとともに、index の部分を取り消すだろう。&lt;span class="jw_in"&gt;--soft&lt;/span&gt; オプションとの主な違いは、&lt;span class="jw_in"&gt;--soft&lt;/span&gt; では HEAD の 意味だけを変更し、index には何も触らないことだ。&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git add foo.c &lt;span class="jw_cm"&gt;# 新しい blob として index へ変更を追加する&lt;/span&gt;&lt;br /&gt;$ git reset HEAD &lt;span class="jw_cm"&gt;# index にステージされた全ての変更を削除する&lt;/span&gt;&lt;br /&gt;$ git add foo.c &lt;span class="jw_cm"&gt;# 間違えていたので add をやり直し&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct5_2"&gt;soft reset の実行&lt;/h3&gt;　&lt;span class="jw_in"&gt;git reset&lt;/span&gt; で &lt;span class="jw_in"&gt;--soft&lt;/span&gt; オプションを使うと、異なるコミットへ HEAD の参照を単に変更する (そこは先ほどの効果と同じだ)。ワーキングツリーでやった変更は、触れられずに残される。これは、以下の2つのコマンドが同等ということを意味する：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git reset --soft HEAD^ &lt;span class="jw_cm"&gt;# 自身の親へ HEAD を戻す。最後のコミットを事実上無視することになる&lt;/span&gt;&lt;br /&gt;$ git update-ref HEAD HEAD^ &lt;span class="jw_cm"&gt;# 手動ではあるが、同じことをする&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;どっちの場合でも、現在のワーキングツリーはより古い HEAD の上に存在するので、もし &lt;span class="jw_in"&gt;git status&lt;/span&gt; を走らせたら多くの変更が見えることになる。あなたのファイルは変更されてはおらず、単にそれらは現在古いバージョンと比較されているということだ。この状況は古いコミットを置き換えるように新しいコミットを作成するチャンスを与えてくれる。実際には、あなたが変更したいと思うコミットがもっとも最後にコミットされたものならば、あなたは最後のコミットに対して最新の変更を追加するために &lt;span class="jw_in"&gt;git commit --amend&lt;/span&gt; を使うこともできる。まるでそれらを一緒にコミットしていたかのようにね。&lt;br /&gt;&lt;br /&gt;しかし、以下に注意しよう。あなたの下流に作業者がいて、その人たちがあなたの以前の HEAD――もう捨ててしまったものだ――を元に作業をしていたら、このような HEAD の変更は、その人たちの次の &lt;span class="jw_in"&gt;pull&lt;/span&gt; の後で、自動的な強制マージを引き起こす。以下は soft reset してから新しいコミットをした後、こうなるだろうというコミット履歴だ：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://3.bp.blogspot.com/-HEfgLA-sVLQ/TdOfPNTBqcI/AAAAAAAAATw/kS1DmjQ-O4U/s495/25_1_ja.png" alt="new-head-and-old-head" width="495" height="181" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;そしてこっちが、下流の作業者が再び &lt;span class="jw_in"&gt;pull&lt;/span&gt; をした後の彼らの HEAD がこうなるだろうという図だ (同色のコミットが同じものを意味している)：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://3.bp.blogspot.com/-u85FnhAzKbc/TdOfPQI4IyI/AAAAAAAAAT4/1gXoSNrVY0M/s526/25_2.png" alt="downstream-concumser's-history" width="526" height="156" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3 class="jw_h" id="ct5_3"&gt;hard reset の実行&lt;/h3&gt;　hard reset (&lt;span class="jw_in"&gt;--hard&lt;/span&gt; オプション) は非常に危険である可能性がある。一度に二つの異なることができるからだ。最初の例として、現在の HEAD に対して hard reset を行うなら、ワーキングツリー内の全ての変更が消去され、ワーキングツリーのファイルが HEAD の内容と一致するようになる。&lt;br /&gt;&lt;br /&gt;こういう事をするなら、もう一つ別のコマンドがある。&lt;span class="jw_in"&gt;git checkout&lt;/span&gt; だ。それは index が空ならば、&lt;span class="jw_in"&gt;git reset --hard&lt;/span&gt; とほぼ似た操作をする。そうでないなら、ワーキングツリーを index と一致させる。&lt;br /&gt;&lt;br /&gt;次の例として、もっと以前のコミットに対して hard reset をしたならば、まず最初に soft reset をしてから、&lt;span class="jw_in"&gt;git reset --hard&lt;/span&gt; を使ってワーキングツリーをリセットしたのと同じになる。したがって、以下のコマンドは同等だ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git reset --hard HEAD~3 &lt;span class="jw_cm"&gt;# 変更を捨てて、過去に遡る&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git reset --soft HEAD~3 &lt;span class="jw_cm"&gt;# 以前のコミットをHEADが指すようにする&lt;/span&gt;&lt;br /&gt;$ git reset --hard &lt;span class="jw_cm"&gt;# ワーキングツリー内の差異を消し去る&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;お分かりのように、hard reset を行うことは非常に破壊的になりうる。幸い、同じ効果を達成するもっと安全な方法として、Git では &lt;span class="jw_in"&gt;stash&lt;/span&gt; (次のセクションで見る) を使った方法が存在する：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git stash&lt;br /&gt;$ git checkout -b new-branch HEAD~3 &lt;span class="jw_cm"&gt;# head を遡る！&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;あなたがたった今現在のブランチを本当に修正したいのかどうか確信できないというならば、このアプローチには二つの異なる利点がある：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;stash へあなたの仕事を保存する。そして、いつでもそこに戻ることができる。注意としては、stash は各ブランチ固有のものではないから、あるブランチのツリーの状態を stash して、後でそれを他のブランチに適用してしまう可能性もある。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;過去の状態へワーキングツリーを巻き戻すが、新しいブランチ上で過去の状態に対して変更をコミットすると決めたならば、あなたのオリジナルブランチは維持されたままになるだろう。&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;もし new-branch への変更を作成したとして、その後それが新しい master ブランチになって欲しいと決めたなら、以下のようにコマンドを実行する：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git branch -D master &lt;span class="jw_cm"&gt;# さようなら古い master（まだ reflog には、いる）&lt;/span&gt;&lt;br /&gt;$ git branch -m new-branch master &lt;span class="jw_cm"&gt;# 今や new-branch が master になる&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この話の教訓は以下のとおりだ。あなたは&lt;strong&gt;現在のブランチ上で&lt;/strong&gt; &lt;span class="jw_in"&gt;git reset --soft&lt;/span&gt; や &lt;span class="jw_in"&gt;git reset --hard&lt;/span&gt; (ワーキングツリーも変更する) を使って一大手術をすることもできるが、なぜそんなことをしたいのだろうか？　Git はとても簡単で安くブランチで作業させてくれる。(新しく作った) あるブランチ上で破壊的な修正をし、それから古い master の代わりとしてそのブランチを使うようにするのは、常に価値のあることだ。それはまるでフォースの暗黒面のような魅力を持っている…。&lt;br /&gt;&lt;br /&gt;それから、あなたが誤って &lt;span class="jw_in"&gt;git reset --hard&lt;/span&gt; を走らせ、現在の変更を失うだけでなく、master ブランチから積み重ねたコミットまでも削除してしまったらどうなるだろう？　そうなのだ、&lt;span class="jw_in"&gt;git stash&lt;/span&gt; を使ってスナップショットを取る (次のセクションで見る) という癖をつけていなかったのなら、失ったワーキングツリーを復活させる方法はない。しかし &lt;span class="jw_in"&gt;reflog&lt;/span&gt; (これも次のセクションで説明される) と共に &lt;span class="jw_in"&gt;git reset --hard&lt;/span&gt; を再び用いれば、ブランチだけは以前の状態へ復帰させることができる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git reset --hard HEAD@{1} &lt;span class="jw_cm"&gt;# reflog から変更前の状態へ復帰させる&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;安全策でいくなら、必ず &lt;span class="jw_in"&gt;git stash&lt;/span&gt; を最初に走らせてから &lt;span class="jw_in"&gt;git reset --hard&lt;/span&gt; を使うことだ。これは後になってあなたの白髪が増えるのを防ぐだろう。&lt;span class="jw_in"&gt;git stash&lt;/span&gt; を走らせたなら、ワーキングツリーの変更を復帰させることにそれを使うことができる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git stash &lt;span class="jw_cm"&gt;# これをするのが常に良いことなので、とりあえずする&lt;/span&gt;&lt;br /&gt;$ git reset --hard HEAD~3 &lt;span class="jw_cm"&gt;# 以前へ遡る&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git reset --hard HEAD@{1} &lt;span class="jw_cm"&gt;# おっと、あれは間違いだった、やり直し！&lt;/span&gt;&lt;br /&gt;$ git stash apply &lt;span class="jw_cm"&gt;# そしてワーキングツリーの変更を呼び戻す&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct6"&gt;6. 鎖をつなぐ最後の輪： stash と reflog&lt;/h2&gt;&lt;br /&gt;　今までで、Git の中へ blob を送り込む2段階の方法を説明してきた。blob はまず最初に index に作成され、そこではまだ親 tree と所属するコミットがない。それからリポジトリへとコミットされ、コミットが保持する tree にぶら下がる葉として存在することになる。しかし、blob をリポジトリ内へ置くことができる方法が他にもまだ2つ存在する。&lt;br /&gt;&lt;br /&gt;それらの内の最初の1つが Git の &lt;span class="jw_in"&gt;reflog&lt;/span&gt; であり、あなたがリポジトリにやった全ての変更を――コミット群の形で――記録するある種のメタリポジトリだ。これは、あなたが &lt;span class="jw_in"&gt;git commit&lt;/span&gt; を使って index から tree を作成しコミットとして保存したとき、そのコミットは reflog へもいつの間にか追加されることを意味する。reflog は以下のコマンドを使って確認することができる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git reflog&lt;br /&gt;&lt;span class="jw_output"&gt;5f1bc85...  HEAD@{0}: commit (initial): Initial commit&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span class="jw_in"&gt;reflog&lt;/span&gt; の美しいところは、リポジトリのその他の変更から独立して維持されているということだ。これは、私が上記のコミットを (&lt;span class="jw_in"&gt;git reset&lt;/span&gt; を使って) リポジトリのどこからもリンクされないようにしても、&lt;span class="jw_in"&gt;reflog&lt;/span&gt; からは30日間はいまだ参照され続け、ガーベジコレクションから守られることを意味する。コミットが本当は必要だったことがわかった場合に、これがあれば一ヶ月間はそれを取り戻すチャンスを与えてくれることになる。&lt;br /&gt;&lt;br /&gt;blob が存在できる他の場所は、間接的ではあるが、ワーキングツリー自身もそうだ。その意味する所は次のとおりだ。あなたが foo.c ファイルを変更したとして、だがまだ index にそれを追加していないとしよう。Git はあなたのために blob を作成しないだろうが、それらの変更は確かに存在し、blob に変換できる内容が存在することを意味する――Git リポジトリの代わりにファイルシステム中に置かれているわけだ。実際の blob が存在しないにも関わらず、ファイル自身は SHA-1 ハッシュ ID も持っている。それをこのコマンドで見ることができる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git hash-object foo.c&lt;br /&gt;&lt;span class="jw_output"&gt;&amp;lt;some hash id&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;この事はあなたのために何をしてくれるだろう？　さて、もしあなたがワーキングツリーにハックをやり込んで、長い一日の終わりに到達したら、身につけるべき良い習慣は、変更をしまい込むことだ：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git stash&lt;/pre&gt;これはあなたのディレクトリの内容の全て――ワーキングツリーと、index の状態の両方を含む――を取り込み、それらのための blob を Git のリポジトリ中に作成する。tree はそれらの blob を保持し、そして stash コミットはワーキングツリーと index と、あなたが &lt;span class="jw_in"&gt;stash&lt;/span&gt; をした時の時刻を記録する。&lt;br /&gt;&lt;br /&gt;これは良いプラクティスだ。なぜなら、次の日にあなたは &lt;span class="jw_in"&gt;git stash apply&lt;/span&gt; を使って stash から変更を戻すことになるが、毎日の終わりにはあなたが stash した全ての変更が reflog に存在するからだ。以下は、次の日の朝に作業をするために戻ってきたあと、あなたがやるはずのことだ (WIP はここでは "Work in progress＝進行中" を表す)：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git stash list&lt;br /&gt;&lt;span class="jw_output"&gt;stash@{0}: WIP on master: 5f1bc85... Initial commit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git reflog show stash &lt;span class="jw_cm"&gt;# 上と同じ出力＋stash コミットのハッシュ ID&lt;/span&gt;&lt;br /&gt;&lt;span class="jw_output"&gt;2add13e...  stash@{0}: WIP on master: 5f1bc85...  Initial commit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git stash apply&lt;br /&gt;&lt;/pre&gt;stash されたワーキングツリーはコミットとして保管されているのだから、他のブランチと似たような扱いができる――いつでも！　これは、&lt;span class="jw_in"&gt;log&lt;/span&gt; を見れたり、いつ stash したかを見れたり、過去に stash した瞬間のどんなワーキングツリーもチェックアウトできることを意味する：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git stash list&lt;br /&gt;&lt;span class="jw_output"&gt;stash@{0}: WIP on master: 73ab4c1...  Initial commit&lt;br /&gt;...&lt;br /&gt;stash@{32}: WIP on master: 5f1bc85...  Initial commit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git log stash@{32} &lt;span class="jw_cm"&gt;# これはいつやった？&lt;/span&gt;&lt;br /&gt;$ git show stash@{32} &lt;span class="jw_cm"&gt;# 私がやっていたことを見せろ&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git checkout -b temp stash@{32} &lt;span class="jw_cm"&gt;# 古いワーキングツリーを見てみよう！&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;この最後のコマンドは特に強力だ。見よ、私は今、一ヶ月以上前のコミットされて&lt;strong&gt;いなかった&lt;/strong&gt;ワーキングツリーをいじっている。私は index にさえそれらのファイルを追加しなかった。私はただ、毎日ログアウトする前に &lt;span class="jw_in"&gt;git stash&lt;/span&gt; を呼び (stash できるようなワーキングツリー内の変更が実際にあったならば、だが)、そして戻ってログインした時に &lt;span class="jw_in"&gt;git stash apply&lt;/span&gt; を使うというシンプルな手段を使っただけだ。&lt;br /&gt;&lt;br /&gt;stash のリストを綺麗にしたいなら――最後の30日間の分だけを維持したいとしたら――&lt;span class="jw_in"&gt;git stash clear&lt;/span&gt; を使わないように。代わりに &lt;span class="jw_in"&gt;git reflog expire&lt;/span&gt; コマンドを使おう：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git stash clear &lt;span class="jw_cm"&gt;# やってはダメ！　全ての履歴を失ってしまう&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git reflog expire --expire=30.days refs/stash&lt;br /&gt;&lt;span class="jw_output"&gt;＜維持されていた分の stash 履歴が出力される＞&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="jw_in"&gt;stash&lt;/span&gt; の美しいところは、あなたの作業プロセス自体に控えめなバージョン管理を適用させてくれるということだ。すなわち、ワーキングツリーに対する時間的な階層を持ったステージングと言えるだろう。もしやりたいなら、以下のスナップショットスクリプトのようなものを使って、定期的に &lt;span class="jw_in"&gt;stash&lt;/span&gt; を実行するようにさえできる：&lt;br /&gt;&lt;pre class="waku_a"&gt;$ cat &amp;lt;&amp;lt;EOF &amp;gt; /usr/local/bin/git-snapshot&lt;br /&gt;#!/bin/sh&lt;br /&gt;git stash &amp;amp;&amp;amp; git stash apply&lt;br /&gt;EOF&lt;br /&gt;$ chmod +x $_&lt;br /&gt;$ git snapshot&lt;br /&gt;&lt;/pre&gt;&lt;span class="jw_in"&gt;git reflog expire&lt;/span&gt; コマンドを毎週か毎月に設定するとともに、cron ジョブを使って毎時間これを走らせない理由は、もはやないだろう。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct7"&gt;7. まとめ&lt;/h2&gt;&lt;br /&gt;　過去数年、私は多くのバージョン管理システム、そして多くのバックアップ機構を使ってきた。それらは全て、過去のファイルの内容を検索する機能を持っていた。それらの大分部は、ファイルが時間が経つに連れてどう変わっていったかを見せてくれる方法を持っていた。多くが、時間を巻き戻すこと、開発ラインを分岐させ、その後そこでやった新しい作業を最新の場所に取り込むこと、などを許してくれた。一部の物は、そのプロセスに対してキメ細かいコントロールを提供し、あなたの作業を修正させてくれ、どのようにでも、あなたがベストと感じる成果物を公開させてくれた。Git はこれらの全てをあなたにさせてくれる。しかもそれらより比較的簡単に――あなたが一旦その基礎を理解したのなら。&lt;br /&gt;&lt;br /&gt;Git はこの種のパワーを持つ唯一のシステムではないし、そのコンセプトのための最高のインターフェースが全体に渡って用いられているわけでもない。そうであるにしても、Git が持っているものは、その上で作業するための確固とした基盤だ。将来、Git が許す柔軟性を利用する多くの新しい方法が考案されると私は想像する。私が使ってきた他のシステムの大部分が、概念的な停滞期へ到達していたと私は思う――他のシステムはこの先、私が以前見てきたような物をゆっくり洗練させていくだけだろう。だが、Git には反対の印象を受ける。その見かけによらずシンプルなデザイン上の誓約がもたらす可能性を、まだまだ見せきれていないと、私は感じる。&lt;br /&gt;&lt;br /&gt;THE END&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="jw_h" id="ct8"&gt;8. 参考文献&lt;/h2&gt;&lt;br /&gt;Git を学ぶ好奇心がそそられたなら、以下の記事をチェックしてみよう：&lt;br /&gt;&lt;br /&gt;• A tour of Git: the basics&lt;br /&gt;&lt;a href="http://cworth.org/hgbook-git/tour/"&gt;http://cworth.org/hgbook-git/tour/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;• Manage source code using Git&lt;br /&gt;&lt;a href="http://www.ibm.com/developerworks/linux/library/l-git/"&gt;http://www.ibm.com/developerworks/linux/library/l-git/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;• A tutorial introduction to git&lt;br /&gt;&lt;a href="http://www.kernel.org/pub/software/scm/git/docs/tutorial.html"&gt;http://www.kernel.org/pub/software/scm/git/docs/tutorial.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;• GitFaq — GitWiki&lt;br /&gt;&lt;a href="http://git.or.cz/gitwiki/GitFaq"&gt;http://git.or.cz/gitwiki/GitFaq&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;• A git core tutorial for developers&lt;br /&gt;&lt;a href="http://www.kernel.org/pub/software/scm/git/docs/gitcore-tutorial.html"&gt;http://www.kernel.org/pub/software/scm/git/docs/gitcore-tutorial.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;• git for the confused&lt;br /&gt;&lt;a href="http://www.gelato.unsw.edu.au/archives/git/0512/13748.html"&gt;http://www.gelato.unsw.edu.au/archives/git/0512/13748.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;• The Thing About Git&lt;br /&gt;&lt;a href="http://tomayko.com/writings/the-thing-about-git"&gt;http://tomayko.com/writings/the-thing-about-git&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="color: #AA0000; font-weight: bold"&gt;Gitに関する翻訳記事はこちらもどうぞ：&lt;br /&gt;&lt;br /&gt;・&lt;a style="color: black; text-decoration: underline; "href="http://keijinsonyaban.blogspot.com/2010/10/successful-git-branching-model.html"&gt;A successful Git branching model を翻訳しました&lt;/a&gt;&lt;br /&gt;・&lt;a style="text-decoration: underline; color: black" href="http://keijinsonyaban.blogspot.com/2010/11/git-tips.html"&gt;【翻訳】あなたの知らないGit Tips&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;h1.jw_h {  font-size: 2.5em;}h2.jw_h {  font-size: 2em;}h3.jw_h {  font-size: 1.7em;}h4.jw_h {  font-size: 1.5em;}.jw_output {  color: #2244FF;}.jw_message {  color: #CC6622;}.jw_in {  background-color: #DDD;  padding: 2px 4px 2px 4px;  font-family: monospace;}.jw_cm {  color: #228b22;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-3874428817606243758?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/3874428817606243758/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/05/git.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/3874428817606243758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/3874428817606243758'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/05/git.html' title='【翻訳】Gitをボトムアップから理解する'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-JV1wRmXO4Jw/TdOfCqbqRbI/AAAAAAAAASw/YTQRDGhbzWE/s72-c/4_ja.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-2531926620102287170</id><published>2011-01-18T20:13:00.003+09:00</published><updated>2011-01-27T08:35:28.171+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><title type='text'>【翻訳】Gitのコミットメッセージに関する注意点</title><content type='html'>Tim Popeさんの "A Note About Git Commit Messages" を翻訳しました。&lt;br /&gt;元記事はこちら： &lt;a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html"&gt;http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html&lt;/a&gt;&lt;br /&gt;（翻訳の公開は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;翻訳の間違い等があればブログコメントやTwitter(&lt;a href="http://twitter.com/oshow"&gt;@oshow&lt;/a&gt;)などで遠慮無くご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #FFFFFF; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 600px; margin: 0 auto 0 auto; padding: 0px 25px 20px 25px; -moz-box-shadow: 0px 0px 10px #000 inset; -webkit-box-shadow: 0px 0px 10px #000 inset; box-shadow: 0px 0px 10px #000 inset; line-height: 1.4em; border: 2px solid black; line-height: 1.5em;"&gt;&lt;h1&gt;Gitのコミットメッセージ&lt;br /&gt;に関する注意点&lt;/h1&gt;&lt;br /&gt;　良い形式のコミットメッセージを書くということについて、時間を取って説こうと思う。私が考えるに、コミットメッセージ形式に関するベストプラクティスは、Git を素晴らしくしてくれる小さなディティールの一つだ。rails.git への最初のコミットのいくつかは、（折り返しのない）長文による多様なコミットメッセージを含んでおり、なぜこれがはっきり言ってお粗末なプラクティスであるかを詳しく述べたいと思う。&lt;br /&gt;&lt;br /&gt;ここにモデルとなるGitのコミットメッセージがある：&lt;br /&gt;&lt;pre class="tim_p"&gt;Short (50 chars or less) summary of changes&lt;br /&gt;&lt;br /&gt;More detailed explanatory text, if necessary.  Wrap it to about 72&lt;br /&gt;characters or so.  In some contexts, the first line is treated as the&lt;br /&gt;subject of an email and the rest of the text as the body.  The blank&lt;br /&gt;line separating the summary from the body is critical (unless you omit&lt;br /&gt;the body entirely); tools like rebase can get confused if you run the&lt;br /&gt;two together.&lt;br /&gt;&lt;br /&gt;Write your commit message in the present tense: "Fix bug" and not "Fixed&lt;br /&gt;bug."  This convention matches up with commit messages generated by&lt;br /&gt;commands like git merge and git revert.&lt;br /&gt;&lt;br /&gt;Further paragraphs come after blank lines.&lt;br /&gt;&lt;br /&gt;- Bullet points are okay, too&lt;br /&gt;&lt;br /&gt;- Typically a hyphen or asterisk is used for the bullet, preceded by a&lt;br /&gt;  single space, with blank lines in between, but conventions vary here&lt;br /&gt;&lt;br /&gt;- Use a hanging indent&lt;br /&gt;&lt;/pre&gt;&lt;pre class="tim_p"&gt;変更に対する短い（50文字以下の）要約&lt;br /&gt;&lt;br /&gt;もし必要なら、より詳しい説明を述べる。約72文字ほどで折り返すようにせよ。&lt;br /&gt;ある文脈では、最初の行はE-Mailの件名になり、残りのテキストが本文になる。&lt;br /&gt;空行で本文と要約を分離するのは絶対に必要だ（本文を省略していない限り）。&lt;br /&gt;もしも二つを繋げてしまうと、rebaseのようなツールが混乱する可能性がある。&lt;br /&gt;&lt;br /&gt;現在時制でコミットメッセージを書くこと。"Fixed bug"ではなく"Fix bug"だ。&lt;br /&gt;この慣習は git merge や git revert のようなコマンドが生成したコミット&lt;br /&gt;メッセージと調和する。&lt;br /&gt;&lt;br /&gt;さらなる段落があれば空行の後に続けられる。&lt;br /&gt;&lt;br /&gt;- 箇条書きも問題ない&lt;br /&gt;&lt;br /&gt;- 箇条書きにはハイフンかアスタリスクが使われ、一つスペースを空けてから&lt;br /&gt;  書き始め、合間には空行が入るのが通常だが、この部分の慣習は多種多様だ&lt;br /&gt;&lt;br /&gt;- ぶら下げインデント(一行目だけ飛び出して後はインデントする)を使うこと&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　コミットメッセージを72文字で折り返すのがなぜ良い事なのかという理由の説明から始めよう。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;git log&lt;/span&gt; はコミットメッセージに対して、なんらの折り返しもしてくれない。デフォルトのページャである &lt;span class="tim_mono"&gt;less -S&lt;/span&gt; では、これは文章が画面外に飛び出してしまうことを意味し、読み辛くなってしまう。横幅80文字のターミナルでは左側のインデントのために4文字引き、右側も釣り合うよう4文字引くなら、残されたのは72文字だ。&lt;/li&gt;&lt;div style="color: #333; margin-left: 40px; margin-top: 10px"&gt;&lt;b&gt;訳注&lt;/b&gt;： ちなみに、 &lt;pre class="tim_p"&gt;$ git config --global core.pager 'less -R'&lt;/pre&gt;とすれば長くても折り返すようになります。もしダメなら以下で。 &lt;pre class="tim_p"&gt;$ git config --global core.pager 'LESS=-R less'&lt;/pre&gt;&lt;/div&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;git format-patch --stdout&lt;/span&gt; は一連のコミットをe-mailに変換し、メール本文にコミットメッセージを使用する。良いe-mailネチケットは、横幅80文字のターミナルにおいても溢れないよう、引用表示が何回かネストした時のための余裕を持たせるようにプレーンテキストのe-mailの折り返しを規定している（現在の rails.git のワークフローはe-mailではなく、未来的な何かを組み込んでいるのだろうが）。&lt;/li&gt;&lt;/ul&gt;Vim ユーザは私の &lt;a class="tim_a" href="https://github.com/tpope/vim-git"&gt;vim-git プラグイン&lt;/a&gt;をインストールするか、単にGitのコミットメッセージファイルに対して以下のオプションを設定することで、この要件を満たすことができる。&lt;br /&gt;&lt;pre class="tim_p"&gt;:set textwidth=72&lt;/pre&gt;Textmate では、view メニュー下の "Wrap Column" オプションを調節し、^Q を使って文章の折り返しを再適用できる(その後必ず、コメントが混ざるのを避けるために、空行があるか確認すること)。メニューに72文字折り返しを追加するシェルコマンドを以下に用意したので、選択するために何度もドラッグする必要はない。&lt;br /&gt;&lt;pre class="tim_p"&gt;$ defaults write com.macromates.textmate OakWrapColumns '( 40, 72, 78 )'&lt;/pre&gt;&lt;br /&gt;　本文の形式を整える方法よりも重要なのが、主題の行をつけるプラクティスだ。例で示したように、あなたは約50文字（これは厳しい限度ではない）を目指すべきだし、とにかく、常にその下に空行を作るべきだ。この最初の行は、そのコミットによって導入された変更への簡潔な要約でなければならない。このような厳しい文字数制限では表現できない技術的な詳細があるならば、代わりに本文の方へ書く。要約の行は Git 全体で使われ、もし長すぎるメッセージだったら端折られてしまうことがしばしばだ。以下はそういった物のうち少数の例を挙げている：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;git log --pretty=oneline&lt;/span&gt; はコミットのハッシュIDと要約を含んだ簡単な履歴を表示する。&lt;/li&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;git rebase --interactive&lt;/span&gt; はそれが呼び出すエディタ内で各コミットの要約を提供する。&lt;/li&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;merge.summary&lt;/span&gt; オプションが設定されていれば、マージされる全てのコミットの要約が、マージコミットのコミットメッセージ内へ格納される。&lt;/li&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;git shortlog&lt;/span&gt; は ChangeLog 的な出力を生成し、その中で要約を使用する。&lt;/li&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;git format-patch&lt;/span&gt;、&lt;span class="tim_mono"&gt;git send-email&lt;/span&gt; そして関連するツールは、e-mailの件名として要約を利用する。&lt;/li&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;git reflog&lt;/span&gt; によってアクセスできる reflog というローカルな履歴は、馬鹿な間違いからあなたを救ってくれる。そこでは要約の写しが使われる。&lt;/li&gt;&lt;li&gt;&lt;span class="tim_mono"&gt;gitk&lt;/span&gt; は要約のためのカラムを持つ。&lt;/li&gt;&lt;li&gt;GitHub はそのインターフェース内の様々な場所で要約を利用する。&lt;/li&gt;&lt;/ul&gt;主題／本文という区別は重要ではないように見えるかもしれないが、それが Git の履歴を Subversion より遥かに快適にしてくれる多くの繊細な要素の一つだ。&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;style type="text/css"&gt;pre.tim_p {  line-height: 1.2em;  padding: 15px;  -moz-box-shadow: 0px 0px 10px #000 inset;  -webkit-box-shadow: 0px 0px 10px #000 inset;  box-shadow: 0px 0px 10px #000 inset;}.tim_mono {  font-family: monospace;}a:link.tim_a {  color: #444;  text-decoration: underline;}a:visited.tim_a {  color: #444;  text-decoration: underline;}a:hover.tim_a {  color: #444;  text-decoration: underline;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-2531926620102287170?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/2531926620102287170/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/01/git.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/2531926620102287170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/2531926620102287170'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/01/git.html' title='【翻訳】Gitのコミットメッセージに関する注意点'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-4811952252855132301</id><published>2011-01-06T03:43:00.000+09:00</published><updated>2011-01-06T03:43:56.288+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Go'/><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><title type='text'>【翻訳】アクターによる並列性、そしてRubyでGoroutine</title><content type='html'>Ilya Grigorikさんの "Concurrency with Actors, Goroutines &amp; Ruby" を翻訳しました。&lt;br /&gt;元記事はこちら： &lt;a href="http://www.igvita.com/2010/12/02/concurrency-with-actors-goroutines-ruby/"&gt;http://www.igvita.com/2010/12/02/concurrency-with-actors-goroutines-ruby/&lt;/a&gt;&lt;br /&gt;（翻訳の公開と画像の利用は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;翻訳の間違い等があればブログコメントやTwitter(&lt;a href="http://twitter.com/oshow"&gt;@oshow&lt;/a&gt;)などで遠慮無くご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #FFFFFF; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 600px; margin: 0 auto 0 auto; padding: 0px 25px 20px 25px; -moz-box-shadow: 1px 1px 3px #000; -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000; line-height: 1.4em; border: 2px solid black; line-height: 1.5em;"&gt;&lt;h1 class="ig_h"&gt;アクターによる並列性、&lt;br /&gt;そしてRubyでGoroutine&lt;/h1&gt;&lt;br /&gt;&lt;img style="float: left; margin-right: 5px" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TSS4ka7b1BI/AAAAAAAAARQ/uowEa1E6lOg/s135/ruby-go.png" alt="ruby-go" width="118" height="135" /&gt;　並列コンピューティングの世界は複雑なものだ。私たちは&lt;a class="ig_a" href="http://www.igvita.com/2010/08/18/multi-core-threads-message-passing/"&gt;ハードウェア&lt;/a&gt;、&lt;a class="ig_a" href="http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/"&gt;ランタイム&lt;/a&gt;、そして半ダースもの異なるモデルとプリミティブから選択することを考えなければならない： fork / wait、スレッド、シェアードメモリ、メッセージパッシング、セマフォ、そしてトランザクションなど。ゆえに、Bruce Tate が彼の最近の本（&lt;a class="ig_a" href="http://pragprog.com/titles/btlang/seven-languages-in-seven-weeks"&gt;Seven Languages in Seven Weeks&lt;/a&gt;）でのインタビューで Matz に、もし過去に戻れるならば Ruby にどんな機能変更を行いたいかと聞いた時、その答えに説得力があったのは驚くべきことではない：　&lt;b&gt;「私はスレッドを取り除いて、アクターなどのより先進的な並列機構を追加するだろう。」&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="ig_h"&gt;プロセス計算と先進的並列性&lt;/h2&gt;&lt;br /&gt;　Matz の言明から多くを読み取るのは簡単だが、追求すべき疑問はこうだ：&lt;b&gt;より先進的な並列機構とは？&lt;/b&gt;　毎年何千人ものプログラマがスレッド、ミューテックス、セマフォについて教えられてから学校を卒業していく――それらは私たちがどう並列を行うかというものだ！　「先進的な並列機構」というトピックに関して私たち皆が逃している重要な講義があるのか？&lt;br /&gt;&lt;br /&gt;答えはたぶん違って、シェアードメモリモデルの「成功」によるところが大きい。プロセス計算(&lt;a class="ig_a" href="http://en.wikipedia.org/wiki/Process_calculi"&gt;Process calculi&lt;/a&gt;)は並列システムの振る舞いをモデリングするアプローチに関係する多くの研究のための正式名称で、多くの代替物を提供している： わずかな例をあげると、&lt;a class="ig_a" href="http://en.wikipedia.org/wiki/Calculus_of_Communicating_Systems"&gt;CCS&lt;/a&gt;、&lt;a class="ig_a" href="http://ja.wikipedia.org/wiki/Communicating_Sequential_Processes"&gt;CSP&lt;/a&gt;、&lt;a class="ig_a" href="http://en.wikipedia.org/wiki/Algebra_of_Communicating_Processes"&gt;ACP&lt;/a&gt;、そして&lt;a class="ig_a" href="http://ja.wikipedia.org/wiki/アクターモデル"&gt;アクターモデル&lt;/a&gt;だ。しかしながら、そんなわずかな頭文字言葉たちしか私たちの辞書に届いていなかった。それらのほとんどのルーツは1970年代前半に遡るのだから驚きだ――まったく新しいものではないのだが、最近まで滅多に言及されなかった。&lt;br /&gt;&lt;br /&gt;&lt;h2 class="ig_h"&gt;アクター、CSP、そしてπ計算&lt;/h2&gt;&lt;br /&gt;&lt;img style="float: left; margin-right: 5px" src="http://1.bp.blogspot.com/_KJLBBSxY7xs/TSS4j9PfdzI/AAAAAAAAAQ4/Ij7AZ3-ppjo/s190/erlang-scala-go.png" alt="erlang-scala-go" width="100" height="190" /&gt;　現在 &lt;a class="ig_a" href="http://ja.wikipedia.org/wiki/Erlang"&gt;Erlang&lt;/a&gt; や &lt;a class="ig_a" href="http://ja.wikipedia.org/wiki/Scala"&gt;Scala&lt;/a&gt; といった言語の最近の成功に牽引されている&lt;a class="ig_a" href="http://ja.wikipedia.org/wiki/アクターモデル"&gt;アクター並列モデル&lt;/a&gt;は、探索する価値のある「代替となる並列モデル」の良い例だ。しかし、これしかないというわけではない。&lt;br&gt;&lt;a class="ig_a" href="http://golang.org/"&gt;Google の Go 言語&lt;/a&gt;もまた関連する、しかしとても異なるモデルを持ち込んだ： &lt;a class="ig_a" href="http://ja.wikipedia.org/wiki/Communicating_Sequential_Processes"&gt;トニー・ホーアのCSP&lt;/a&gt; と&lt;a class="ig_a" href="http://en.wikipedia.org/wiki/Pi_calculus"&gt;π計算&lt;/a&gt;のミックスだ。表面上では、上記の言語群に採用されたモデルはお互いに非常に異なったものだが、しかし全ては共通の中核原則に基づいている：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;「状態を共有することによってコミュニケーションするな。 &lt;br /&gt;　コミュニケーションによって状態を共有するようにせよ」&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;少しの間、沈思してみよう。データ構造をロックによって守りそのロックを奪い合う代わりに、このモデルは&lt;b&gt;明示的にプロセスからプロセスへ状態を渡すこと&lt;/b&gt;を&lt;a class="ig_a" href="http://blog.golang.org/2010/07/share-memory-by-communicating.html"&gt;推奨する&lt;/a&gt;。これは、ある時点ではただ一つだけのプロセスがデータにアクセスできることを保証し、そして即座に並列性問題の全体を解決する。&lt;br /&gt;&lt;br /&gt;&lt;h2 class="ig_h"&gt;アクター、Goroutine、Channnel と Ruby&lt;/h2&gt;&lt;br /&gt;　それで、類似性はわかったが、Erlang と Go のような言語の間の実際の違いは何なんだろう？　構文やVM実装の詳細はさておき、Erlang では 各プロセスに独自に与えられた名前を使ってコミュニケーションをとる――&lt;a class="ig_a" href="http://en.wikipedia.org/wiki/Erlang_(programming_language)#Concurrency_and_distribution_orientation"&gt;&lt;span class="ig_i"&gt;mailbox&lt;/span&gt;&lt;/a&gt; という考え方だ。対照的に Go では、全てのプロセスは無名であり、その代わりに "communication channel" を指定する――&lt;a class="ig_a" href="http://publib.boulder.ibm.com/infocenter/soliddb/v6r3/index.jsp?topic=/com.ibm.swg.im.soliddb.admin.doc/doc/unix.pipes.html"&gt;&lt;span class="ig_i"&gt;Unixのパイプ&lt;/span&gt;&lt;/a&gt;の考え方だ。微妙な違いだが、これらが非常に異なるプログラミングモデルと能力をもたらす。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img src="http://2.bp.blogspot.com/_KJLBBSxY7xs/TSS4kAcDrlI/AAAAAAAAARA/ZinMeDRak2I/s500/erlang-vs-go.png" alt="erlang-vs-go" width="500" height="63" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;理論的なことはわきにどけて、Go の並列モデルを注意深く見てみよう。&lt;a class="ig_a" href="http://golang.org/doc/install.html"&gt;Go runtime&lt;/a&gt; をインストールするかもしくは、実は Ruby ランタイム上で直接そのモデルのほとんどをエミュレートすることもできる（&lt;b class="ig_i"&gt;gem install agent&lt;/b&gt;）。：&lt;br /&gt;&lt;pre class="ig_code"&gt;c = &lt;span style="color: #66F; font-weight: bold"&gt;Agent::Channel&lt;/span&gt;.&lt;span style="color: #90C"&gt;new&lt;/span&gt;&lt;span style="color: #060"&gt;(&lt;/span&gt;name: &lt;span style="color: #960"&gt;'incr'&lt;/span&gt;, type: &lt;span style="color: #C06; font-weight: bold"&gt;Integer&lt;/span&gt;&lt;span style="color: #060"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;go&lt;span style="color: #060"&gt;(&lt;/span&gt;c&lt;span style="color: #060"&gt;)&lt;/span&gt; &lt;span style="color: #96C; font-weight: bold"&gt;do&lt;/span&gt; |c, i=&lt;span style="color: #066"&gt;0&lt;/span&gt;|&lt;br /&gt;  &lt;span style="color: #C06; font-weight: bold"&gt;loop&lt;/span&gt; &lt;span style="color: #060"&gt;{&lt;/span&gt; c &amp;lt;&amp;lt; i+= &lt;span style="color: #066"&gt;1&lt;/span&gt; &lt;span style="color: #060"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #96C; font-weight: bold"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color: #C06; font-weight: bold"&gt;p&lt;/span&gt; c.&lt;span style="color: #90C"&gt;receive&lt;/span&gt; &lt;span style="color: green"&gt;# =&amp;gt; 1&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #C06; font-weight: bold"&gt;p&lt;/span&gt; c.&lt;span style="color: #90C"&gt;receive&lt;/span&gt; &lt;span style="color: green"&gt;# =&amp;gt; 2&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="ig_github"&gt;&lt;a style="border: none" class="ig_a" href="http://www.igvita.com/download.php?file=http://www.github.com/igrigorik/agent/tree/master/.git"&gt;&lt;img style="float: left; margin: 5px 15px 0 5px; padding-top 4px;" src="http://2.bp.blogspot.com/_KJLBBSxY7xs/TSS4kR7-09I/AAAAAAAAARI/BfMjwuvHUS8/s30/github.png" alt="github" width="30" height="30" /&gt;&lt;/a&gt;&lt;span style="padding: 10px 0 0 5px; font-weight: bold;"&gt;&lt;a class="ig_a" href="http://www.igvita.com/download.php?file=http://www.github.com/igrigorik/agent/tree/master/.git"&gt;Agent (Go-like concurrency, in Ruby)&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Downloads: 275 File Size: 0.0 KB&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;シンプルなジェネレータの例だが、多くの異なる機能をハイライトさせるものでもある。まず最初に、プロセス間でコミュニケーションを取るための名前（'incr'）のついた型付き channel を作成する。それから少し面白いことに &lt;b class="ig_i"&gt;"go"&lt;/b&gt; という、channel を一つと Ruby のコードブロックを取る関数を呼ぶ。&lt;br /&gt;&lt;br /&gt;裏側では、&lt;b class="ig_i"&gt;"go"&lt;/b&gt; 関数は実際にはコードブロック（ここでは loop 命令）を実行するための&lt;a class="ig_a" href="https://github.com/igrigorik/agent/blob/master/lib/agent.rb#L8"&gt;新しいスレッドを作成&lt;/a&gt;し、元の channel で receive を呼ぶためにすぐさま復帰する。その channel は、今度は、producer が値を生成するまで receive 呼び出しをブロックする！　言い換えれば、マルチスレッドな producer-consumer を、シングルスレッドまたは mutex が見えないように書いたってことになる！　また、よりおもしろい&lt;a class="ig_a" href="https://github.com/igrigorik/agent/blob/master/examples/agent-workers.rb"&gt;マルチワーカーの例&lt;/a&gt;、&lt;a class="ig_a" href="https://github.com/igrigorik/agent/blob/master/spec/examples/sieve_spec.rb#L7"&gt;エラトステネスのふるい&lt;/a&gt;、そして MRI と JRuby の間の&lt;a class="ig_a" href="https://github.com/igrigorik/agent/blob/master/benchmark/sieve.rb#L71"&gt;非科学的な小競り合いの結果&lt;/a&gt;を見よ。&lt;br /&gt;&lt;br /&gt;&lt;h2 class="ig_h"&gt;"先進的な並列性" の受け入れ&lt;/h2&gt;&lt;br /&gt;　シェアードメモリ、スレッドそしてロックには&lt;a class="ig_a" href="http://www.igvita.com/2010/08/18/multi-core-threads-message-passing/"&gt;それらを使う場所と目的&lt;/a&gt;がある。実際、上で紹介した Agent の裏側か、"代替となる並列モデル" を持つランタイムのソースコードの中を見てみれば、間違いなくそれらが使われているのが見つかるだろう。だから、&lt;b&gt;スレッドの存在が必要かどうかは疑問点ではなくむしろ、重要なのはランタイムに関わらず、並列性を必要とするコードを書き、テストし、管理するベストで高水準なインターフェースが実際になされているか、だ。&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;アクターや CSP/π計算モデルは最初は複雑に見えるが、ほとんどはそれに馴染みないせいだ。実際、一度いくつか例を経験してみれば、それらは著しくシンプルで、パワフルで、そしてどんなランタイムの中でも再現できる。Erlang を始めるか、Go を試してみるか、あるいは Ruby でアイデアをプロトタイピングするために &lt;a class="ig_a" href="https://github.com/igrigorik/agent"&gt;Agent をインストール&lt;/a&gt;するかすれば、あなたは時間を有益に過ごせるだろう。&lt;br /&gt;&lt;style type="text/css"&gt;h1.ig_h {  border-bottom: 2px solid #80C9FF;}h2.ig_h {  border-bottom: 1px solid #80C9FF;}.ig_i {  font-style: italic;}pre.ig_code {  border-top: 1px dotted #333;  border-bottom: 1px dotted #333;  padding: 1em 0;  font-size: 1.1em;  line-height: 1.2em;}.ig_github {  background: #F6F6F6;  border: 1px solid #CCC;  margin: 0 0 5px 0;  padding-top: 8px;  padding-bottom: 5px;  padding-left: 15px;  height: 50px;}a:link.ig_a {  color: #000;  text-decoration: underline;}a:visited.ig_a {  color: #000;  text-decoration: underline;}a:hover.ig_a {  color: #999;  text-decoration: underline;}&lt;/style&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-4811952252855132301?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/4811952252855132301/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/01/rubygoroutine.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/4811952252855132301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/4811952252855132301'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/01/rubygoroutine.html' title='【翻訳】アクターによる並列性、そしてRubyでGoroutine'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_KJLBBSxY7xs/TSS4ka7b1BI/AAAAAAAAARQ/uowEa1E6lOg/s72-c/ruby-go.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-9060798515156398064</id><published>2011-01-02T23:31:00.002+09:00</published><updated>2011-01-03T05:50:34.542+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><category scheme='http://www.blogger.com/atom/ns#' term='Mercurial'/><title type='text'>【翻訳】Rebaseは安全である</title><content type='html'>Gary Bernhardtさんの "Rebase Is Safe" を翻訳しました。&lt;br /&gt;元記事はこちら： &lt;a href="http://blog.extracheese.org/2010/12/rebase-is-safe.html"&gt;http://blog.extracheese.org/2010/12/rebase-is-safe.html&lt;/a&gt;&lt;br /&gt;（翻訳の公開は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;翻訳の間違い等があればブログコメントやTwitter(&lt;a href="http://twitter.com/oshow"&gt;@oshow&lt;/a&gt;)などで遠慮無くご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #FFFFFF; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 600px; margin: 0 auto 0 auto; padding: 5px 25px 20px 25px; -moz-box-shadow: 1px 1px 3px #000; -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000; line-height: 1.4em; border: 2px solid #000;"&gt;&lt;h1&gt;Rebaseは安全である&lt;/h1&gt;&lt;br /&gt;　なにやら Git についての嘘がまかり通っているらしい： &lt;span class="gary_in"&gt;git rebase&lt;/span&gt; は安全ではない、という。push 済みの変更をあなたが rebase してしまい、皆がタチの悪いマージ大惨事に陥ってしまうという類の危険のことでは「ない」。そんなものは本当の、よく知られた危険であり、そんなことしちゃいけないってのは皆受け入れているはずだ。&lt;br /&gt;&lt;br /&gt;私が言っている嘘というのは &lt;span class="gary_in"&gt;git rebase&lt;/span&gt; はそもそもあなたの履歴を不安定にするものであり、コンパイルできないまたはテストをパスしない変更を混入するから、これは深刻な問題だ、というものだ。主な症状としては &lt;span class="gary_in"&gt;git bisect&lt;/span&gt; が中断する。テストが壊れているリビジョンが存在する場合、慎重にやるなら bisect はそれをスキップするが、そうでないなら、本来突き止めるべきではないものを bisect が見つけてしまう（false positive）ことになる。 &lt;br /&gt;&lt;br /&gt;確かにそれは悪く聞こえる。しかし問題が、新しく rebase されたコミットがテストをパスするかわからないということならば、なぜテストを走らせないのか？&lt;br /&gt;&lt;br /&gt;この例のように。：&lt;br /&gt;&lt;pre class="gary_box"&gt;(set -e;&lt;br /&gt;  git rev-list --reverse origin/master..master |&lt;br /&gt;    while read rev; do&lt;br /&gt;      echo "Checking out: $(git log --oneline -1 $rev)";&lt;br /&gt;      git checkout -q $rev;&lt;br /&gt;      python runtests.py;&lt;br /&gt;    done)&lt;br /&gt;&lt;/pre&gt;これは難しいことじゃない――シェルによるただの while ループだ。origin/master から master の間の全リビジョンをチェックアウトし、それぞれのリビジョンでテストを走らせる。&lt;a class="gary_a" href="https://github.com/garybernhardt/expecter"&gt;Expector Gadget&lt;/a&gt;（訳注：著者の自作テストツール）の2つのリビジョンでそれを走らせたら、こう出力される：&lt;br /&gt;&lt;pre class="gary_box"&gt;Checking out: 4f56581 Split tests into many files&lt;br /&gt;....................&lt;br /&gt;-------------------------------------------------&lt;br /&gt;Ran 20 tests in 0.019s&lt;br /&gt;&lt;br /&gt;OK&lt;br /&gt;Checking out: 44de2c2 pyflakes&lt;br /&gt;....................&lt;br /&gt;-------------------------------------------------&lt;br /&gt;Ran 20 tests in 0.019s&lt;br /&gt;&lt;br /&gt;OK&lt;br /&gt;&lt;/pre&gt;これはたった1.1秒しかかかってない。もし遅かったら、それはあなたのユニットテストが遅いからだ（Git のせいではない）。無論テストの遅さは bisect や継続的インテグレーション、開発フロー内の繰り返し作業、その他多くのものを遅くする。そこでは、rebase はボトルネックではない。&lt;br /&gt;&lt;br /&gt;このコマンドはテストが失敗した時点で停止する――最初に &lt;span class="gary_in"&gt;set -e&lt;/span&gt; をしているためだ。だから、もしどれかのリビジョンがテストをパスしなかったら、あなたはそのテストの出力結果を見せられ、コマンドは停止し、そしてチェックアウトされたリビジョンがあなたの前に残される。あなたはおそらく &lt;span class="gary_in"&gt;git checkout master&lt;/span&gt; して、そのリビジョンを修正するために対話的リベースをしたいはずだ。私の場合、こういうことは実際には滅多に起こらない。rebase は変更なしでほとんどいつも働いているが、リポジトリ履歴を壊したくないならば、チェックはいまだ重要だ。&lt;br /&gt;&lt;br /&gt;あなたは、チェックアウトがワーキングコピーを粉砕するか、さもなくばカオスな状況を引き起こすのではないかと心配するかもしれない。もう一度言うと &lt;span class="gary_in"&gt;set -e&lt;/span&gt; が我々を守ってくれる。もしワーキングコピーが汚かったら最初の &lt;span class="gary_in"&gt;git checkout&lt;/span&gt; が失敗し、サブシェルは終了するだろう：&lt;br /&gt;&lt;pre class="gary_box"&gt;Checking out: 4f56581 Split tests into many files&lt;br /&gt;error: You have local changes [...]; cannot switch branches.&lt;br /&gt;&lt;/pre&gt;私はこのシェルコマンドを複数のプロジェクト、私一人のものと6人程度の小さなチームの両方で採用して大成功を収めた。これは元々 Mercurial の patch queue の中の全てのリビジョンに対してテストを走らせる、似たコマンドから来ている。patch queue は コミットを rebase する Mercurial における方法であり、Mercurial ユーザは本記事を Git 固有の問題だと思わないように。&lt;br /&gt;&lt;br /&gt;過去に、私はコマンドをスクリプトに落としこむことさえ面倒臭がっていた。私には zsh の巨大なヒストリサイズ（100,000コマンド）があり、"rev-list" を履歴検索をするためにただ ^R を打つだけでよかった。でも今は私の dotfiles リポジトリにコマンドを&lt;a class="gary_a" href="https://github.com/garybernhardt/dotfiles/blob/master/bin/run-command-on-git-revisions"&gt;スクリプト化した&lt;/a&gt;ところなので、あなたも自身のプロジェクトで簡単にこれを使うことができる。&lt;br /&gt;&lt;br /&gt;本記事の教訓は、あなたはツールに深く携わる必要があるということだ： Git を理解し、そしてまた Unix を理解せよ。それらをよく使うことを学び（例えば Unix では、私のスクリーンキャストの "&lt;a class="gary_a" href="http://blog.extracheese.org/2010/06/screencast-python-to-shell-to-ruby.html"&gt;Python to Shell to Ruby&lt;/a&gt;" や "&lt;a class="gary_a" href="http://blog.extracheese.org/2010/04/a-raw-view-into-my-unix-hackery.html"&gt;A Raw View into My Unix Hackery&lt;/a&gt;" を見よ）、両方共の根本的なモデルを学び（例えばUnixでは、"&lt;a class="gary_a" href="http://blog.extracheese.org/2010/05/the-tar-pipe.html"&gt;The Tar Pipe&lt;/a&gt;" を見よ）、そしてそれらを一緒に使う方法を特に学ぼう。どちらかだけを学ぶとか、両方を中途半端にするとかして、問題が起こったときにそれらのツールに文句を言うのはやめよう。プログラムを書くのは難しい、だからって色んなものをとっ替えひっ替えするのはイクナイ。&lt;br /&gt;&lt;br /&gt;（もしこの記事が楽しめたなら、"&lt;a class="gary_a" href="http://blog.extracheese.org/2010/05/why-i-switched-to-git-from-mercurial.html"&gt;Why I Switched to Git From Mercurial&lt;/a&gt;" もいいかもしれない。）&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;body {  background-color: #FFFFFF;}pre.gary_box {  padding: 6px 0 6px 24px;  margin-bottom: 24px;  background-color: #DDD;  border-top: 6px solid #888;  border-bottom: 6px solid #888;}.gary_in {  background-color: #DDD;  padding: 2px 4px 2px 4px;  font-family: monospace;}a:link.gary_a {  color: #001B70;  text-decoration: underline;}a:visited.gary_a {  color: #001B70;  text-decoration: underline;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-9060798515156398064?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/9060798515156398064/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/01/rebase.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/9060798515156398064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/9060798515156398064'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2011/01/rebase.html' title='【翻訳】Rebaseは安全である'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-4210356207095075624</id><published>2010-12-31T09:06:00.004+09:00</published><updated>2011-01-03T05:50:11.174+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='EventMachine'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>【翻訳】EventMachine入門</title><content type='html'>dan sinclairさんのEventMachineの入門記事（PDF）を翻訳しました。&lt;br /&gt;原文はここからダウンロード可能です： &lt;a href="http://everburning.com/news/eventmachine-introductions/"&gt;http://everburning.com/news/eventmachine-introductions/&lt;/a&gt;&lt;br /&gt;（翻訳の公開と画像の利用は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;翻訳・内容の間違い等があればブログコメントや&lt;a href="http://twitter.com/oshow"&gt;Twitter&lt;/a&gt;などで遠慮無くご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #FFFFFF; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 750px; margin: 0 auto 0 auto; padding: 5px 25px 20px 25px; -moz-box-shadow: 2px 2px 3px #000; -webkit-box-shadow: 2px 2px 3px #000; box-shadow: 2px 2px 3px #000; line-height: 1.4em; border: 2px solid #000;"&gt;&lt;h1 class="dan_h"&gt;EventMachine入門&lt;/h1&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="dan_h"&gt;Introduction&lt;/h2&gt;&lt;br /&gt;　うん、これから何を学ぶことになるのか、この導入のくだりがスタート地点として役に立つと思う。EventMachine とは何だろう。そしてそれは私たちのために何をしてくれるのだろう。さて、最初の部分は簡単だね。EventMachine は Reactor パターン(&lt;a name="fm20101231-01-01" href="#f20101231-01-01" title="http://en.wikipedia.org/wiki/Reactor_pattern"&gt;*1&lt;/a&gt;)の高性能な実装さ。&lt;br /&gt;&lt;br /&gt;すげえ、いや、ちょっと待て、Reactor パターンって何だ？　Wikipedia によると：&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;div class="dan_bluebox"&gt;Reactor デザインパターンとは、一つ以上の入力による、サービスハンドラへ送られた同時並行なリクエストを扱うための並列プログラミングパターンです。サービスハンドラは入ってくるリクエスト群をより分け、関連するリクエストハンドラに同期的に送りつけます。&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;基本的に、EventMachine(EM) はソケットの受信待機、ネットワーク接続の確立、タイマー処理、そしていくつかの並列プリミティブを含んだ低レベルなもの全てを扱う。EM は高性能なAPIサーバ／サービスを作るのに必要な多くの中核機能を提供する。また EventMachine は Dan Kegel 他による C10K 問題(&lt;a name="fm20101231-01-02" href="#f20101231-01-02" title="http://www.kegel.com/c10k.html"&gt;*2&lt;/a&gt;)の教訓を考慮に入れている。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img border="0" height="507" width="528" src="http://4.bp.blogspot.com/_KJLBBSxY7xs/TR0IZFFsO8I/AAAAAAAAAPg/NtQVfPz-gyY/s528/3.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;ネットワーク処理能力と共に、EM は長時間かかるタスクをバックグラウンドなスレッドに回すことができるスレッドプールを提供する。これはアプリケーションを素早い・応答性の良いものにしてくれる。みんな応答性は好きだよね？　もちろんスレッドプールを使うことに関してはトレードオフがあって、ほとんどは Ruby1.8 のグリーンスレッド（OS ではなく VM がスケジュールするスレッド）の実装に関係するんだ。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;（&lt;b&gt;訳注&lt;/b&gt;： Ruby1.9ではネイティブスレッドになりましたが、Global Interpreter Lock により完全に並列実行されるわけではありません。ただしグリーンスレッドよりもスレッド切り替えコストは軽減されています）&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;最初に、簡単な例を見てみようか。EM におけるHello World、エコーサーバを例として使ってみよう。&lt;br /&gt;&lt;span class="dan_green"&gt;緑色&lt;/span&gt;のテキストはサーバからの応答だから注意してね。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;class Echo &amp;lt; EM::Connection&lt;br /&gt;  def receive_data(data)&lt;br /&gt;    send_data(data)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.start_server("0.0.0.0", 10000, Echo)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;Rei:~ dj2$ telnet localhost 10000&lt;br /&gt;Trying 127.0.0.1...&lt;br /&gt;Connected to localhost.&lt;br /&gt;Escape character is '^]'.&lt;br /&gt;helo&lt;br /&gt;&lt;span class="dan_green"&gt;helo&lt;/span&gt;&lt;br /&gt;goodbye cruel world&lt;br /&gt;&lt;span class="dan_green"&gt;goodbye cruel world&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;詳細は後に見ていくけど大雑把に言うと、ポート10000番上で開始されたサーバは接続を確立したときに、用意しておいた &lt;span class="dan_i"&gt;Echo&lt;/span&gt; クラスを使っている。ポートにデータが届いた時、EM は &lt;span class="dan_i"&gt;receive_data&lt;/span&gt; メソッドを実行し、&lt;span class="dan_i"&gt;send_data&lt;/span&gt; を呼ぶことによって、受け取ったデータをクライアントにエコーし返す。&lt;br /&gt;&lt;br /&gt;本質的には、&lt;span class="dan_i"&gt;Echo&lt;/span&gt; クラスのインスタンスはファイルディスクリプタに結びつけられている。ファイルディスクリプタに動きがあればいつでも、君のクラスのインスタンスはそのアクションをハンドルするために呼ばれるのだ。これがほとんどの EventMachine プログラミングの基礎であり、reactor はファイルディスクリプタを監視し、君のクラスのインスタンスにあるコールバックを実行する。&lt;br /&gt;&lt;br /&gt;注目すべき興味深いことは、我々の &lt;span class="dan_i"&gt;Echo&lt;/span&gt; クラスにはどんなネットワーク原理の概念もないってことだ。実装した &lt;span class="dan_i"&gt;Echo#receive_data&lt;/span&gt; にはパケットやヘッダの概念はないけれど、ネットワークのデータを取り出すことができる。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="dan_h"&gt;Getting Started&lt;/h2&gt;&lt;br /&gt;　導入はやりのけたので、EventMachine の楽園へのユカイな道のりを始められる。君が邁進するのに使えるいくつかの基本的タスクとコマンドがあるから、そこを原点として始めようか。&lt;br /&gt;&lt;br /&gt;最初に、最も簡単で最もばかげた EM アプリケーションを作ってみよう。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require '&lt;span class="dan_blue"&gt;eventmachine&lt;/span&gt;'&lt;br /&gt;&lt;br /&gt;EventMachine::&lt;span class="dan_blue"&gt;run&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;ちっとも刺激的じゃない例だが、良い出発点だ。注意が2、3ある。まず最初に、EventMachine を利用するには、&lt;span class="dan_i"&gt;eventmachine&lt;/span&gt; を require しなくちゃならない。2番目に、抜け目ない人ならお気づきだろうが、最初の例では &lt;span class="dan_i"&gt;EM.&lt;/span&gt; を使っていたが今回は &lt;span class="dan_i"&gt;EventMachine::&lt;/span&gt; を使った。これは &lt;span class="dan_i"&gt;EM::&lt;/span&gt; でも &lt;span class="dan_i"&gt;EventMachine.&lt;/span&gt; でもいい。どれも同等の書き方だ。個人的には &lt;span class="dan_i"&gt;EM.&lt;/span&gt; が短くて簡潔なので好きだ。最後に、もしこの例を実行させたなら、決して終了しなかったことに気づくだろう。&lt;span class="dan_i"&gt;EM#run&lt;/span&gt; を呼ぶと、EventMachine reactor は開始され、止まれと言われるまではハッピーに走り続ける。そして実際に今は止まれと言わなかった。&lt;br /&gt;&lt;br /&gt;どうやってこの野獣ちゃんを止めたらいい？　とっても簡単。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.add_timer(1) { EM.&lt;span class="dan_blue"&gt;stop&lt;/span&gt; }&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;こっちでは &lt;span class="dan_i"&gt;EM#run&lt;/span&gt; にブロックを渡している。ブロックの中身は reactor が初期化されたあと、 reactor が走り始める前に実行される。必要な初期化処理があれば、なんでもこのブロックに入れることができる。この場合は、時が来たら &lt;span class="dan_i"&gt;EM#stop&lt;/span&gt; を実行してくれるタイマーを作成している。EM#stop の代わりに &lt;span class="dan_i"&gt;EM#stop_event_loop&lt;/span&gt; を呼ぶこともできる。この二つのメソッド呼び出しはどちらも同じもので、reactor を終了させる。reactor が終了すれば、&lt;span class="dan_i"&gt;EM#run&lt;/span&gt; ブロックのうしろに書かれたコードが実行される。&lt;br /&gt;&lt;br /&gt;&lt;h3 class="dan_h"&gt;Timers&lt;/h3&gt;　ツアーの次の停留所は EventMachine タイマーだ。タイマーには二つのタイプが存在する。一回限りのタイマーと、周期的なタイマーだ。EventMachine にタイマーを加えるには二つの異なる、だが同等の効果の方法がある。一般的な方法としては、下記で見るように &lt;span class="dan_i"&gt;EM#add_timer&lt;/span&gt; と &lt;span class="dan_i"&gt;EM#add_periodic_timer&lt;/span&gt; を使うやり方だ。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 70%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.&lt;span class="dan_blue"&gt;add_timer&lt;/span&gt;(5) do&lt;br /&gt;    puts "BOOM"&lt;br /&gt;    EM.stop_event_loop&lt;br /&gt;  end&lt;br /&gt;  EM.&lt;span class="dan_blue"&gt;add_periodic_timer&lt;/span&gt;(1) do&lt;br /&gt;    puts "Tick ... "&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="dan_yellowbox"&gt;titania:examples dj2$ ruby timer.rb&lt;br /&gt;Tick...&lt;br /&gt;Tick...&lt;br /&gt;Tick...&lt;br /&gt;Tick...&lt;br /&gt;BOOM&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="456" width="192" src="http://4.bp.blogspot.com/_KJLBBSxY7xs/TR0IZUbDWaI/AAAAAAAAAPo/ZPxvAIKnAiI/s456/6.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;この例では二つのタイマーをシステムに追加する。周期的なタイマーは多くとも1秒に一度実行され、一回限りのタイマーは少なくとも5秒後には実行されるだろう。この（「多くとも」とか「少なくとも」みたいな）言葉づかいは超重要だ。EventMachine はタイマーがいつ実行されるのか保証しない。指定したフレーム時間で実行される&lt;span class="dan_i"&gt;かもしれない&lt;/span&gt;だけだ。&lt;br /&gt;&lt;br /&gt;以下の同等の例では、メソッドの代わりにクラスを用いている。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  &lt;span class="dan_blue"&gt;EM::Timer.new&lt;/span&gt;(5) do&lt;br /&gt;    puts "BOOM"&lt;br /&gt;    EM.stop&lt;br /&gt;  end&lt;br /&gt;  &lt;span class="dan_blue"&gt;EM::PeriodicTimer.new&lt;/span&gt;(1) do&lt;br /&gt;    puts "Tick ..."&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;機能面ではこれらの二つの例は同一だ。私は最初に見た方、&lt;span class="dan_i"&gt;EM#add_timer&lt;/span&gt; と &lt;span class="dan_i"&gt;EM#add_periodic_timer&lt;/span&gt; の方をより多く使う。&lt;br /&gt;&lt;br /&gt;（&lt;b&gt;訳注&lt;/b&gt;：以下の問題は現在の EventMachine(0.12.10) では存在しません。&lt;br /&gt;　EM#add_periodic_timer の返り値は EM::PeriodicTimer オブジェクトであり、&lt;br /&gt;　EM#cancel_timer にそれを渡すと中で EM::PeriodicTimer#cancel メソッドを呼んでくれます）&lt;br /&gt;&lt;br /&gt;メソッドではなくクラスを使用しなければならない場合も一つだけある。それは周期的なタイマーをキャンセルする場合だ。 &lt;span class="dan_i"&gt;EM#add_timer&lt;/span&gt; の返り値のシグネチャを &lt;span class="dan_i"&gt;EM#cancel_timer&lt;/span&gt; に渡して実行すると、一回限りのタイマーはキャンセル出来る。周期的なタイマーでは、タイマーが再スケジュールされる度に、毎回新しいシグネチャを受け取ってしまうという問題があるんだ。そして、シグネチャを知らなければタイマーをキャンセルことができない。&lt;br /&gt;&lt;br /&gt;もし周期的なタイマーをキャンセルさせる必要があるなら、&lt;span class="dan_i"&gt;EM::PeriodicTimer&lt;/span&gt; を使う必要がある。これは &lt;span class="dan_i"&gt;EM::PeriodicTimer#cancel&lt;/span&gt; というメソッドを提供しているんだが、もうおわかりの通り、周期的なタイマーをキャンセルできる。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 65%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  &lt;span class="dan_blue"&gt;p&lt;/span&gt; = EM::PeriodicTimer.new(1) do&lt;br /&gt;    puts "Tick ..."&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  EM::Timer.new(5) do&lt;br /&gt;    puts "BOOM"&lt;br /&gt;    &lt;span class="dan_blue"&gt;p.cancel&lt;/span&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  EM::Timer.new(8) do&lt;br /&gt;    puts "The googles, they do nothing"&lt;br /&gt;    EM.stop&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;titania:examples dj2$ ruby timer_cancel.rb&lt;br /&gt;Tick...&lt;br /&gt;Tick...&lt;br /&gt;Tick...&lt;br /&gt;Tick...&lt;br /&gt;BOOM&lt;br /&gt;The googles, they do nothing&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="507" width="244" src="http://2.bp.blogspot.com/_KJLBBSxY7xs/TR0IZdrZQMI/AAAAAAAAAPw/-5R733AAYBs/s507/8.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3 class="dan_h"&gt;Deferring and Delaying Work&lt;/h3&gt;　Reactor パターンの定義を思い返してみると、 reactor はシングルスレッドだったのに気づくだろう。EventMachine もこのシングルスレッドなアプローチの reactor に当てはまる。reactor 自身はシングルスレッドであり、reactor で扱う EM のメソッドはスレッドセーフでは&lt;span class="dan_i"&gt;&lt;b&gt;ない&lt;/b&gt;&lt;/span&gt;。&lt;br /&gt;&lt;br /&gt;これは2つの結果になる。まず第一に、おそらく私たちは長い時間かかるコードを持つってことだ。データベースクエリや、リモートHTTPリクエスト、その他もろもろ。効率のためには、これらのコードをバックグラウンドのスレッドにやらせる必要がある。第二に、コードをバックグラウンドのスレッドに追いやったら、それを動かしてくれるように reactor に命令できるようにする必要もある。&lt;br /&gt;&lt;br /&gt;ここで &lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; と &lt;span class="dan_i"&gt;EM#next_tick&lt;/span&gt; のおでましだ。&lt;br /&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; を使うと EventMachine のスレッドプールへ、実行するコードブロックを一つのスレッドとしてスケジュールすることができる。このスレッドプールは（デフォルトでは）最大で20個までのスレッドを提供する。やべぇ、俺らのコードをバックグラウンドで走らせたら、その結果をどうやってクライアントに伝えるんだ？　もし必要なら、&lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; は第二のパラメータをとる。&lt;span class="dan_i"&gt;callback&lt;/span&gt; だ。このコールバックはメイン reactor スレッド上で実行され、スレッドプールに回された操作の返り値を提供する。我々は、クライアントとコミュニケーションするために、このコールバックを使うことができる。&lt;br /&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; には悪い面もあって、Ruby1.8 のスレッドの実装で動かさなきゃいけないということだ。 Ruby には本当のOSスレッドがない。グリーンスレッドと呼ばれるものならある。（一つのRubyプロセスの）全てをその上で動かすOSスレッドが一つあり、Ruby はそのOSレベルスレッド上で自分のスレッドを作成する。これは、 Ruby が全てのスレッドスケジューリングを扱っていることを意味していて、そしていずれにしてもあなたのプロセスがブロックするだろうOSレベルスレッドをつかむ。だから、あなたが延期処理を行うどのスレッドの中でも、Ruby をブロックしないと確信できるように注意しなくちゃならない。じゃないと全体をブロックしてしまう。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;(&lt;b&gt;訳注&lt;/b&gt;：先述の通り、Ruby1.9ではネイティブスレッドになっています。1.9ではOSがスレッドスケジューリングを扱いますが、GILにより一度に走るスレッドは一つだけです。よって注意すべき点は変わりません)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;EM#next_tick&lt;/span&gt; を使うと、次の reactor ループイテレーションで発生するように、実行するコードブロックをスケジュールできる。実行はメイン reactor スレッドで起こる。事実上この遅延は瞬時に起っていると考えることができて、これは本来コードが異なるスレッドで動作することを意図してスケジュールしている。EM はスレッドセーフではないから、スレッドプールのとあるスレッドから &lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; を使おうとすると、深刻な問題に陥ったりクラッシュする可能性がある。&lt;br /&gt;&lt;br /&gt;例えば EM#defer なスレッドで何かを動かしていて、&lt;span class="dan_i"&gt;EM::HttpClient&lt;/span&gt; を使って新しい接続を確立する必要があるとしたら、それはメインスレッド上で行う必要がある。となると接続の作成は、&lt;span class="dan_i"&gt;EM#next_tick&lt;/span&gt; へ渡すコードブロックの中ですればいいわけだ。&lt;br /&gt;&lt;h4 class="dan_h"&gt;EM#next_tick&lt;/h4&gt;　&lt;span class="dan_i"&gt;EM#next_tick&lt;/span&gt; を使うことは、&lt;span class="dan_i"&gt;EM#add_timer&lt;/span&gt; を動かすのにとてもよく似ている： &lt;span class="dan_i"&gt;EM#next_tick&lt;/span&gt; に渡した特定のコードブロックは、reactor ループの次のイテレーションで実行される。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 70%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.add_periodic_timer(1) do&lt;br /&gt;    puts "Hai"&lt;br /&gt;  end&lt;br /&gt;  EM.add_timer(5) do&lt;br /&gt;    EM.&lt;span class="dan_blue"&gt;next_tick&lt;/span&gt; do&lt;br /&gt;      EM.stop_event_loop&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;titania:examples dj2$ ruby next_tick.rb&lt;br /&gt;Hai&lt;br /&gt;Hai&lt;br /&gt;Hai&lt;br /&gt;Hai&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="378" width="184" src="http://2.bp.blogspot.com/_KJLBBSxY7xs/TR0IZrHMtdI/AAAAAAAAAP4/ffUb6Tw9eK4/s378/10.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;EM#next_tick&lt;/span&gt; でスケジュールされたものは、メインスレッドで同期的に実行される。&lt;span class="dan_i"&gt;EM#next_tick&lt;/span&gt; ブロック内のどんな長い時間かかるタスクも、それの実行を終えるまでプログラム全体をブロックしてしまう。通常、これはよくないことだ。&lt;br /&gt;&lt;h4 class="dan_h"&gt;EM#defer&lt;/h4&gt;　同様に、&lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; を使うことは、その実行がバックグラウンドスレッドで終了した後に、メインスレッドで実行されるコールバックを提供する能力を与えてくれる。また、コールバック関数は渡さなくてもよい。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 55%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;require 'thread'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.add_timer(2) do&lt;br /&gt;    puts "Main #{Thread.current}"&lt;br /&gt;    EM.stop_event_loop&lt;br /&gt;  end&lt;br /&gt;  EM.&lt;span class="dan_blue"&gt;defer&lt;/span&gt; do&lt;br /&gt;    puts "Defer #{Thread.current}"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;titania:examples dj2$ ruby defer.rb&lt;br /&gt;Defer #&amp;lt;Thread:0x5637f4&amp;gt;&lt;br /&gt;Main #&amp;lt;Thread:0x35700&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="318" width="335" src="http://2.bp.blogspot.com/_KJLBBSxY7xs/TR0IZorIzXI/AAAAAAAAAQA/d6oDkqBpK64/s335/11.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; に渡したブロックは、バックグラウンドスレッドで実行が開始され、ゴキゲンに走り続ける。注意だが、あなたのコードはこのスレッドを永遠に占有しないようにしなければならない。EventMachine はこの状態を検知しないので、スレッドが無期限に実行されてしまう。スレッドプールのサイズは決っているため、そうやってスレッドを失ったら、その分取り戻せなくなる。&lt;br /&gt;&lt;br /&gt;また、コードが走り終わったあとにコールバック関数を実行するという &lt;span class="dan_i"&gt;EM#defer&lt;/span&gt; の機能を利用できる。コールバック関数に仮引数を指定していたならば、コードの返り値がそこに渡されてから実行される。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 55%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  op = proc do&lt;br /&gt;    2+2&lt;br /&gt;  end&lt;br /&gt;  callback = proc do |count|&lt;br /&gt;    puts "2 + 2 == #{count}"&lt;br /&gt;    EM.stop&lt;br /&gt;  end&lt;br /&gt;  EM.&lt;span class="dan_blue"&gt;defer(op, callback)&lt;/span&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="dan_yellowbox"&gt;Rei:EventMachine dj2$ ruby defer_callback.rb&lt;br /&gt;2 + 2 == 4&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="398" width="328" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TR0IkueJluI/AAAAAAAAAQI/VjxwmyTEVAg/s398/12.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;ここでは二つの数字を足す &lt;span class="dan_i"&gt;proc&lt;/span&gt; オブジェクトを作成している。この合計の結果は、EM#defer スレッドでの実行から返ってきて、コールバックへと渡される。そしてコールバックはメイン reactor スレッド上で実行される。このコールバックは結果を出力している。&lt;br /&gt;&lt;br /&gt;&lt;h3 class="dan_h"&gt;Lightweight Concurrency&lt;/h3&gt;EventMachine は軽量な並行処理(Lightweight Concurrency)(&lt;a name="fm20101231-01-03" href="#f20101231-01-03" title="http://rubyeventmachine.com/browser/trunk/docs/LIGHTWEIGHT_CONCURRENCY"&gt;*3&lt;/a&gt;)を扱うための2つのメカニズムを内蔵している。spawned process と deferrable だ。注意して欲しいのは、spawned &lt;span class="dan_i"&gt;process&lt;/span&gt; なんて呼ばれてはいるものの、OSのプロセスとは違うってことだ。この名前は Erlang から来ているのだが少し紛らわしい。&lt;br /&gt;&lt;br /&gt;それら二つのメカニズムにひそむ主要なアイデアは、CPU やメモリにとってより軽く、そして標準のRubyスレッドであるってことだ。軽量の並列動作における多くの働きは、あなたのアプリケーション側でハンドルされる必要がある。deferrable と spawned process によるコードはあなたのアプリケーションから実行要求が来るまで、実行されない。&lt;br /&gt;&lt;br /&gt;これらのメカニズムがどう動くのか、見て行こう。&lt;br /&gt;&lt;h4 class="dan_h"&gt;EM::Deferrable&lt;/h4&gt;&lt;span class="dan_i"&gt;EM::Deferrable&lt;/span&gt;(&lt;a name="fm20101231-01-04" href="#f20101231-01-04" title="http://rubyeventmachine.com/browser/trunk/docs/DEFERRABLES"&gt;*4&lt;/a&gt;) を見ていくところから始めよう。あなたのクラスに &lt;span class="dan_i"&gt;EM::Defferable&lt;/span&gt; をミックスインしたとき、そのクラスのインスタンスには callback と errback 関連の能力が提供される。あなたは実行される callback と errback をいくらでも定義できる。callback と errback は、インスタンスに追加された順番で実行される。&lt;br /&gt;&lt;br /&gt;callback と errback を発動させるためには、インスタンスオブジェクトの &lt;span class="dan_i"&gt;#set_deferred_status&lt;/span&gt; を呼び出す。そのメソッドには &lt;span class="dan_i"&gt;:succeeded&lt;/span&gt; か &lt;span class="dan_i"&gt;:failed&lt;/span&gt; を渡すことができて、&lt;span class="dan_i"&gt;:succeeded&lt;/span&gt; なら callback が、&lt;span class="dan_i"&gt;:failed&lt;/span&gt; なら errback が発動する。これらのブロックは、メインスレッド上ですぐさま実行されるだろう。また、deferrable オブジェクトに状態をセットするために、&lt;span class="dan_i"&gt;#succeed&lt;/span&gt; と &lt;span class="dan_i"&gt;#fail&lt;/span&gt; というシンタックスシュガーも用意されている。&lt;br /&gt;&lt;br /&gt;一旦オブジェクトの状態が指定されると、その後で追加されるどんな callback や errback も、追加された途端にその状態に応じて&lt;span class="dan_i"&gt;ただちに&lt;/span&gt;実行される。&lt;br /&gt;&lt;br /&gt;これが実際にどう動くか見てみよう。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 65%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;class MyDeferrable&lt;br /&gt;  &lt;span class="dan_blue"&gt;include EM::Deferrable&lt;/span&gt;&lt;br /&gt;  def go(str)&lt;br /&gt;    puts "Go #{str} go"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  df = &lt;span class="dan_blue"&gt;MyDeferrable.new&lt;/span&gt;&lt;br /&gt;  df.&lt;span class="dan_blue"&gt;callback&lt;/span&gt; do |x|&lt;br /&gt;    df.go(x)&lt;br /&gt;    EM.stop&lt;br /&gt;  end&lt;br /&gt;  EM.add_timer(1) do&lt;br /&gt;    df.&lt;span class="dan_blue"&gt;set_deferred_status&lt;/span&gt; :succeeded, "SpeedRacer"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;titania:EventMachine dj2$ ruby deferrable.rb&lt;br /&gt;Go SpeedRacer go&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="471" width="248" src="http://2.bp.blogspot.com/_KJLBBSxY7xs/TR0Ik-IDSrI/AAAAAAAAAQQ/D3wpvwqLWW8/s471/13.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;ここで何が起っているか注意深く見てみよう。最初に &lt;span class="dan_i"&gt;EM::Deferrable をクラスに include&lt;/span&gt; している。これで deferrable するのに必要なメソッドがミックスインされる。&lt;br /&gt;&lt;br /&gt;普通に &lt;span class="dan_i"&gt;MyDeferrable&lt;/span&gt; クラスを作成して、そのインスタンスで &lt;span class="dan_i"&gt;#callback&lt;/span&gt; と &lt;span class="dan_i"&gt;#errback&lt;/span&gt; を呼んでいる。callback と errback のブロックには、仮引数をいくらでも指定できる。処理が成功したか失敗したかが決まった時、インスタンスの &lt;span class="dan_i"&gt;#set_deferred_status&lt;/span&gt; を実行している。この場合では、&lt;span class="dan_i"&gt;:succeeded&lt;/span&gt; を渡し、callback には一つの仮引数を指定して定義したから、&lt;span class="dan_i"&gt;"SpeedRacer"&lt;/span&gt; が callback に渡される。&lt;br /&gt;&lt;br /&gt;デフォルトでは、全ての callback が同じ引数で実行される。callback 内で &lt;span class="dan_i"&gt;#set_deferred_status&lt;/span&gt; をもう一度呼び、異なる引数を渡すことで、それ以降の callback には違う引数を渡すことも可能だ。これは deferrable のドキュメントでより詳しく解説される。&lt;br /&gt;&lt;br /&gt;deferrable なオブジェクトを使うために、わざわざクラス全体を実装する必要がない場合もあるだろう。そういう場合のため、 EventMachine は &lt;span class="dan_i"&gt;EM::DefaultDeferrable&lt;/span&gt; というクラスを提供している。カスタムクラスでやる代わりに、&lt;span class="dan_i"&gt;EM::DefaultDeferrable.new&lt;/span&gt; をただするだけで、 &lt;span class="dan_i"&gt;EM::Deferrable&lt;/span&gt; をミックスインしたものと全く同じ動作をしてくれる。&lt;br /&gt;&lt;h4 class="dan_h"&gt;EM::SpawnedProcess&lt;/h4&gt;EventMachine の spwened process は、Erlang のプロセスにインスパイアされている。OSのプロセスではないのにプロセスというネーミングには少し混乱させられるが。spawned process が持つアイデアは、プロセスを作成できて、それにコードを付加することができるということだ。未来のいつかの時点で、spawn されたオブジェクトの &lt;span class="dan_i"&gt;#notify&lt;/span&gt; メソッドを呼び出すことで、付加したブロックを実行することができる。&lt;br /&gt;&lt;br /&gt;deferrable と異なりコードブロックはすぐ実行されないが、&lt;span class="dan_i"&gt;#notify&lt;/span&gt; 呼び出しがあったならいずれは実行される。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 60%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  s = EM.&lt;span class="dan_blue"&gt;spawn&lt;/span&gt; do |val|&lt;br /&gt;    puts "Received #{val}"&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  EM.add_timer(1) do&lt;br /&gt;    s.&lt;span class="dan_blue"&gt;notify&lt;/span&gt; "hello"&lt;br /&gt;  end&lt;br /&gt;  EM.add_periodic_timer(1) do&lt;br /&gt;    puts "Periodic"&lt;br /&gt;  end&lt;br /&gt;  EM.add_timer(3) do&lt;br /&gt;    EM.stop&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;Rei:EventMachine dj2$ ruby spawn.rb&lt;br /&gt;Periodic&lt;br /&gt;Received hello&lt;br /&gt;Periodic&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="456" width="270" src="http://2.bp.blogspot.com/_KJLBBSxY7xs/TR0IlB--daI/AAAAAAAAAQY/pb3sbtcHoBM/s456/15.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3 class="dan_h"&gt;Network Fun&lt;/h3&gt;さあて、イイモノの紹介に入ろう。EM は、ネットワークプログラミングを扱うように設計されている。どんなプロトコルだろうと、一連のベースプロトコル実装だろうが、その能力はAPI開発者やサーバ開発者に楽をさせる。&lt;br /&gt;&lt;h4 class="dan_h"&gt;Servers&lt;/h4&gt;サーバーサイドから始めることにしよう。クライアント側のコードとはとてもよく似ているけど、それは次のセクションでやる。&lt;br /&gt;&lt;br /&gt;イントロダクションで使ったエコーサーバの例に戻ってみよう。&lt;br /&gt;&lt;br /&gt;&lt;div style="float: left; width: 63%"&gt;&lt;div class="dan_marginbox2"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;class Echo &amp;lt; &lt;span class="dan_blue"&gt;EM::Connection&lt;/span&gt;&lt;br /&gt;  def &lt;span class="dan_blue"&gt;receive_data&lt;/span&gt;(data)&lt;br /&gt;    &lt;span class="dan_blue"&gt;send_data&lt;/span&gt;(data)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.&lt;span class="dan_blue"&gt;start_server&lt;/span&gt;("0.0.0.0", 10000, Echo)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;Rei:~ dj2$ telnet localhost 10000&lt;br /&gt;Trying 127.0.0.1...&lt;br /&gt;Connected to localhost.&lt;br /&gt;Escape character is '^]'.&lt;br /&gt;helo&lt;br /&gt;&lt;span class="dan_green"&gt;helo&lt;/span&gt;&lt;br /&gt;goodbye cruel world&lt;br /&gt;&lt;span class="dan_green"&gt;goodbye cruel world&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right"&gt;&lt;img border="0" height="412" width="264" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TR0IlG8b_xI/AAAAAAAAAQg/2M2-Ci7pIeg/s412/16.png" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;君にも分かるとおり、&lt;span class="dan_i"&gt;EM::Connection&lt;/span&gt; クラスを継承して &lt;span class="dan_i"&gt;Echo&lt;/span&gt; クラスを作成している。そして &lt;span class="dan_i"&gt;EM#start_server&lt;/span&gt; メソッドを使い、さっき定義した &lt;span class="dan_i"&gt;Echo&lt;/span&gt; クラスを用いて、全てのインターフェースを監視する、ポート10000番上のサーバを作っている。&lt;br /&gt;&lt;br /&gt;おもしろいことに、これと同じコードを書く方法がなんと二つ以上存在している。どれを使うかは好きにしていい。&lt;br /&gt;&lt;br /&gt;モジュールを使うこともできる：&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;&lt;span class="dan_blue"&gt;module&lt;/span&gt; Echo&lt;br /&gt;  def receive_data(data)&lt;br /&gt;    send_data(data)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.start_server("0.0.0.0", 10000, Echo)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;またはブロックでも：&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.start_server("0.0.0.0", 10000) do |&lt;span class="dan_blue"&gt;srv&lt;/span&gt;|&lt;br /&gt;    def &lt;span class="dan_blue"&gt;srv&lt;/span&gt;.receive_data(data)&lt;br /&gt;      send_data(data)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;３つの全ての例で、新しいコネクションが確立したとき、新しい匿名のクラスがあなたのコードを取り込んで作成される。これは大事なことで、コネクション毎にあなたのクラスの新しいインスタンスを持つことになるってことだ。インスタンスは次の接続の時には存在しないので、コネクション間でインスタンス内には何も保存することはできない。&lt;br /&gt;&lt;br /&gt;サーバとして機能させるためには &lt;span class="dan_i"&gt;#receive_data(data)&lt;/span&gt; という一つのメソッドを実装する必要がある。もし &lt;span class="dan_i"&gt;#receive_data&lt;/span&gt; を実装しなかったら、&lt;span class="dan_i"&gt;"............&gt;&gt;&gt;6"&lt;/span&gt; みたいなものがコンソールに吐出されるのを見るハメになる。もし君が私に似ているなら、それがどこから来ているのか調べるために３０分費やすことになるだろう。&lt;br /&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;#receive_data&lt;/span&gt; のようにクライアントとの接続がある間に呼び出される、いくつかのメソッドが他にもある。&lt;br /&gt;&lt;br /&gt;&lt;table style="border: 2px solid black; border-collapse: collapse"&gt;&lt;tr&gt;  &lt;td style="border: 2px solid black"&gt;&lt;b&gt;post_init&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;  &lt;td style="border: 2px solid black"&gt;インスタンスの初期化時、コネクションが完全に確立する前に呼ばれる。&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr style="background-color: #DDDDDD"&gt;  &lt;td style="border: 2px solid black"&gt;&lt;b&gt;connection_completed&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;  &lt;td style="border: 2px solid black"&gt;コネクションが完全に確立した後に呼ばれる。&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt;  &lt;td style="border: 2px solid black"&gt;&lt;b&gt;receive_data(data)&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;  &lt;td style="border: 2px solid black"&gt;クライアントからデータを受け取った時に呼ばれる。データはチャンクで受け取る。チャンクの組み立てはあなたの責任だ。&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr style="background-color: #DDDDDD"&gt;  &lt;td style="border: 2px solid black"&gt;&lt;b&gt;unbind&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;  &lt;td style="border: 2px solid black"&gt;クライアントとの接続が完全に切れたときに呼ばれる。&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;私たちの例では、クライアントに返送するために &lt;span class="dan_i"&gt;#send_data(data)&lt;/span&gt; を使った。巨大なデータファイルを送りたいなら、巨大なデータのチャンクを送り出すのに便利なメソッドである &lt;span class="dan_i"&gt;#send_file_data(filename)&lt;/span&gt; を使うこともできる。&lt;br /&gt;&lt;br /&gt;最後に、ここには示されていないが &lt;span class="dan_i"&gt;#close_connection&lt;/span&gt; と &lt;span class="dan_i"&gt;#close_connection_after_writing&lt;/span&gt; という二つの便利なメソッドがある。これら2つのメソッドはとても似た操作を行う。両方ともクライアントが接続を閉じた時にシグナルを飛ばす。&lt;span class="dan_i"&gt;#close_connection_after_writing&lt;/span&gt; は接続が閉じられる前に &lt;span class="dan_i"&gt;#send_data&lt;/span&gt; で送った全てのデータを確実にクライアントに送るという点で異なる。&lt;br /&gt;&lt;br /&gt;以前に言及したように、接続と接続の間で君のクラスのインスタンスはどんな情報も共有できない。幸運にも、いや、設計されたことだろうが、EventMachine はこれを処理するメカニズムを提供する。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;class Pass &amp;lt; EM::Connection&lt;br /&gt;  &lt;span class="dan_blue"&gt;attr_accessor :a, :b&lt;/span&gt;&lt;br /&gt;  def receive_data(data)&lt;br /&gt;    send_data "#{@a} #{data.chomp} #{b}"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.start_server("127.0.0.1", 10000, Pass) do |&lt;span class="dan_blue"&gt;conn&lt;/span&gt;|&lt;br /&gt;    &lt;span class="dan_blue"&gt;conn.a&lt;/span&gt; = "Goodbye"&lt;br /&gt;    &lt;span class="dan_blue"&gt;conn.b&lt;/span&gt; = "world"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;titania:~ dj2$ telnet localhost 10000&lt;br /&gt;Trying 127.0.0.1...&lt;br /&gt;Connected to localhost.&lt;br /&gt;Escape character is '^]'.&lt;br /&gt;mostly cruel&lt;br /&gt;&lt;span class="dan_green"&gt;Goodbye mostly cruel world&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;EM#start_server&lt;/span&gt; へ渡されたブロックの中で、&lt;span class="dan_i"&gt;Pass&lt;/span&gt; インスタンスは自身が初期化された後、クライアントからデータを受け取る前に、EventMachine から値が渡されている。このどんな状態でもセットされたインスタンスを、必要ならば使うことができる。&lt;br /&gt;&lt;h4 class="dan_h"&gt;Clients&lt;/h4&gt;ひとたびサーバを起動したならば、クライアントでそれに接続するのが有益だろう。幸い、サーバの動作を知った後なので、魔法を起こすのに何が必要か大部分は知っているよね。&lt;br /&gt;&lt;br /&gt;&lt;div class="dan_marginbox"&gt;&lt;pre class="dan_bluebox"&gt;require 'eventmachine'&lt;br /&gt;&lt;br /&gt;class Connector &amp;lt; EM::Connection&lt;br /&gt;  def post_init&lt;br /&gt;    puts "Getting /"&lt;br /&gt;    send_data "GET / HTTP/1.1\r\nHost: MagicBob\r\n\r\n"&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def receive_data(data)&lt;br /&gt;    puts "Received #{data.length} bytes"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;EM.run do&lt;br /&gt;  EM.&lt;span class="dan_blue"&gt;connect&lt;/span&gt;("www.postrank.com", 80, Connector)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;pre class="dan_yellowbox"&gt;titania:EventMachine dj2$ ruby connect.rb&lt;br /&gt;Getting /&lt;br /&gt;Received 1448 bytes&lt;br /&gt;Received 1448 bytes&lt;br /&gt;Received 1448 bytes&lt;br /&gt;Received 1448 bytes&lt;br /&gt;Received 2896 bytes&lt;br /&gt;Received 1448 bytes&lt;br /&gt;Received 1448 bytes&lt;br /&gt;Received 935 bytes&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span class="dan_i"&gt;EM#connect&lt;/span&gt; によりコネクションが作成される。このコード例は、上でサーバを作成したときに述べられた考えに従っている。コールバックメソッドは同じ名前を持ち、サーバにデータを送るメソッドも、サーバがクライアントにデータを送るときと同じ &lt;span class="dan_i"&gt;#send_data&lt;/span&gt; だ。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="dan_h"&gt;Conclusion&lt;/h2&gt;&lt;br /&gt;EventMachine の連続公演はこれにておしまい。私たちは、物事の成し遂げ方と、&lt;span class="dan_i"&gt;EM#run&lt;/span&gt;を使ってそれが走るのを見た。一回限りのタイマーと、周期的なタイマーを作成すること。Deferring と next_tick のコードブロック。deferrable と spawned process をクライアントとサーバで作成すること。&lt;br /&gt;&lt;br /&gt;たぶん、全てを見たあとでは、あなたは Eventmachine がどう機能するか、そしてあなたのアプリケーションでどう使えばいいのか、より理解が深まったことだろう。&lt;br /&gt;&lt;br /&gt;何か質問やコメントがあるならば、遠慮なく私に連絡を。： dan(at-mark)aiderss.com&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="dan_h"&gt;Resources&lt;/h2&gt;&lt;br /&gt;&lt;a href="http://rubyeventmachine.com/"&gt;http://rubyeventmachine.com/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://github.com/eventmachine/eventmachine/tree/master"&gt;http://github.com/eventmachine/eventmachine/tree/master&lt;/a&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/eventmachine/topics"&gt;http://groups.google.com/group/eventmachine/topics&lt;/a&gt;&lt;br /&gt;&lt;a href="http://eventmachine.rubyforge.org/"&gt;http://eventmachine.rubyforge.org/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/"&gt;http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://20bits.com/articles/an-eventmachine-tutorial/"&gt;http://20bits.com/articles/an-eventmachine-tutorial/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://nutrun.com/weblog/distributed-programming-with-jabber-and-eventmachine/"&gt;http://nutrun.com/weblog/distributed-programming-with-jabber-and-eventmachine/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.infoq.com/news/2008/06/eventmachine"&gt;http://www.infoq.com/news/2008/06/eventmachine&lt;/a&gt;&lt;br /&gt;&lt;a href="http://everburning.com/news/playing-with-eventmachine/"&gt;http://everburning.com/news/playing-with-eventmachine/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.nominet.org.uk/tech/2007/10/12/dnsruby-and-eventmachine/"&gt;http://blog.nominet.org.uk/tech/2007/10/12/dnsruby-and-eventmachine/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://devver.net/blog/2008/10/sending-files-with-eventmachine/"&gt;http://devver.net/blog/2008/10/sending-files-with-eventmachine/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/1820"&gt;http://en.oreilly.com/rails2008/public/schedule/detail/1820&lt;/a&gt;&lt;br /&gt;&lt;a href="http://nhw.pl/wp/2007/12/07/eventmachine-how-to-get-clients-ip-address"&gt;http://nhw.pl/wp/2007/12/07/eventmachine-how-to-get-clients-ip-address&lt;/a&gt;&lt;br /&gt;&lt;a href="http://simonwex.com/articles/2008/10/22/eventmachine-http-client"&gt;http://simonwex.com/articles/2008/10/22/eventmachine-http-client&lt;/a&gt;&lt;br /&gt;&lt;a href="http://adrianhosey.blogspot.com/2009/01/eventmachine-tcp-server-module-for-ruby.htm"&gt;http://adrianhosey.blogspot.com/2009/01/eventmachine-tcp-server-module-for-ruby.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="f20101231-01-01" href="#fm20101231-01-01"&gt;*1&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Reactor_pattern"&gt;http://en.wikipedia.org/wiki/Reactor_pattern&lt;/a&gt;&lt;br /&gt;&lt;a name="f20101231-01-04" href="#fm20101231-01-02"&gt;*2&lt;/a&gt; &lt;a href="http://www.kegel.com/c10k.html"&gt;http://www.kegel.com/c10k.html&lt;/a&gt;&lt;br /&gt;&lt;a name="f20101231-01-03" href="#fm20101231-01-03"&gt;*3&lt;/a&gt; &lt;a href="http://rubyeventmachine.com/browser/trunk/docs/LIGHTWEIGHT_CONCURRENCY"&gt;http://rubyeventmachine.com/browser/trunk/docs/LIGHTWEIGHT_CONCURRENCY&lt;/a&gt;&lt;br /&gt;&lt;a name="f20101231-01-02" href="#fm20101231-01-04"&gt;*4&lt;/a&gt; &lt;a href="http://rubyeventmachine.com/browser/trunk/docs/DEFERRABLES"&gt;http://rubyeventmachine.com/browser/trunk/docs/DEFERRABLES&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;style type="text/css"&gt;h1.dan_h {  font-size: 2.5em;}h2.dan_h {  font-size: 2em;}h3.dan_h {  font-size: 1.7em;}h4.dan_h {  font-size: 1.5em;}.dan_bluebox {  background-color: #edf6ff;  border: 1px solid black;  padding: 10px;  line-height: 1.5em;  font-weight: bold;}.dan_yellowbox {  background-color: #fefddd;  border: 1px solid black;  padding: 10px;  line-height: 1.5em;  font-weight: bold;}.dan_marginbox {  margin-left: 50px;  margin-right: 50px;}.dan_marginbox2 {}.dan_green {  color: #71a340;}.dan_blue {  color: #2577ff;}.dan_center {  margin: 0 auto 0 auto;}.dan_i {  font-style: italic;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-4210356207095075624?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/4210356207095075624/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/12/eventmachine.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/4210356207095075624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/4210356207095075624'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/12/eventmachine.html' title='【翻訳】EventMachine入門'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_KJLBBSxY7xs/TR0IZFFsO8I/AAAAAAAAAPg/NtQVfPz-gyY/s72-c/3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-5178634174536614045</id><published>2010-11-27T06:29:00.003+09:00</published><updated>2010-11-27T06:36:07.423+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='RSpec'/><title type='text'>【翻訳】Fuubar: instafailing な RSpec プログレスバーフォーマッタ</title><content type='html'>Jeff Kreeftmeijerさんの "Fuubar: the instafailing RSpec progress bar formatter" を翻訳しました。&lt;br /&gt;元記事はこちら： &lt;a href="http://jeffkreeftmeijer.com/2010/fuubar-the-instafailing-rspec-progress-bar-formatter/"&gt;http://jeffkreeftmeijer.com/2010/fuubar-the-instafailing-rspec-progress-bar-formatter/&lt;/a&gt;&lt;br /&gt;（翻訳の公開と画像の利用は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;Jeffさんのひとつ前のRSpecの記事もよろしければどうぞ。&lt;br /&gt;　&lt;a style="font-weight: bold; color: #880000; text-decoration: underline" href="http://keijinsonyaban.blogspot.com/2010/11/rspec.html"&gt;【翻訳】RSpecでテストが失敗したら即停止して結果を出力&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;翻訳の間違い等があればブログコメントや&lt;a href="http://twitter.com/oshow"&gt;Twitter&lt;/a&gt;などで遠慮無くご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-border-radius: 10px; -moz-box-shadow: 1px 1px 3px #000; -webkit-border-radius: 10px; -webkit-box-shadow: 1px 1px 3px #000; background-color: #eeeeee; border-radius: 10px; border: solid 1px black; box-shadow: 1px 1px 3px #000; color: #222222; margin: 0 auto 0 auto; padding: 10px 20px; width: 500px; text-shadow: 0 1px 0 white; line-height: 1.4em"&gt;&lt;h1&gt;Fuubar: instafailing な RSpec&lt;br /&gt;プログレスバーフォーマッタ&lt;/h1&gt;&lt;br /&gt;　気づいたかもしれないけど、私はここ一週間ほど &lt;a class="jeff_link" href="https://github.com/rspec"&gt;RSpec&lt;/a&gt; でテストスイートをより良く・より速く走らせることに時間を費やしていた。そして今週は、RSpec のフォーマッタを調べた。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img border="0" height="450" src="http://4.bp.blogspot.com/_KJLBBSxY7xs/TPAV0RS6dcI/AAAAAAAAAPA/emTE-HII2MM/s450/fuubar.png" width="450" style="border: 5px solid #222; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px;" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;spec が失敗した時、RSpec が出力する赤い "F" 以外に、あなたがすぐにバグを修正しにいくためのダイレクトなフィードバックがない。あなたは単に全てのテストスイートが走り切るのを待つか、あるいは ^Cを使って割込みをかけるしかない。あなたに出来る他の事は、&lt;a class="jeff_link" href="http://jeffkreeftmeijer.com/2010/making-rspec-stop-operation-immediately-after-failing/"&gt;先週私が書いた &lt;span style="font-style: normal; font-weight: normal"&gt;--fail-fast&lt;/span&gt; オプション&lt;/a&gt;を使うか、あるいは残りの spec を走らせ続けている間にも failure の詳細を出力する &lt;a class="jeff_link" href="https://github.com/grosser/rspec-instafail"&gt;rspec-instafail&lt;/a&gt; を見てみることだ。こりゃあいいや。&lt;br /&gt;&lt;br /&gt;それ以外にも、spec の総数を知ったり、既に実行された spec の数を知ったり、例えば 終了予定時刻(ETA)か何かのようなもの知ったり、より良くできるものがあったと気づいた。また、ドットと "F" による大きな文字列は不要であり、この情報を表示するもっと良い方法があるはずだと感じ始めた。&lt;br /&gt;&lt;br /&gt;私は RSpec のフォーマッタを調べて、それを書くのがとても簡単だと気づいたので、気紛れに &lt;a class="jeff_link" href="https://gist.github.com/676219"&gt;FffuuuFormatter&lt;/a&gt; という、RSpec が FFFFF の代わりに FFFUUU を出力するフォーマッタを書いてみたりした。えっ。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Fuubar&lt;/h2&gt;&lt;br /&gt;　少し見て回ったあと、2008年に &lt;a class="jeff_link" href="http://twitter.com/nick_evans"&gt;@nick_evans&lt;/a&gt; によって書かれた、私が&lt;a class="jeff_link" href="http://ekenosen.net/nick/devblog/2008/12/better-progress-bar-for-rspec/"&gt;プログレスバーフォーマッタ&lt;/a&gt;で抱えているようないくつかの問題を修正しようとした記事を見つけた。Nick は &lt;a class="jeff_link" href="http://twitter.com/peleteiro"&gt;@peleteiro&lt;/a&gt; の &lt;a class="jeff_link" href="http://rubygems.org/gems/progressbar"&gt;progressbar gem&lt;/a&gt; を使った本当に良い解決法を書いていた。&lt;br /&gt;&lt;br /&gt;私は Nick の仕事をさらに先に進めようと決め、rspec-instafail を使って全ての failure 毎にダイレクトフィードバックを行う、RSpec 2.0 にもちゃんと対応したフォーマッタを作り上げた。全てを gem に入れたところで、&lt;a class="jeff_link" href="http://twitter.com/josevalim"&gt;@josevalim&lt;/a&gt; が名前を考えてくれた： &lt;a class="jeff_link" href="https://github.com/jeffkreeftmeijer/fuubar"&gt;Fuubar&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;ここに、&lt;a class="jeff_link" href="http://vimeo.com/16845253"&gt;動作中の Fuubar の短いビデオ&lt;/a&gt;がある：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object width="440" height="350" style="border: 5px solid #222; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px;"&gt; &lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=16845253&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=ff9933&amp;amp;fullscreen=1" /&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=16845253&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=ff9933&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always"  width="440" height="350"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Fuubar のインストール法は簡単だ。ただ Gemfile にそれを入れて、これからはあなたの spec をこうやって走らせるだけだ。&lt;br /&gt;（&lt;b&gt;訳注&lt;/b&gt;：Bundler 前提みたいに書いてありますが、もちろん gem install fuubar でも大丈夫です）&lt;br /&gt;&lt;br /&gt;&lt;pre class="jeff_code"&gt;&lt;span style="color: #555"&gt;$&lt;/span&gt; rspec --format Fuubar --color spec&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;デフォルトのフォーマッタとして Fuubar を使いたいなら、.rspec ファイルにオプションを書けばよい。&lt;br /&gt;&lt;br /&gt;&lt;pre class="jeff_code"&gt;--format Fuubar&lt;br /&gt;--color&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;そのあとは、あなたがいつも慣れているように spec を走らせることができる。&lt;br /&gt;&lt;br /&gt;&lt;pre class="jeff_code"&gt;&lt;span style="color: #555"&gt;$&lt;/span&gt; rspec spec&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Fuuture&lt;/h2&gt;&lt;br /&gt;いつもの： どんな感じか教えて欲しい、そして &lt;a class="jeff_link" href="https://github.com/jeffkreeftmeijer/fuubar/issues"&gt;Github 上で issue&lt;/a&gt; を作成し、いいアイデアがあったり、何か問題があったら、&lt;a class="jeff_link" href="https://github.com/inbox/new/jeffkreeftmeijer"&gt;Github メッセージ&lt;/a&gt;を送るか &lt;a class="jeff_link" href="http://jeffkreeftmeijer.com/contact/"&gt;email&lt;/a&gt; で連絡して欲しい。もちろん、いつでもプロジェクトを fork して、プルリクエストを送ったり email でパッチを送ることもできる。&lt;br /&gt;&lt;br /&gt;Fuubar は今のところ RSpec 2 上でのみ動作するが、旧バージョンと互換性を持たせられない理由はない。また、Nick の元のコードには遅い spec を見つける機能があったが、いい実装が見つからなかったので私はそれを省略した。&lt;br /&gt;&lt;br /&gt;それで、しなければならないことはまだたくさんあるが、これは現在のフォーマッタからの確かな進歩だと私は思う。多分、Fuubar を RSpec のデフォルトのフォーマッタの一つにするパッチに変えることもできるだろう。あなたはどう思う？&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;style&gt;pre.jeff_code {  background-color: #222;  margin: 0px 0px 0px -40px;  padding: 20px;  width: 540px;  -webkit-border-radius: 5px;  -moz-border-radius: 5px;  border-radius: 5px;  color: white;  text-shadow: 0 1px 0 black;}a.jeff_link, a:visited.jeff_link {  font-weight: bold;  color: black;  text-decoration: none;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-5178634174536614045?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/5178634174536614045/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/11/fuubar-instafailing-rspec.html#comment-form' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/5178634174536614045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/5178634174536614045'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/11/fuubar-instafailing-rspec.html' title='【翻訳】Fuubar: instafailing な RSpec プログレスバーフォーマッタ'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_KJLBBSxY7xs/TPAV0RS6dcI/AAAAAAAAAPA/emTE-HII2MM/s72-c/fuubar.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-616146106995731550</id><published>2010-11-27T06:29:00.002+09:00</published><updated>2010-11-27T06:35:04.061+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='RSpec'/><title type='text'>【翻訳】RSpecでテストが失敗したら即停止して結果を出力</title><content type='html'>Jeff Kreeftmeijerさんの "Making RSpec stop operation immediately after failing" を翻訳しました。&lt;br /&gt;元記事はこちら： &lt;a href="http://jeffkreeftmeijer.com/2010/making-rspec-stop-operation-immediately-after-failing/"&gt;http://jeffkreeftmeijer.com/2010/making-rspec-stop-operation-immediately-after-failing/&lt;/a&gt;&lt;br /&gt;（翻訳の公開と画像の利用は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;Jeffさんのその次のRSpecの記事もよろしければどうぞ。&lt;br /&gt;　&lt;a style="font-weight: bold; color: #880000; text-decoration: underline" href="http://keijinsonyaban.blogspot.com/2010/11/fuubar-instafailing-rspec.html"&gt;【翻訳】Fuubar: instafailing な RSpec プログレスバーフォーマッタ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;翻訳の間違い等があればブログコメントや&lt;a href="http://twitter.com/oshow"&gt;Twitter&lt;/a&gt;などで遠慮無くご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-border-radius: 10px; -moz-box-shadow: 1px 1px 3px #000; -webkit-border-radius: 10px; -webkit-box-shadow: 1px 1px 3px #000; background-color: #eeeeee; border-radius: 10px; border: solid 1px black; box-shadow: 1px 1px 3px #000; color: #222222; margin: 0 auto 0 auto; padding: 10px 20px; width: 500px; text-shadow: 0 1px 0 white; line-height: 1.4em"&gt;&lt;h1&gt;RSpecでテストが失敗したら&lt;br /&gt;即停止して結果を出力&lt;/h1&gt;&lt;br /&gt;　&lt;a class="jeff_link" href="https://github.com/rspec/rspec"&gt;RSpec&lt;/a&gt; で全てのテストスイートを走らせていて、最初か二番目で spec が失敗したと想像してみて欲しい。その後も走る spec が約200は残っているが、あなたはすぐにでも最初の失敗を修正するのに没頭したい。あなたは多分、それらを修正するための failure の詳細を知るために、spec の実行に割り込もうとするはずだ、そうだろう？&lt;br /&gt;&lt;br /&gt;ほとんどの時間こうして作業しているわけだが（&lt;a class="jeff_link" href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; を使っている時、なんらかの問題で実行に割込みをかけるだろう）、もし RSpec が最初の failure で自動的に停止し結果を出力してくれたらすごくないだろうか？&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img border="0" height="337" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TPAFuCbvMsI/AAAAAAAAAO8/C7112Ttznwc/s450/fusebox.jpg" width="450" style="border: 5px solid #222; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px;" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a class="jeff_link" href="http://rubyforge.org/pipermail/rspec-users/2007-July/002376.html"&gt;rspec-users グループの3年前のスレッド&lt;/a&gt;以外には、役立つデータはほとんど見つからなかったので、私自身で書き始めることにした。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Fail-Fast&lt;/h2&gt;&lt;br /&gt;　私は RSpec のソースを捜索し始め、そして偶然にも &lt;a class="jeff_link" href="http://relishapp.com/rspec/rspec-core/"&gt;Relish により生成された RSpec のドキュメント&lt;/a&gt;を見つけた。そこでは、&lt;a class="jeff_link" href="http://rubygems.org/gems/rspec-core/versions/2.0.0.rc"&gt;rspec-core 2.0.0.rc&lt;/a&gt; から &lt;a class="jeff_link" href="http://relishapp.com/rspec/rspec-core/v/2-0/dir/configuration/fail-fast"&gt;&lt;span style="font-style: normal; font-weight: normal;"&gt;fail_fast&lt;/span&gt; の設定オプション&lt;/a&gt;が導入されていることがわかった。それはまさに私が達成したかったことをやってくれる。&lt;br /&gt;&lt;br /&gt;この fail_fast オプションは、spec が最初に失敗したときに RSpec をすぐさま停止させて failure の詳細を出力し、spec の失敗を修正するのにいい感じに速度を加速させてくれる。使い方は極々簡単だ：&lt;br /&gt;&lt;br /&gt;&lt;pre class="jeff_code"&gt;&lt;span style="color: #BC9458"&gt;# spec/spec_helper.rb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;RSpec.configure &lt;span style="color: #CC7833"&gt;do&lt;/span&gt; |c|&lt;br /&gt;  c.fail_fast = &lt;span style="color: #CC7833"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #CC7833"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;コマンドラインサポート&lt;/h2&gt;&lt;br /&gt;あなたは時々 fail_fast オプションをなしにして、テストスイート全体を走らせたいとも思っているだろうが、spec/spec_helper.rb に現実にはいいオプションが存在しない。だから私は、あなたがいつでもそれをしたい時に出来るよう、&lt;a class="jeff_link" href="https://github.com/rspec/rspec-core/issues/issue/219"&gt;コマンドラインオプション&lt;/a&gt;を追加した：&lt;br /&gt;&lt;br /&gt;&lt;pre class="jeff_code"&gt;&lt;span style="color: #555"&gt;$&lt;/span&gt; bundle exec rspec spec/ --fail-fast&lt;br /&gt;&lt;span style="color: #888"&gt;.F&lt;br /&gt;&lt;br /&gt;Failures:&lt;br /&gt;  1) Swinger should set the Capybara driver&lt;br /&gt;     Failure/Error: Capybara.current_driver.should_not == :rack_test&lt;br /&gt;&lt;br /&gt;Finished in 0.00479 seconds&lt;br /&gt;2 examples, 1 failure&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この --fail-fast オプションは、先日&lt;a class="jeff_link" href="http://blog.davidchelimsky.net/2010/11/07/rspec-21-is-released/"&gt;リリース&lt;/a&gt;された RSpec 2.1 にのみ含まれているので、アップデートを忘れないように。&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;style&gt;pre.jeff_code {  background-color: #222;  margin: 0px 0px 0px -40px;  padding: 20px;  width: 540px;  -webkit-border-radius: 5px;  -moz-border-radius: 5px;  border-radius: 5px;  color: white;  text-shadow: 0 1px 0 black;}a.jeff_link, a:visited.jeff_link {  font-weight: bold;  color: black;  text-decoration: none;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-616146106995731550?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/616146106995731550/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/11/rspec.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/616146106995731550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/616146106995731550'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/11/rspec.html' title='【翻訳】RSpecでテストが失敗したら即停止して結果を出力'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_KJLBBSxY7xs/TPAFuCbvMsI/AAAAAAAAAO8/C7112Ttznwc/s72-c/fusebox.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-3983506033889794474</id><published>2010-11-23T01:41:00.006+09:00</published><updated>2011-11-11T17:49:35.554+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><title type='text'>【翻訳】あなたの知らないGit Tips</title><content type='html'>Mislav Marohnićさんの "A few git tips you didn't know about" を翻訳しました。&lt;br /&gt;元記事はこちら： &lt;a href="http://mislav.uniqpath.com/2010/07/git-tips/"&gt;http://mislav.uniqpath.com/2010/07/git-tips/&lt;/a&gt;&lt;br /&gt;（翻訳の公開は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;翻訳の間違い等があれば遠慮なくご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #EAEAEA; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 850px; margin: 0 auto 0 auto; padding: 10px 0px 20px 0px; -moz-box-shadow: 1px 1px 3px #000; -webkit-box-shadow: 1px 1px 3px #000; box-shadow: 1px 1px 3px #000"&gt;&lt;h1 class="mislav_h"&gt;あなたの知らないGit Tips&lt;/h1&gt;&lt;div class="mislav_text" style="font-style: italic"&gt;注意：いくつかのコマンドやオプションは Git の version &lt;b&gt;1.7.2&lt;/b&gt; 以降が必要です。&lt;br /&gt;OS Xでは、 &lt;a class="mislav_link" href="http://mxcl.github.com/homebrew/"&gt;Homebrew&lt;/a&gt; で簡単にアップグレードできます： &lt;span class="mislav_i"&gt;brew install git&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;git log でブランチとタグも見る&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git log --oneline --decorate&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;&lt;span style="color: #ACA41F"&gt;7466000 (&lt;span style="color: #14F0F0"&gt;HEAD&lt;/span&gt;, &lt;span style="color: #F9391F"&gt;mislav/master&lt;/span&gt;, &lt;span style="color: #31E722"&gt;mislav&lt;/span&gt;)&lt;/span&gt; fix test that fails if current dir is not "hub"&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;494a414&lt;/span&gt; fix cherry-pick of a commit URL&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;4277848 (&lt;span style="color: #F9391F"&gt;origin/master&lt;/span&gt;, &lt;span style="color: #F9391F"&gt;origin/HEAD&lt;/span&gt;, &lt;span style="color: #31E722"&gt;master&lt;/span&gt;)&lt;/span&gt; whoops&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;d270fae&lt;/span&gt; bugfix: git init -g&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;9307af3&lt;/span&gt; test deps&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;8ccc17e&lt;/span&gt; http://github.com/defunkt/hub/contributors&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;64bb19c&lt;/span&gt; bugfix: variable name&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;546726a&lt;/span&gt; dont need you&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;3a8d7af (&lt;span style="color: #EAEC23"&gt;tag: v1.3.1&lt;/span&gt;)&lt;/span&gt; v1.3.1&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;197f429 (&lt;span style="color: #EAEC23"&gt;tag: v1.3.0&lt;/span&gt;)&lt;/span&gt; v1.3.0&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;a1e1a50&lt;/span&gt; not important&lt;br /&gt;&lt;span style="color: #ACA41F"&gt;3c6af16&lt;/span&gt; magic `cherry-pick` supports GitHub commit URLs and "user@sha" notation&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;diff で行の全てではなく、変更された単語部分のみハイライトする&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git diff --word-diff&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;# Returns a Boolean.&lt;br /&gt;def command?(name)&lt;br /&gt;  `type -t &lt;span style="color: #F9391F"&gt;[-#{command}`-]&lt;/span&gt;&lt;span style="color: #31E722"&gt;{+#{name}`+}&lt;/span&gt;&lt;br /&gt;  $?.success?&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;このオプションは &lt;span class="mislav_i"&gt;git log -p&lt;/span&gt; や &lt;span class="mislav_i"&gt;git show&lt;/span&gt; などの、diff のためのオプションを使えるところなら動作する。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;短い status 出力&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git status -sb&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;## &lt;span style="color: #31E722"&gt;thibaudgg&lt;/span&gt;...&lt;span style="color: #F9391F"&gt;thibaudgg/master&lt;/span&gt; [ahead &lt;span style="color: #31E722"&gt;1&lt;/span&gt;, behind &lt;span style="color: #F9391F"&gt;2&lt;/span&gt;]&lt;br /&gt; &lt;span style="color: #F9391F"&gt;M&lt;/span&gt; ext/fsevent/fsevent_watch.c&lt;br /&gt;&lt;span style="color: #F9391F"&gt;??&lt;/span&gt; Makefile&lt;br /&gt;&lt;span style="color: #F9391F"&gt;??&lt;/span&gt; SCEvents/&lt;br /&gt;&lt;span style="color: #F9391F"&gt;??&lt;/span&gt; bin/fsevent_watch&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;&lt;span class="mislav_i"&gt;git status&lt;/span&gt; のデフォルトの冗長な出力は初心者にはいいのだが、一旦 Git に慣れてしまえば必要でなくなる。私は status のチェックをよくやるので、出力はできるだけ簡潔であって欲しい。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;ブランチの push と同時に追跡のセッティングも自動的に行う&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git push -u origin master&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;# "master" ブランチを "origin" リモートへプッシュして、さらに追跡させる&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;”追跡”とはつまり、ローカルブランチとリモートブランチの間のリンクのことだ。他のブランチを追跡しているローカルブランチ上で作業しているなら、&lt;span class="mislav_i"&gt;git pull&lt;/span&gt; と &lt;span class="mislav_i"&gt;git push&lt;/span&gt; に何も引数を渡さなくても、Git は何をするかわかってくれる。&lt;br /&gt;&lt;br /&gt;しかしながら &lt;span class="mislav_i"&gt;git push&lt;/span&gt; はデフォルトでは、同じブランチ名がリモート上にあるならそれらを全て push してしまう。この振る舞いを現在のブランチのみの push に限定するためには、以下の設定を行う。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="mislav_code"&gt;$ git config --global push.default tracking&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;これで、まだ push する準備が整っていないブランチを誤って push することが避けられる。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;他人のリモートブランチを簡単に追跡する&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git checkout -t origin/feature&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;# "feature" ブランチを作成してチェックアウトし、&lt;br /&gt;# "origin/feature" を追跡させる。&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;チームメイトが作業していたブランチをその人と共有することになり、あなたもそれに対して変更を行うつもりなら、それに対応するローカルブランチを作らないといけない。上記のコマンドではブランチの作成とともに追跡のセットアップもやってくれるので、あなたは変更を作成した後にただ &lt;span class="mislav_i"&gt;git push&lt;/span&gt; するだけでよい。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;ブランチをチェックアウトし、master へ rebase して merge する&lt;/h2&gt;&lt;pre class="mislav_code"&gt;&lt;span style="color: gray"&gt;# "master" ブランチ上にいるとき：&lt;/span&gt;&lt;br /&gt;$ git checkout feature &amp;&amp; git rebase @{-1} &amp;&amp; git checkout @{-2} &amp;&amp; git merge @{-1}&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;# "feature" を "master" へ rebase して、それを master へ merge する&lt;/pre&gt;&lt;div class="mislav_text"&gt;"@{-n}" という特別な構文は「現在から数えてn個前にチェックアウトされていたブランチ」という意味だ。"feature" がチェックアウトされたなら、"@{-1}" は "master" を表している。rebase した後、"@{-1}" は rebase の内部処理により "feature" を指すことになるので、今度は "@{-2}" を使って master をチェックアウトする。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;更新：&lt;/b&gt; Björn Steinbrinkh がこれはコマンド2つでも可能だと指摘してくれた： &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="mislav_code"&gt;$ git rebase HEAD feature &amp;&amp; git rebase HEAD @{-2}&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;（&lt;b&gt;訳注：&lt;/b&gt;自分の手元では、このコマンド2つの場合がうまく動かなかった（Gitのバージョンは1.7.3.2）のですが、もし試してくださる方がいたら、結果をブログコメントか&lt;a class="mislav_link"  href="http://twitter.com/oshow"&gt;Twitter&lt;/a&gt;などで教えてくだされば嬉しいです）&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;pull のとき merge ではなく rebase する&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git pull --rebase&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;# 例) "master" ブランチ上にいるなら、 `git fetch origin` をしてから、&lt;br /&gt;# `git rebase origin/master` を実行したのに等しい。&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;Git ではブランチのマージはマージコミットを記録するので、それらは深い意味を持つ――例えば、ある機能がリリースブランチにマージされたのがいつなのかを示すなど。しかしながら、ある1つのブランチを何人かのチームメンバと頻繁にやりとりするような日常的なワークフローでは、普通に &lt;span class="mislav_i"&gt;git pull&lt;/span&gt; していると不必要な細かいマージコミットでタイムラインが汚染されてしまう。rebase ならコミットを常に再適用してくれるので、コミット履歴は直線的な一本のままでいられる。&lt;br /&gt;&lt;br /&gt;&lt;span class="mislav_i"&gt;--rebase&lt;/span&gt; フラグをつけなくても特定のブランチでは常に rebase するようにしてくれる設定がある：&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="mislav_code"&gt;&lt;span style="color: gray"&gt;# master 上で `git pull` するときは常に rebase を使う&lt;/span&gt;&lt;br /&gt;$ git config branch.master.rebase true&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;上の設定を、全ての新しい追跡ブランチでもやるようにする設定もある（グローバルに設定している）：&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="mislav_code"&gt;&lt;span style="color: gray"&gt;# 全追跡ブランチで rebase を使う&lt;/span&gt;&lt;br /&gt;$ git config --global branch.autosetuprebase always&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;ある変更がどのリリースの一部なのか見つける&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git name-rev --name-only 50f3754&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;"tags/v2.3.8~6"&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;コミットの SHA-1 ハッシュはわかるのだが、そのコミットがプロジェクト履歴のどこに位置しているかわからないということは珍しくない。もしあなたが私に似ているなら、多分あなたはその変更があるリリースで発生したのか、それとも違うのかが知りたいだろう。そのコミットに対して &lt;span class="mislav_i"&gt;git show&lt;/span&gt; を使えばコミットメッセージは見れるし、日付も差分も見られるのだが、それらはちっとも助けてはくれない――特に、コミットした日付と、それを成果物に適用した日付が必ずしも一致しないような時には。&lt;br /&gt;&lt;br /&gt;&lt;span class="mislav_i"&gt;name-rev&lt;/span&gt; コマンドはプロジェクトにおいてコミットと関係のあるタグを教えてくれる。上記の例は Ruby on Rails リポジトリから持ってきたものだ。この場合は "v2.3.8" とタグ付けされる6つ前にそのコミットが位置していることを教えてくれている――つまりこの変更は Rails 2.3.8 に存在していると確定できる。&lt;br /&gt;&lt;br /&gt;このコマンドはさらに有用性がある。いくつかのコミットに言及するような議論に参加したとしよう：&lt;br /&gt;&lt;br /&gt;&lt;div style="border-left: 2px solid gray; padding: 15px 15px 15px 15px"&gt;このバグは e6cadd422b72ba9818cc2f3b22243a6aa754c9f8 で混入したものだが、私の記憶が確かなら 50f3754525c61e3ea84a407eb571617f2f39d6fe で修正されている。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;上の文章をクリップボードにコピーして &lt;span class="mislav_i"&gt;git name-rev&lt;/span&gt; へパイプで渡すと、文章中にあるコミットの SHA-1 ハッシュを認識してそれぞれにタグ情報を付加してくれる：&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="mislav_code"&gt;$ pbpaste | git name-rev --stdin&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;"このバグは e6cadd422b72ba9818cc2f3b22243a6aa754c9f8 (tags/v2.3.6~215) で混入したものだが、&lt;br /&gt;私の記憶が確かなら 50f3754525c61e3ea84a407eb571617f2f39d6fe (tags/v2.3.8~6) で修正されている。"&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;併せて読みたい： &lt;span class="mislav_i"&gt;git help describe&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;ある変更が含まれているブランチを見つける&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git branch --contains 50f3754&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;このオプションはブランチのリストを、指定したコミットがそのブランチの祖先に存在するものだけを表示するようにフィルタリングする。"-a" フラグをつければ、リストにリモートの追跡ブランチも含めてくれる。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;あるブランチの上流に既に存在している変更を知る&lt;/h2&gt;&lt;pre class="mislav_code"&gt;&lt;span style="color: gray"&gt;# "feature" ブランチにいる場合に：&lt;/span&gt;&lt;br /&gt;$ git cherry -v master&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;+ 497034f2 Listener.new now accepts a hash of options&lt;br /&gt;- 2d0333ff cache the absolute images path for growl messages&lt;br /&gt;+ e4406858 rename Listener#run to #start&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;&lt;span class="mislav_i"&gt;cherry&lt;/span&gt; コマンドは例えば、開発中のブランチから安定しているブランチへ cherry-pick が行われたコミットを調べるのに便利だ。このコマンドは現在（feature）のブランチと上流（master）のブランチを比較して、両方に存在しているものには "-" をつけて表示する。上流にまだ存在しない変更には "+" マークをつける。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;正規表現にマッチするコミットメッセージを持つ最後のコミットを表示&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git show :/fix&lt;br /&gt;&lt;span style="color: gray"&gt;# メッセージ中に "fix" を含む最後のコミットを表示&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ git show :/^Merge&lt;br /&gt;&lt;span style="color: gray"&gt;# 最後のマージコミットを表示&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;複数のリモートからまとめて fetch する&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git config remotes.default 'origin mislav staging'&lt;br /&gt;$ git remote update&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;# リモートの "origin"、"mislav"、"staging" をfetch&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;&lt;span class="mislav_i"&gt;remote update&lt;/span&gt;するコマンドで fetch される対象になる、デフォルトのリストを決めることができる。あなたのチームメイトや、オープンソースプロジェクトでの信頼できるコミュニティメンバ、等からのリモートだ。また、関連するグループに名前をつけて定義することもできる：&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="mislav_code"&gt;$ git config remotes.mygroup 'remote1 remote2 ...'&lt;br /&gt;$ git fetch mygroup&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;コミットの注釈を書く&lt;/h2&gt;&lt;pre class="mislav_code"&gt;$ git notes add&lt;br /&gt;&lt;/pre&gt;&lt;pre class="mislav_output"&gt;# 最後のコミットに注釈を追加するためにエディタが開く&lt;br /&gt;&lt;/pre&gt;&lt;div class="mislav_text"&gt;Git の notes は既に存在するコミットへの注釈だ。それらはリポジトリの歴史を変更しないので、どんなコミットにも自由に追加することができる。notes はあなたのリポジトリにしか保存されないが、他のリポジトリと&lt;a class="mislav_link" href="http://lists.zerezo.com/git/msg714256.html"&gt;共有すること&lt;/a&gt;も可能だ。notes には&lt;a class="mislav_link" href="http://lists-archives.org/git/709977-git-notes-notes.html"&gt;興味深いユースケースのアイデア&lt;/a&gt;だってある。&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="mislav_h"&gt;"hub" をインストール&lt;/h2&gt;&lt;div class="mislav_text"&gt;&lt;a class="mislav_link" href="http://mislav.uniqpath.com/hub/"&gt;Hub は Github について Git に教えてくれる&lt;/a&gt;。もし日常的に Github のリポジトリを利用しているなら、あなたは間違いなく hub をインストールしてキーストロークを減らしたくなる――特にあなたがオープンソースに関わっているのなら。&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="color: #AA0000; font-weight: bold"&gt;Gitに関する翻訳記事はこちらもどうぞ： &lt;a class="mislav_link" href="http://keijinsonyaban.blogspot.com/2010/10/successful-git-branching-model.html"&gt;A successful Git branching model を翻訳しました&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;style&gt;.mislav_h {  color: #1C4973;  text-shadow: 1px 1px 3px #1C4973;  border-bottom: none;  border-left: 30px solid #B3C1CD;  padding: 5px 10px;  margin-bottom: 10px;}.mislav_text {  margin-left: 40px;  margin-top: 20px;  margin-right: 20px;  line-height: 1.4em;}.mislav_code {  font-size: 1.2em;  background-color: #DFE7B7;  border-left: 30px solid #8F9B58;  padding: 15px 10px;  margin: 0;  line-height: 1.4em;}.mislav_output {  font-size: 1.1em;  background-color: #222;  color: #D7DFDA;  padding: 15px 10px;  margin: 0;  margin-left: 30px;  line-height: 1.4em;}.mislav_i {  background-color: #DFE7B7;  padding: 2px 4px 2px 4px;  font-family: monospace;}a:link.mislav_link {  color: #CC5D21;  text-decoration: underline;}a:visited.mislav_link {  color: black;  text-decoration: underline;}&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-3983506033889794474?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/3983506033889794474/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/11/git-tips.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/3983506033889794474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/3983506033889794474'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/11/git-tips.html' title='【翻訳】あなたの知らないGit Tips'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-5548393901921730100</id><published>2010-10-30T06:08:00.003+09:00</published><updated>2012-01-24T12:09:16.023+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><title type='text'>A successful Git branching model を翻訳しました</title><content type='html'>Vincent Driessenさんの "&lt;a href="http://nvie.com/posts/a-successful-git-branching-model/"&gt;A successful Git branching model&lt;/a&gt;" を翻訳しました。&lt;br /&gt;元記事はこちら： &lt;a href="http://nvie.com/posts/a-successful-git-branching-model/"&gt;http://nvie.com/posts/a-successful-git-branching-model/&lt;/a&gt;&lt;br /&gt;（翻訳の公開と画像の利用は本人より許諾済みです）&lt;br /&gt;&lt;br /&gt;このブランチモデルの導入を補助してくれる、&lt;a href="http://github.com/nvie/gitflow"&gt;git-flow&lt;/a&gt;というGit用プラグインがあるそうです。&lt;br /&gt;&lt;br /&gt;翻訳の間違い等があれば遠慮なくご指摘ください。&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #333; border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; width: 850px; margin: 0 auto 0 auto"&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-border-radius: 10px; -moz-box-shadow: 1px 1px 3px #000; -webkit-border-radius: 10px; -webkit-box-shadow: 1px 1px 3px #000; border-radius: 10px; border: solid 1px black; box-shadow: 1px 1px 3px #000; margin: 0 auto 0 auto; padding: 10px 20px; width: 630px; background-color: white"&gt;&lt;h1&gt;A successful Git branching model&lt;/h1&gt;&lt;br /&gt;&lt;br /&gt;　この記事では、私の全てのプロジェクト（仕事でもプライベートでも）で約一年ほど導入して、とてもうまくいくことがわかった開発モデルを紹介する。しばらく前からこれについて書くつもりだったんだが、今まですっかりその時間を見つけられずにいた。ここでは私のプロジェクトの詳細については書かず、単にリリース管理のブランチ戦略についてだけ述べよう。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img border="0" height="815" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TMnp-_lNIjI/AAAAAAAAAOw/aR1XP9fYhfA/s815/Screen-shot-2009-12-24-at-11.32.03.png" width="611" /&gt;&lt;/div&gt;&lt;br /&gt;ここではソースコードのバージョニングのためのツール、&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt;に注目する。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;なぜGitか？&lt;/h2&gt;&lt;br /&gt;　中央管理型のソースコード管理システムと比べて、Gitの長所と短所を徹底的に議論するために、&lt;a href="http://whygitisbetterthanx.com/"&gt;webを&lt;/a&gt; &lt;a href="http://www.looble.com/git-vs-svn-which-is-better/"&gt;見て&lt;/a&gt; &lt;a href="https://git.wiki.kernel.org/index.php/GitSvnComparsion"&gt;みよう&lt;/a&gt;。そこではたくさんのディスり合いが続いている。開発者として、私は今ある他の全てのツールより、とりわけGitを好む。Gitは開発者のマージとブランチについての考え方を本当に変えてしまった。私のいた古きよき CVS/Subversion の世界では、マージ／ブランチングはちょっと怖いものと考えられていて（マージの衝突に用心しろ、噛み付かれるぞ！）、しかもそれを時たまだけやっていた。&lt;br /&gt;&lt;br /&gt;しかしGitでは、それらの動作は非常に安く簡単で、日常のワークフローの重要な一部と考えられている。本当に。例えば、 CVS/Subversion の&lt;a href="http://svnbook.red-bean.com/"&gt;本&lt;/a&gt;では、ブランチングとマージは後ろの方の章（先進的ユーザのための章だ）で扱われているが、&lt;a href="http://book.git-scm.com/"&gt;どの&lt;/a&gt; &lt;a href="http://pragprog.com/titles/tsgit/pragmatic-version-control-using-git"&gt;Gitの&lt;/a&gt; &lt;a href="http://github.com/progit/progit"&gt;本でも&lt;/a&gt;、3章（基本的な章だ）では既に扱われている。&lt;br /&gt;&lt;br /&gt;それらの簡潔性と反復的な性質の結果として、ブランチングとマージはもはや恐れるような何かではない。バージョン管理ツールは他のどんな機能よりも、ブランチング／マージを手助けすることがサポートされている。&lt;br /&gt;&lt;br /&gt;さてツールについては十分だ、開発モデルに向かおう。ここで私が紹介しようとしているモデルは、本質的には、管理されたソフトウェア開発プロセスにするために、それぞれのチームメンバが従うべき手続きの集まり以上のものではない。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;分散、しかし中央集権&lt;/h2&gt;&lt;br /&gt;　私たちが使う、そしてこのブランチングモデルでうまく動かすためにセットアップしたリポジトリは、中央の「本当の」リポジトリがついている。このリポジトリは単に中央だとみなしただけのもの、ということに注意して欲しい（Gitは分散バージョン管理システムだから、技術的なレベルでは、中央リポジトリのようなものは存在しない）。私たちはこのリポジトリを origin として参照する。この名前が Git ユーザーには馴染みがあるからだ。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img border="0" height="356" src="http://1.bp.blogspot.com/_KJLBBSxY7xs/TMnp75lIJvI/AAAAAAAAAOg/EcWe1DfhEhw/s478/centr-decentr.png" width="478" /&gt;&lt;/div&gt;&lt;br /&gt;それぞれの開発者は、 origin から pull または push を行う。だが中央管理的な push-pull の関係の他にも、各開発者はサブチームを形成するので、他の同僚から変更を pull することもある。例えば、 origin に対して作業中のものを早まって push する前に、大きな新しい機能を2人以上で一緒に作業することに役立つかもしれない。上の図の中では、 Alice と Bob 、 Alice と David 、そして Clair と David のサブチームがある。&lt;br /&gt;&lt;br /&gt;技術的には、これは Alice が bob という名前の、 Bob のリポジトリを指す Git remote を定義した（逆もまた同様）ことを意味する。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;メインブランチ&lt;/h2&gt;&lt;br /&gt;&lt;div style="float: right; margin-left: 5px"&gt;&lt;img border="0" height="378" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TMnp7AQUQAI/AAAAAAAAAOc/VtcBxp0FTXs/s378/bm002.png" width="254" /&gt;&lt;/div&gt;　開発モデルのコアを成すのは、多くの既存のモデルたちにとてもインスパイアされたものだ。中央リポジトリは永遠の生涯ずっと、２つのメインブランチを保持する：&lt;br /&gt;&lt;br /&gt;　・master&lt;br /&gt;　・develop&lt;br /&gt;&lt;br /&gt;origin の master ブランチは全てのGitユーザーに馴染みがあるはずだ。そして master ブランチに平行する、 develop と呼ばれるもうひとつのブランチが存在する。&lt;br /&gt;&lt;br /&gt;origin/master は、製品として出荷可能な状態を常に反映する、ソースコードの HEAD のありかであるメインブランチだと考える。&lt;br /&gt;&lt;br /&gt;origin/develop は、次のリリースのための最新の開発作業の変更を常に反映する、ソースコードの HEAD のありかであるメインブランチだと考える。これは「統合ブランチ」と呼ぶこともある。これは自動ナイトリービルドのビルド元にもなる。&lt;br /&gt;&lt;br /&gt;develop ブランチのソースコードが安定し、リリースの準備ができたとき、 develop ブランチの全ての変更は master ブランチへマージされ、リリース番号をタグ付けされることになる。（これをどうやるかの詳細は、あとで述べる。）&lt;br /&gt;&lt;br /&gt;したがって、 master へ変更がマージされる時はいつも、その定義からして新しい製品リリースの時だ。私たちはここで非常に厳密になる傾向にあり、そのため理論的には、 master にコミットがあるときは毎回Gitのフックスクリプトで自動ビルドを行い、そしてプロダクションサーバにソフトウェアをロールアウトする。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;サポートブランチ&lt;/h2&gt;&lt;br /&gt;　master と develop のメインブランチの隣で、私たちの開発モデルはチームメンバ間の平行開発を助ける様々なサポートブランチを用い、機能の追跡、製品リリースの準備、製品に起きた問題をすばやく修正すること、などを容易にする。メインブランチと異なり、これらのブランチは寿命が決まっており、使い終わったら最終的には削除される。&lt;br /&gt;&lt;br /&gt;私たちが使う異なるタイプのブランチたちは以下の通り：&lt;br /&gt;&lt;br /&gt;　・Feature branches&lt;br /&gt;　・Release branches&lt;br /&gt;　・Hotfix branches&lt;br /&gt;&lt;br /&gt;それぞれのブランチは特定の目的を持ち、どのブランチから分岐するか、またどのブランチへマージされるのか、という厳密なルールと結びついている。すぐにそれらをお見せできるだろう。&lt;br /&gt;&lt;br /&gt;技術的な見地からすると、これらのブランチは決して「特別な」ものではない。ブランチの種類は、私たちがそれをどう使うかで分類されたものだ。もちろんそれらはどれも、普通のGitブランチだ。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;フィーチャーブランチ&lt;/h3&gt;&lt;div style="float: right; margin-left: 5px"&gt;&lt;img border="0" height="350" src="http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnp8h5hZiI/AAAAAAAAAOk/DQ7WqINZg6s/s352/fb.png" width="133" /&gt;&lt;/div&gt;分岐元： develop&lt;br /&gt;マージ先： develop&lt;br /&gt;ブランチ名の慣習： master, develop, release-*, hotfix-* 以外なら全てOK&lt;br /&gt;&lt;br /&gt;　フィーチャーブランチ（またはトピックブランチとも呼ばれる）は、今度のリリースに入る、または遠い将来のリリースに入るような新しい機能を開発するのに使われる。ある機能を開発し始めるとき、その時点ではその機能を含めるべきリリースがどれなのか不明であるはずだ。フィーチャーブランチの本質は、機能を開発している限りは存在しているが、結局は develop にマージされる（新機能を次のリリースに追加すると決める）か、捨てられる（実験が期待はずれの場合）ということだ。&lt;br /&gt;&lt;br /&gt;フィーチャーブランチは典型的には開発者のリポジトリにだけ存在し、 origin には存在しない。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;フィーチャーブランチの作成&lt;/h4&gt;　新しい機能の作業を始める時、develop ブランチから分岐する。&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout -b myfeature develop&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to a new branch "myfeature"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;開発済みの機能を develop ブランチに取り込む&lt;/h4&gt;　確実に今度のリリースに追加する、開発済みの機能は、develop ブランチにマージされる：&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout develop&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to branch 'develop'&lt;/span&gt;&lt;br /&gt;$ git merge --no-ff myfeature&lt;br /&gt;&lt;span style="color: gray"&gt;Updating ea1b82a..05e9557&lt;br /&gt;(Summary of changes)&lt;/span&gt;&lt;br /&gt;$ git branch -d myfeature&lt;br /&gt;&lt;span style="color: gray"&gt;Deleted branch myfeature (was 05e9557).&lt;/span&gt;&lt;br /&gt;$ git push origin develop&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;--no-ff フラグは、たとえマージがfast-forwardで実行できるとしても、新しいコミットオブジェクトを作成する。これは、履歴にフィーチャーブランチが存在したという情報を失うのを避けるのと、機能の追加に使った全てのコミットをひとまとめにしておける。比べてみよう：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img border="0" height="414" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TMnp-E5P5EI/AAAAAAAAAOs/GKZDTuzeZFE/s463/merge-without-ff.png" width="463" /&gt;&lt;/div&gt;&lt;br /&gt;右の場合、ある機能を実装したコミットオブジェクトをGitの履歴から見つけられない――あなたは全てのコミットログメッセージを手動で見なければならなくなるだろう。機能の全て（例えば、一連のコミット）を revert しなきゃいけないなら、右の状況では本当に頭を痛くさせる。だがもし --no-ff フラグを使用したなら、簡単に終わるのだ。&lt;br /&gt;&lt;br /&gt;確かに、これだとより多くの（空の）コミットオブジェクトを作成するはめになるが、そこから得られるものはコストよりずっと大きい。&lt;br /&gt;&lt;br /&gt;残念ながら、 --no-ff をGitのマージのデフォルトの動作にする方法をまだ見つけてないけれど、それは本当に必要なことだ。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;リリースブランチ&lt;/h3&gt;分岐元： develop&lt;br /&gt;マージ先： develop と master&lt;br /&gt;ブランチ名の慣習: release-*&lt;br /&gt;&lt;br /&gt;　リリースブランチは新しい製品リリースの準備をサポートする。それらは最後の瞬間の詰めをしっかりと行わせてくれる。その上、マイナーなバグフィクスや、リリースのためのメタデータ（バージョン番号、ビルド日時、他）の準備までさせてくれる。これらの全ての作業をリリースブランチ上で行うことで、 develop ブランチは次の大きなリリースのための機能を受け取るために、キレイな体でいられる。&lt;br /&gt;&lt;br /&gt;develop から新しいリリースブランチを分岐する主要なタイミングは、develop ブランチが新しいリリースの望ましい状態を（ほぼ）反映しているときだ。少なくとも、そのリリースのビルドのターゲットとされる全ての機能は、この時点で develop にマージされていなければならない。将来のリリース向けの全ての機能は違う――それらはリリースブランチを分岐させるまでは、まだマージを待っていなければいけない。&lt;br /&gt;&lt;br /&gt;正確には次のリリースがバージョン番号を割り当てられた時が、リリースブランチを始める時だ――それより早くてはいけない。その瞬間までずっと、 develop ブランチは「次のリリース」のための変更を反映するが、リリースブランチを始めるまで、「次のリリース」が結局0.3なのか1.0なのかは不明確だ。その決定はリリースブランチを始める時に、プロジェクトのバージョン番号を増加させるルールに則って、執り行われる。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;リリースブランチの作成&lt;/h4&gt;　リリースブランチは develop ブランチから作成される。例えば、現在の製品リリースがバージョン1.1.5で、大きいリリースが近づいているとしよう。develop が「次のリリース」への準備が出来ている状態で、それをバージョン1.2（1.1.6や2.0ではなく）と決めた。そしたら、ブランチを切って、それに新しいバージョン番号を反映させた名前をつけるんだ。以下のように。&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout -b release-1.2 develop&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to a new branch "release-1.2"&lt;/span&gt;&lt;br /&gt;$ ./bump-version.sh 1.2&lt;br /&gt;&lt;span style="color: gray"&gt;Files modified successfully, version bumped to 1.2.&lt;/span&gt;&lt;br /&gt;$ git commit -a -m "Bumped version number to 1.2"&lt;br /&gt;&lt;span style="color: gray"&gt;[release-1.2 74d9424] Bumped version number to 1.2&lt;br /&gt;1 files changed, 1 insertions(+), 1 deletions(-)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;新しいブランチを作ってそれにスイッチした後、バージョン番号を増加させる。ここでは、 bump-version.sh はワーキングコピーのいくつかのファイルを、新しいバージョン番号を反映させるために変更を行うシェルスクリプトだ（もちろんこれは手動でも可能だ――このポイントは、何かしらのファイルを変更しているってことだ）。それから、バージョン番号の増加をコミットする。&lt;br /&gt;&lt;br /&gt;リリースが確実にロールアウトするまで、この新しいブランチはしばらく存在するかもしれない。この間、バグフィックスがこのブランチに適用される場合もある（develop ブランチではなく）。ここで新しい大きな機能を加えるのは、厳禁だ。それらは develop ブランチにマージする、つまりその次の大きなリリースを待たなくちゃいけない。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;リリースブランチを終える&lt;/h4&gt;　リリースブランチが本当にリリースされてもよい状態になったら、いくつかの動作が実行される必要がある。まず最初に、リリースブランチは master にマージされる（その定義から、master にあるコミットは全て新しいリリースだということを思い出そう）。次に、そのマージコミットにはタグをつけて、後で簡単に見直せるようにしなければならない。最後に、リリースブランチで行われた変更を develop にマージしなくちゃいけない。リリースブランチでやったバグフィックスなんかを将来のリリースに含めるためにね。&lt;br /&gt;&lt;br /&gt;最初の２つのステップはGitだと：&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout master&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to branch 'master'&lt;/span&gt;&lt;br /&gt;$ git merge --no-ff release-1.2&lt;br /&gt;&lt;span style="color: gray"&gt;Merge made by recursive.&lt;br /&gt;(Summary of changes)&lt;/span&gt;&lt;br /&gt;$ git tag -a 1.2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;リリースは完了し、そして後日のためにタグづけされる。&lt;br /&gt;&lt;b&gt;注：&lt;/b&gt; -s または -u &amp;lt;key&amp;gt; フラグを使って、タグに署名をした方が良いでしょう。&lt;br /&gt;&lt;br /&gt;リリースブランチで作られた変更をまた使い続けたいから、 それらを develop にマージする必要があった。Gitでは：&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout develop&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to branch 'develop'&lt;/span&gt;&lt;br /&gt;$ git merge --no-ff release-1.2&lt;br /&gt;&lt;span style="color: gray"&gt;Merge made by recursive.&lt;br /&gt;(Summary of changes)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;このステップは、多分マージのコンフリクトを起こすだろう（ここでは私たちはバージョン番号を変更したから、起きる）。もしそうだったら、修正してコミットしよう。&lt;br /&gt;&lt;br /&gt;今完全にリリースが終わり、もう必要ないので、リリースブランチは削除される：&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git branch -d release-1.2&lt;br /&gt;&lt;span style="color: gray"&gt;Deleted branch release-1.2 (was ff452fe).&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;ホットフィックスブランチ&lt;/h3&gt;&lt;div style="float: right; margin-left: 5px"&gt;&lt;img border="0" height="422" src="http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnp9aAhjkI/AAAAAAAAAOo/std7tYAMZa8/s422/hotfix-branches1.png" width="307" /&gt;&lt;/div&gt;分岐元： master&lt;br /&gt;マージ先： develop と master&lt;br /&gt;ブランチ名の慣習： hotfix-*&lt;br /&gt;&lt;br /&gt;　ホットフィックスブランチは、新しい製品リリースへの準備であるという意味でリリースブランチに似ているが、計画されて行われるわけではない。それらは、現在の製品バージョンの望まざる状態への必要性から発生する。製品バージョンにあるクリティカルなバグがすぐに解決されなければならないとき、ホットフィックスブランチは、そのバージョンのタグがつけられている master のコミットから分岐されることになるだろう。&lt;br /&gt;&lt;br /&gt;その本質は、（develop ブランチ上で）作業しているチームメンバーが作業を続けられながら、別の人間が製品のすばやい修正を準備できることにある。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;ホットフィックスブランチの作成&lt;/h4&gt;　ホットフィックスブランチは master ブランチから作成される。例えば現在の製品バージョンが1.2で、深刻なバグがトラブルを起こしているとしよう。だが develop はまだ不安定だ。ならばホットフィックスブランチを切って、問題を修正し始めるんだ：&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout -b hotfix-1.2.1 master&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to a new branch "hotfix-1.2.1"&lt;/span&gt;&lt;br /&gt;$ ./bump-version.sh 1.2.1&lt;br /&gt;&lt;span style="color: gray"&gt;Files modified successfully, version bumped to 1.2.1.&lt;/span&gt;&lt;br /&gt;$ git commit -a -m "Bumped version number to 1.2.1"&lt;br /&gt;&lt;span style="color: gray"&gt;[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1&lt;br /&gt;1 files changed, 1 insertions(+), 1 deletions(-)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ブランチを切ったあと、バージョン番号を増加させるのを忘れないように！&lt;br /&gt;&lt;br /&gt;それからバグを修正して、一つ以上のコミットを行う。&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git commit -m "Fixed severe production problem"&lt;br /&gt;&lt;span style="color: gray"&gt;[hotfix-1.2.1 abbe5d6] Fixed severe production problem&lt;br /&gt;5 files changed, 32 insertions(+), 17 deletions(-)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;ホットフィックスブランチを終える&lt;/h4&gt;　修正が終わった時、そのバグフィックスを次のリリースにもちゃんと含められるように保護するために、 master にマージされるだけでなく develop にもマージされる必要がある。これはリリースブランチを終える時ととてもよく似ている。&lt;br /&gt;&lt;br /&gt;最初に、master をアップデートして、タグをつける。&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout master&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to branch 'master'&lt;/span&gt;&lt;br /&gt;$ git merge --no-ff hotfix-1.2.1&lt;br /&gt;&lt;span style="color: gray"&gt;Merge made by recursive.&lt;br /&gt;(Summary of changes)&lt;/span&gt;&lt;br /&gt;$ git tag -a 1.2.1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;注：&lt;/b&gt; -s または -u &amp;lt;key&amp;gt; フラグを使って、タグに署名をした方が良いでしょう。&lt;br /&gt;&lt;br /&gt;次に、バグフィックスを develop にも含めさせる。&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git checkout develop&lt;br /&gt;&lt;span style="color: gray"&gt;Switched to branch 'develop'&lt;/span&gt;&lt;br /&gt;$ git merge --no-ff hotfix-1.2.1&lt;br /&gt;&lt;span style="color: gray"&gt;Merge made by recursive.&lt;br /&gt;(Summary of changes)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ここで一つルールの例外があって、リリースブランチがこの時に存在していたら、ホットフィックスの修正を develop の代わりにリリースブランチにマージしなきゃいけない。リリースブランチにバグフィックスをマージすると、リリースブランチを終えたときに結局 develop にも含まれることになる（develop での作業にこの修正がすぐに必要で、リリースブランチを終えるのを待てないなら、今ここでも develop にマージする場合もある）。&lt;br /&gt;&lt;br /&gt;最後に、一時的なブランチを削除しよう：&lt;br /&gt;&lt;br /&gt;&lt;pre class="waku_a"&gt;$ git branch -d hotfix-1.2.1&lt;br /&gt;&lt;span style="color: gray"&gt;Deleted branch hotfix-1.2.1 (was abbe5d6).&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;まとめ&lt;/h2&gt;&lt;br /&gt;　このブランチモデルには驚くような新しいことは一つもないが、この記事の最初の「大きな絵」は、私たちのプロジェクトにものすごく役立つと判明した。それは理解しやすいエレガントなメンタルモデルを形成し、チームメンバーにブランチングと、リリースプロセスの理解の共有を発展させる。&lt;br /&gt;&lt;br /&gt;高品質な図のPDF版はここに用意した。持って行って、そしていつでもクイックリファレンスとして壁に掛けておいて欲しい。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/downloads/nvie/gitflow/Git-branching-model.pdf"&gt;&lt;div style="text-align: center;"&gt;&lt;img border="0" width="128" height="128" src="http://3.bp.blogspot.com/_KJLBBSxY7xs/TMoOwx_-BSI/AAAAAAAAAO0/7PJdQs16WFc/s128/pdf.png" /&gt;&lt;/div&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;更新：それと誰かがリクエストしていたので：ここに &lt;a href="http://github.com/downloads/nvie/gitflow/Git-branching-model-src.key.zip"&gt;gitflow-model.src.key &lt;/a&gt;として主な図の画像を置く（Apple Keynote）。&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #AA0000; font-weight: bold"&gt;Gitに関する翻訳記事はこちらもどうぞ： &lt;a style="text-decoration: underline; color: black" href="http://keijinsonyaban.blogspot.com/2010/11/git-tips.html"&gt;【翻訳】あなたの知らないGit Tips&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-5548393901921730100?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/5548393901921730100/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/10/successful-git-branching-model.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/5548393901921730100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/5548393901921730100'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/10/successful-git-branching-model.html' title='A successful Git branching model を翻訳しました'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_KJLBBSxY7xs/TMnp-_lNIjI/AAAAAAAAAOw/aR1XP9fYhfA/s72-c/Screen-shot-2009-12-24-at-11.32.03.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-6442313013402461088</id><published>2010-10-09T01:36:00.006+09:00</published><updated>2011-11-29T00:04:52.378+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='YAML'/><title type='text'>Ruby1.9.2で日本語を含むYAMLを出力する時、バイナリ文字列化されないようにする</title><content type='html'>&lt;h3&gt;RubyのYAML&lt;/h3&gt;Ruby(1.8以上)ではYAMLライブラリが標準添付ライブラリです。&lt;br /&gt;そのため、YAMLを扱うには「require 'yaml'」とするだけです。&lt;br /&gt;&lt;br /&gt;これでYAML.load（YAML形式から読み込み）、YAML.dump（YAML形式への出力）、&lt;br /&gt;さらに様々なオブジェクトで to_yaml メソッドが使えるようになります。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;日本語を含むYAMLを出力&lt;/h3&gt;しかしこのままでは、日本語文字列を含んだオブジェクトを&lt;br /&gt;YAMLドキュメントとして出力すると、日本語部分がバイナリ文字列になってしまいます。&lt;br /&gt;これでは人間にも読みやすいというYAMLの特徴が台なしです。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-&lt;br /&gt;require 'yaml'&lt;br /&gt;&lt;br /&gt;puts YAML.dump({'あ' =&amp;gt; 'い'}) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# 【出力結果】&lt;br /&gt;# --- &lt;br /&gt;# "\xE3\x81\x82": "\xE3\x81\x84"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これを解消する方法を軽く検索してみると、&lt;br /&gt;gemで違うYAMLライブラリを入れるとか、パッチをあてるなどの情報が出てきます。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ruby1.9.2では：Psych&lt;/h3&gt;Ruby1.9.2からは、PsychというYAMLパーサも標準添付ライブラリになっています。&lt;br /&gt;（以前からあるのは、Syckというライブラリ）&lt;br /&gt;このPsychは「require 'yaml'」するだけでは有効にならないので、以下のようにします。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-&lt;br /&gt;require 'yaml'&lt;br /&gt;&lt;br /&gt;YAML::ENGINE.yamler = 'psych'&lt;br /&gt;&lt;br /&gt;puts YAML.dump({'あ' =&amp;gt; 'い'})&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# 【出力結果】&lt;br /&gt;# ---&lt;br /&gt;# あ: い&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;今度は日本語がバイナリ文字列化されませんでした。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;この方法はTwitter上で &lt;a href="http://twitter.com/sakuro"&gt;@sakuro&lt;/a&gt; さんに教えて頂きました。&lt;br /&gt;ありがとうございました！&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;（2010年10月9日夜に追記↓）&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;&lt;/span&gt;&lt;br /&gt;YAML::ENGINE.yamlerを使わなくとも、「yamlの前にpsychがロードされていればOK」とのことです。&lt;br /&gt;つまり以下の方法でも良いということになります。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-&lt;br /&gt;require 'psych' # 追加&lt;br /&gt;require 'yaml'&lt;br /&gt;&lt;br /&gt;puts YAML.dump({'あ' =&amp;gt; 'い'})&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# 【出力結果】&lt;br /&gt;# ---&lt;br /&gt;# あ: い&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;上記の追記はTwitterで &lt;a href="http://twitter.com/n0kada"&gt;@n0kada&lt;/a&gt; さんに教えて頂きました。感謝です！&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;ちょっと実験&lt;/h4&gt;require 'psych'だけではどうでしょうか。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-&lt;br /&gt;require 'psych'&lt;br /&gt;&lt;br /&gt;puts YAML.dump({'あ' =&amp;gt; 'い'})&lt;br /&gt;&lt;br /&gt;# 【出力結果】&lt;br /&gt;# uninitialized constant Object::YAML (NameError)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;エラーになります。YAMLは使えません。&lt;br /&gt;&lt;br /&gt;ではrequire 'yaml'が先で、require 'psych'が後だったら？&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-&lt;br /&gt;require 'yaml'&lt;br /&gt;require 'psych'&lt;br /&gt;&lt;br /&gt;puts YAML.dump({'あ' =&amp;gt; 'い'})&lt;br /&gt;&lt;br /&gt;# 【出力結果】&lt;br /&gt;# --- &lt;br /&gt;# "\xE3\x81\x82": "\xE3\x81\x84"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Syckが使われてしまうようです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;1.9.2なのにPsychが使えないよ？&lt;/h3&gt;Ruby1.9.2なのにPsychが使えない場合は、 libyaml-dev を入れてからRubyを再コンパイルしましょう（パッケージ名は、Ubuntu 等の場合）。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Psychという名前&lt;/h3&gt;Psyc&lt;span style="color: red;"&gt;h&lt;/span&gt;であってPsyc&lt;span style="color: red;"&gt;k&lt;/span&gt;じゃないんですね。&lt;br /&gt;前のライブラリがSyc&lt;span style="color: red;"&gt;k&lt;/span&gt;なのでちょっと紛らわしい。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ruby1.9.3では（2011年11月28日追記）&lt;/h3&gt;コメントで教えて頂いた情報によると、&lt;br /&gt;Ruby1.9.3からは、Psychの方がデフォルトになっているようです。&lt;br /&gt;ですので、require 'yaml' 以外に余計な事を書かなくても、日本語を正しく扱うことができます。&lt;br /&gt;&lt;br /&gt;逆に Syck を使いたい場合は、YAML::ENGINE.yamler='syck' としなければなりません。&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-6442313013402461088?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/6442313013402461088/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/10/ruby192yaml.html#comment-form' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6442313013402461088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6442313013402461088'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/10/ruby192yaml.html' title='Ruby1.9.2で日本語を含むYAMLを出力する時、バイナリ文字列化されないようにする'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-5295222752110847970</id><published>2010-09-13T21:24:00.000+09:00</published><updated>2010-09-13T21:24:08.030+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Rubyのprivateメソッドルールの例外</title><content type='html'>&lt;h3&gt;privateメソッドのルール&lt;/h3&gt;&lt;a href="http://www.amazon.co.jp/dp/4048687158"&gt;『メタプログラミングRuby』&lt;/a&gt;P.65のコラムに、&lt;br /&gt;privateメソッドのルールについて書かれていました。&lt;br /&gt;&lt;br /&gt;　&lt;i&gt;”プライベートメソッドには1つのシンプルなルールが適用される。それは、「明示的なレシーバをつけてプライベートメソッドを呼び出すことはできない」というものだ。つまり、プライベートメソッドは、暗黙的なレシーバselfに対するものでなければならない。”&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;「privateメソッドは、明示的なレシーバをつけられない」。&lt;/b&gt;&lt;br /&gt;レシーバがない状態といえば、「（暗黙的に）selfをレシーバとする状態」しかないわけですから、&lt;br /&gt;通常はそのprivateメソッドを持っているオブジェクトからじゃないとメソッドを参照する経路がありません。&lt;br /&gt;これによってRubyのprivateメソッドが「プライベートな」存在になるのですね。&lt;br /&gt;（本気を出せば破ってしまえますが、それはまた別の話。）&lt;br /&gt;&lt;br /&gt;これはわかりやすい覚え方です。&lt;br /&gt;具体的に、極端な例を試してみると以下のようになります。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;class A&lt;br /&gt;  def foo&lt;br /&gt;    self.bar&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  private&lt;br /&gt;&lt;br /&gt;  def bar&lt;br /&gt;    puts "bar is private method"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;A.new.foo # =&gt; error&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;例え同じクラス内からでも、明示的にレシーバ（ここではself）を&lt;br /&gt;書いてしまうとエラーが起きます。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ルールの例外&lt;/h3&gt;しかし、このルールには例外が一つあります。&lt;br /&gt;それは&lt;b&gt;「セッターメソッドには明示的なレシーバが必要」&lt;/b&gt;、ということです。&lt;br /&gt;（セッターメソッドというのは、メソッド名が「=」で終わるもののこと）&lt;br /&gt;&lt;br /&gt;先程の例を、privateメソッドをセッターメソッドに変えてやってみましょう。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;class B&lt;br /&gt;  def foo&lt;br /&gt;    self.bar = 1&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  private&lt;br /&gt;&lt;br /&gt;  def bar=(arg)&lt;br /&gt;    puts "bar= is private method"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;B.new.foo # =&gt; "bar= is private method"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この通りエラーが起きません。&lt;br /&gt;privateメソッドがセッターメソッドの場合には、&lt;br /&gt;明示的にレシーバを書いてもよいのです。&lt;br /&gt;&lt;br /&gt;というよりも、明示的にレシーバを書かないとおかしなことになるからです。&lt;br /&gt;以下にそれを示します。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;class C&lt;br /&gt;  def foo&lt;br /&gt;    bar = 1 # ただのローカル変数の代入と見なされる&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  private&lt;br /&gt;&lt;br /&gt;  def bar=(arg)&lt;br /&gt;    puts "bar= is private method"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;C.new.foo # =&gt; 当然何も起こらない&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;セッターメソッドには明示的なレシーバが必要。&lt;br /&gt;また、それはメソッドがprivateでもpublicでも変わることはありません。&lt;br /&gt;&lt;br /&gt;この、privateメソッドのルールの例外については、&lt;br /&gt;Twitterで &lt;a href="http://twitter.com/n0kada"&gt;@n0kada&lt;/a&gt; さんに教えていただきました。ありがとうございました。&lt;br /&gt;&lt;a href="http://twitter.com/n0kada/status/11625643920"&gt;http://twitter.com/n0kada/status/11625643920&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-5295222752110847970?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/5295222752110847970/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/09/rubyprivate.html#comment-form' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/5295222752110847970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/5295222752110847970'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/09/rubyprivate.html' title='Rubyのprivateメソッドルールの例外'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-7692687657060580468</id><published>2010-09-07T08:49:00.000+09:00</published><updated>2010-09-07T08:49:02.518+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>RubyでNoMethodError時にObject#inspectが使われている</title><content type='html'>&lt;a href="http://rubykaigi.org/2010/ja"&gt;RubyKaigi2010&lt;/a&gt;での関 将俊さんの発表で聞いた話。&lt;br /&gt;&lt;br /&gt;dRubyアプリケーション(RWiki)にirbから接続した時、&lt;br /&gt;メソッド名の打ち間違えをするとなんだかとても遅い。&lt;br /&gt;&lt;br /&gt;原因は、NoMethodError時にObject#inspectが走っており、&lt;br /&gt;たくさんのデータ（配列やハッシュに入った数万のオブジェクト）を抱えているオブジェクトを&lt;br /&gt;見えるように印字したらそりゃ遅いよねという話だった。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;ruby-1.9.2-p0 &gt; Object.new.does_not_exist_method&lt;br /&gt;NoMethodError: undefined method `does_not_exist_method' for #&amp;lt;Object:0x00000001088288&amp;gt;&lt;br /&gt; from (irb):1&lt;br /&gt; from /home/oshow/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `&amp;lt;main&amp;gt;'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;ruby-1.9.2-p0 &gt; class Object&lt;br /&gt;ruby-1.9.2-p0 ?&gt;  def inspect&lt;br /&gt;ruby-1.9.2-p0 ?&gt;    "HELLO"&lt;br /&gt;ruby-1.9.2-p0 ?&gt;  end&lt;br /&gt;ruby-1.9.2-p0 ?&gt;end&lt;br /&gt; =&gt; nil &lt;br /&gt;&lt;br /&gt;ruby-1.9.2-p0 &gt; Object.new.does_not_exist_method&lt;br /&gt;NoMethodError: undefined method `does_not_exist_method' for HELLO:Object&lt;br /&gt; from (irb):7&lt;br /&gt; from /home/oshow/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `&amp;lt;main&amp;gt;'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;確かに、「for #&amp;lt;Object:0x00000001088288&amp;gt;」ってところが&lt;br /&gt;「for HELLO」に変わった。inspectが使われているらしい。&lt;br /&gt;&lt;br /&gt;実際にも、関さんはObject#inspectを再定義して遅くなるのを回避したそうです。&lt;br /&gt;（しかたなく…らしい（笑）。&lt;a href="http://www.nicovideo.jp/watch/sm11932774"&gt;発表の動画&lt;/a&gt;を見るとわかります）&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-7692687657060580468?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/7692687657060580468/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/09/rubynomethoderrorobjectinspect.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/7692687657060580468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/7692687657060580468'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/09/rubynomethoderrorobjectinspect.html' title='RubyでNoMethodError時にObject#inspectが使われている'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-6841798616777218771</id><published>2010-09-05T23:37:00.005+09:00</published><updated>2010-10-25T00:57:54.237+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu10.04でデスクトップに流れる音声を録音したい</title><content type='html'>インターネットラジオや生配信の音声を録音しておきたい、ということがあると思います。&lt;br /&gt;Ubuntuには標準でサウンドレコーダーがついていますが、&lt;br /&gt;ブラウザ等で音声を流しながらこれを使って録音してみても、&lt;br /&gt;そのままでは何も録音することができません。&lt;br /&gt;&lt;br /&gt;標準のサウンドレコーダーで録音できるようにするためには、&lt;br /&gt;以下のような作業が必要です。&lt;br /&gt;&lt;br /&gt;まず、padevchooserをインストールします。&lt;br /&gt;&lt;pre class="waku"&gt;$ sudo apt-get install padevchooser&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;次に「アプリケーション」→「サウンドとビデオ」→「PulseAudio Device Chooser」を起動。&lt;br /&gt;パネルの通知領域にアイコンが出てくるので、左クリックして「Manager...」を選択。&lt;br /&gt;&lt;br /&gt;Devicesタブの中のSourcesに「alsa_output〜」というものがあるので、&lt;br /&gt;選択して右下の「Properties」ボタンを押す。&lt;br /&gt;&lt;br /&gt;出てきたウィンドウの中の、Nameに書かれている内容をコピー。&lt;br /&gt;自分の場合は「alsa_output.pci-0000_00_1b.0.analog-stereo.monitor」でした。&lt;br /&gt;&lt;br /&gt;Managerを閉じたら、もう一度パネルのアイコンを左クリックして&lt;br /&gt;「Default Source」→「Other...」を選択。&lt;br /&gt;&lt;br /&gt;出てきたウィンドウに先程コピーした内容を張り付けて、OKを押します。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;これで、標準のサウンドレコーダーを使って、&lt;br /&gt;デスクトップに流れている音声を録音できるようになりました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;参考： &lt;a href="http://blog.livedoor.jp/penguin_drummer/archives/51406745.html"&gt;recordMyDesktopでデスクトップを録画してみる on Ubuntu 9.10&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #AA0000"&gt;（2010年10月25日　追記）&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://gihyo.jp/admin/serial/01/ubuntu-recipe/0137?skip"&gt;こちらの記事&lt;/a&gt;に書かれている方法でもよいようです。&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-6841798616777218771?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/6841798616777218771/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/09/ubuntu1004.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6841798616777218771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6841798616777218771'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/09/ubuntu1004.html' title='Ubuntu10.04でデスクトップに流れる音声を録音したい'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-411391217083519980</id><published>2010-03-03T22:53:00.019+09:00</published><updated>2010-12-30T06:33:14.741+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rvm'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu9.10作業メモ6：rvmを使って複数バージョンのRubyを同時に利用する</title><content type='html'>&lt;div&gt;&lt;a href="http://rvm.beginrescueend.com/"&gt;rvm&lt;/a&gt;（Ruby Version Manager）を使うと、複数バージョンのRubyの&lt;/div&gt;&lt;div&gt;同時利用が非常に簡単にできます。&lt;/div&gt;&lt;div&gt;1.8.7と1.9.1を切り替えて使ったり、最新の1.9.2のtrunkを試してみたり、&lt;br /&gt;JRuby・Ruby Enterprise Editionのような異なる処理系のRubyを管理する&lt;br /&gt;といったことが手軽に出来るようになります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;主な効能としては、以下のようなものがあります。&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;コマンド一発で新しいRubyをインストール、アンインストール&lt;/li&gt;&lt;li&gt;元からシステムに入っているRubyの環境を一切汚さない（全てのファイルは $HOME/.rvm/ の下に格納）&lt;/li&gt;&lt;li&gt;ディレクトリに設定ファイル（.rvmrc）を置くことで、そのディレクトリ下でrubyコマンドが実行されたときに呼び出されるバージョンを指定できる&lt;/li&gt;&lt;li&gt;あるスクリプトに対して、インストール済みの全てのRubyをまとめて走らせられる&lt;/li&gt;&lt;li&gt;同様のことがrakeでも可能なので、例えばrake specを全Rubyで試すといったことができる&lt;/li&gt;&lt;li&gt;ある一つのバージョンのRubyに対して複数のgem環境を使い分けるGem Sets機能（例えば1.9.1に対して複数のrailsのバージョンを切り替える等ができる）&lt;/li&gt;&lt;li&gt;他多数&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;なお、現在rvmは頻繁にアップデートを繰り返していますので、&lt;/div&gt;&lt;div&gt;説明した動作と異なる可能性もあることに注意してください。&lt;/div&gt;&lt;div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;執筆時点のrvmのバージョンは、0.1.21です。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;ちなみに、Windowsにも似たソフトとして、&lt;a href="http://github.com/vertiginous/pik/"&gt;pik&lt;/a&gt;というものがあるそうです。&lt;/div&gt;&lt;div&gt;（上記に挙げた機能と同じものが全て存在するかは、わかりませんが）&lt;/div&gt;&lt;div&gt;&lt;br /&gt;この記事では、rvmをインストールし、rvm経由でRuby1.8.7と1.9.1をインストールし、&lt;br /&gt;それらが切り替えられるのを確認するところまでやってみます。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;それでは、rvmをインストールしてみましょう。&lt;/div&gt;&lt;div&gt;&lt;a href="http://rvm.beginrescueend.com/rvm/install/"&gt;rvmの公式サイトのインストール手引き&lt;/a&gt;を見ると、Githubからのインストールが&lt;br /&gt;オススメとありますので、ここではそれで進めてみます。(Gitが必要です)&lt;br /&gt;&lt;br /&gt;公式サイトには何やら長いコマンドが書いてありますが、要するに&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;$ git clone git://github.com/wayneeseguin/rvm.git&lt;br /&gt;$ cd rvm&lt;br /&gt;$ ./install&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;という手順が守られていれば問題はありません。&lt;br /&gt;公式の手引きで、 $HOME/.rvm/src に対してgit cloneしようとするのは、&lt;br /&gt;rvm本体に備わったアップデート機能を使うとどうせまたそこにgit cloneされるからだと思われます。&lt;br /&gt;&lt;br /&gt;また、git cloneに対して「--depth 1」&lt;span class="Apple-style-span" style="color: #555555; font-family: monospace; line-height: 22px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: 'Times New Roman'; line-height: normal; white-space: normal;"&gt;というオプションがついているのは、&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #555555; font-family: monospace; line-height: 22px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: 'Times New Roman'; line-height: normal; white-space: normal;"&gt;要は「私はリポジトリをいじったりしないから、履歴とかなしで&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #555555; font-family: monospace; line-height: 22px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: 'Times New Roman'; line-height: normal; white-space: normal;"&gt;最新のリビジョンのファイルだけコピーしてください」という指定です。&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #555555; font-family: monospace; line-height: 22px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: 'Times New Roman'; line-height: normal; white-space: normal;"&gt;その方がダウンロードする容量が少なくて済むという配慮でしょう。&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #555555; font-family: monospace; line-height: 22px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: 'Times New Roman'; line-height: normal; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #555555; font-family: monospace; line-height: 22px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: black; font-family: 'Times New Roman'; line-height: normal; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;さて、installスクリプトの実行が完了すると色々とメッセージが表示されます。&lt;br /&gt;&lt;br /&gt;重要なのは後半の「You must now finish the install manually:」以下の部分です。&lt;br /&gt;指示通り、そこに表示された一行をシェルの設定ファイルの最後に書き込みましょう。&lt;br /&gt;自分の場合は、 $HOME/.bashrc の最後に以下を書き込みました。（人によって内容が違うはずです）&lt;br /&gt;&lt;pre&gt;if [[ -s /home/oshow/.rvm/scripts/rvm ]] ; then source&amp;nbsp;/home/oshow/.rvm/scripts/rvm ; fi&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #990000;"&gt;（※2010年12月30日追記：現在は以下のような一行を追加せよと指示されます。意味は同じです）&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;[[ -s "$HOME/.rvm/scripts/rvm" ]] &amp;&amp; source "$HOME/.rvm/scripts/rvm"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;もう一つ重要なのは、rvmでRubyをインストールする際に必要なパッケージ類の説明です。&lt;br /&gt;rvmではRubyのインストールは基本的にソースからのビルドなので、&lt;br /&gt;ビルドのためのパッケージを準備しなければなりません。&lt;br /&gt;ここでは普通に1.8.7と1.9.1をインストールしたいので、&lt;br /&gt;「* &amp;nbsp;For MRI &amp;amp; ree (if you wish to use it) you will need:」と書かれた行を探してみてください。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ aptitude install curl bison build-essential zlib1g-dev libssl-dev libreadline5-dev libxml2-dev git-core&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;と書かれています。これらがビルドに必要なパッケージです。&lt;br /&gt;自分の場合はGitが既に入っているので、それを除いて、&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;$ sudo aptitude install curl bison build-essential zlib1g-dev libssl-dev libreadline5-dev libxml2-dev&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;のように実行しました。&lt;br /&gt;&lt;br /&gt;また、上記の説明文を見逃してしまっても、&lt;br /&gt;rvmのアップデートコマンド（ rvm update --head ）を使う度に見れますので安心してください。&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #990000;"&gt;（※2010年6月8日追記：現在は rvm notes コマンドで見られるようです。）&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #990000;"&gt;（※2010年12月30日追記：rvm update --head というコマンドは古くて、現在は rvm get head を使うようです。）&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;以上で準備が整ったので、rvmを使っていきましょう。&lt;br /&gt;rvmを使い始める前に、端末を一旦閉じて開き直してください。&lt;br /&gt;&lt;br /&gt;まずrvm経由のRubyのインストールです。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ rvm install 1.8.7&lt;br /&gt;$ rvm install 1.9.1&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;このようにバージョンを指定するだけでインストールが可能です。&lt;br /&gt;ダウンロード→ビルドと実行されるので、それなりに時間がかかります。&lt;br /&gt;完了したら、バージョンを切り替えられることを確認してみましょう。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ rvm use 1.8.7&lt;br /&gt;$ ruby -v&lt;br /&gt;ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-linux]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;$ rvm use 1.9.1&lt;/div&gt;&lt;div&gt;$ ruby -v&lt;/div&gt;&lt;div&gt;&lt;div&gt;ruby 1.9.1p378 (2010-01-10 revision 26273) [i686-linux]&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;となるはずです。&lt;/div&gt;&lt;div&gt;元々入っているRubyに戻すには、&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;$ rvm use system&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;とします。&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;----&lt;br /&gt;&lt;br /&gt;rvmの実体はシェルスクリプトの集合体です。rvmはシェルに対して細工を行います&lt;br /&gt;（例えば、cdコマンドを再定義する等）。その辺りが気にかかる方は、十分考慮してから利用してください。&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-411391217083519980?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/411391217083519980/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/03/ubuntu9106rvmruby.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/411391217083519980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/411391217083519980'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/03/ubuntu9106rvmruby.html' title='Ubuntu9.10作業メモ6：rvmを使って複数バージョンのRubyを同時に利用する'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-4750557019638405628</id><published>2010-02-17T19:47:00.006+09:00</published><updated>2012-02-03T18:34:21.749+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu9.10作業メモ5：Gitをソースからインストール</title><content type='html'>分散バージョン管理システムである&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt;をソースからインストールしてみます。&lt;div&gt;執筆時点の最新バージョンは1.7.0です。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;Linux等では普通、パッケージ管理システムを使ってソフトをインストールします。&lt;/div&gt;&lt;div&gt;そうすることで現在何がインストールされているか把握でき、&lt;/div&gt;&lt;div&gt;統一的な操作でアップデートやアンインストールができ、&lt;/div&gt;&lt;div&gt;ソフトウェア同士の依存関係の問題も起こりにくくなります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ソフトウェアをソースから自分でインストールする場合はそれらの恩恵が&lt;/div&gt;&lt;div&gt;受けられなくなる代わりに、パッケージ管理システムが用意していない最新版を&lt;/div&gt;&lt;div&gt;インストールすることができます。メリットとデメリットを考えて実行してください。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Ubuntuでソフトウェアをソースからインストールする場合、&lt;a href="http://paco.sourceforge.net/"&gt;paco&lt;/a&gt; などを使って&lt;/div&gt;&lt;div&gt;インストールの事実を管理すると良いようですが、ここでは特に考えずにインストール手順を示します。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;ソースからインストールするということは、インストール作業は持ってきたファイルを&lt;/div&gt;&lt;div&gt;コピーするだけでは済まず、ビルドというコンパイルも含んだ作業ができなければなりません。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;あるソフトをビルドするのに何が必要なのかは、そのソフトによります。&lt;/div&gt;&lt;div&gt;通常はそのソフトのインストール手順書などを見てビルドの準備をしますが、&lt;/div&gt;&lt;div&gt;ここでは楽をしてパッケージ管理システムの機能を利用しましょう。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ubuntuでは、最初からパッケージ管理システムにやや古い版のGitが用意されています。&lt;/div&gt;&lt;div&gt;「git-core」というものがそれです。ここにGitがあるということは、&lt;/div&gt;&lt;div&gt;Gitをビルドするのに必要なソフト類をパッケージ管理システムは知っていることになります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;これを利用して、「Gitをビルドするのに必要なソフト類を選択してインストールしてください」&lt;/div&gt;&lt;div&gt;というように指示することができます。以下の通りです。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;div&gt;$ sudo apt-get build-dep git-core&lt;/div&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;これで、ビルドの準備が整いました。&lt;/div&gt;&lt;div&gt;（この方法は、&lt;a href="http://www.amazon.co.jp/dp/4798023809"&gt;『入門Git』&lt;/a&gt;の記述からお借りしました。）&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;　&lt;span style="color: #AA0000"&gt;【2012年2月3日追記】&lt;/span&gt;&lt;br /&gt;　現在ではパッケージ名は「git-core」ではなく「git」になっているようです。&lt;br /&gt;　ですので、「sudo apt-get build-dep git」と実行します。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;それではGit本体のインストールです。&lt;/div&gt;&lt;div&gt;&lt;a href="http://git-scm.com/"&gt;Gitの公式サイト&lt;/a&gt;から最新版をダウンロードして解凍し、解凍したディレクトリに移動してください。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ここではドキュメント類も一緒にビルドします。&lt;/div&gt;&lt;div&gt;また、システム全体で使うように /usr/local へインストールします。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;div&gt;$ ./configure&lt;/div&gt;&lt;div&gt;$ make prefix=/usr/local all doc&lt;/div&gt;&lt;div&gt;$ sudo make install install-doc&lt;/div&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="color: #AA0000"&gt;【2010年11月19日追記】&lt;/span&gt;&lt;br /&gt;以下の方がいいかもしれません。&lt;br /&gt;&lt;pre class="waku"&gt;$ ./configure --prefix=/usr/local&lt;br /&gt;$ make all doc&lt;br /&gt;$ sudo make install install-doc&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;以上です。&lt;/div&gt;&lt;div&gt;インストールに成功したか確認してみましょう。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;div&gt;$ git --version&lt;/div&gt;&lt;div&gt;git version 1.7.0&lt;/div&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;となるはずです。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-4750557019638405628?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/4750557019638405628/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9105git.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/4750557019638405628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/4750557019638405628'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9105git.html' title='Ubuntu9.10作業メモ5：Gitをソースからインストール'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-8318631471623209429</id><published>2010-02-16T15:06:00.004+09:00</published><updated>2010-02-16T15:18:06.751+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu9.10作業メモ4：nautilus-open-terminalを使って対象ディレクトリからターミナルを簡単に開く</title><content type='html'>Ubuntuの標準のファイラーはNautilusというエクスプローラ風のものですが、&lt;div&gt;これを使ってディレクトリを操作している際に、対象のディレクトリを現在位置として&lt;/div&gt;&lt;div&gt;ターミナルを開きたくなるということがあります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;対象ディレクトリの場所を覚えておいてから、普通にターミナルを立ち上げて&lt;/div&gt;&lt;div&gt;cdコマンドで移動するのは少々不便です。そこで、Nautilusの方から一発で&lt;/div&gt;&lt;div&gt;ターミナルを開けるようにしてくれるソフトウェアがあります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;それが nautilus-open-terminal です。Synapticで探してインストールすると、&lt;/div&gt;&lt;div&gt;Nuatilusでディレクトリアイコンを右クリックしたときのメニューに&lt;/div&gt;&lt;div&gt;「Open in Terminal」というものが増えています。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;これで、対象のディレクトリを現在位置としてターミナルを開くことができるようになります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-8318631471623209429?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/8318631471623209429/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9104nautilus-open-terminal.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/8318631471623209429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/8318631471623209429'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9104nautilus-open-terminal.html' title='Ubuntu9.10作業メモ4：nautilus-open-terminalを使って対象ディレクトリからターミナルを簡単に開く'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-6704612066230560218</id><published>2010-02-15T11:16:00.004+09:00</published><updated>2010-02-15T11:39:54.120+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu9.10作業メモ3：UbuntuTweakを使って標準以外のソフトウェアをインストール</title><content type='html'>UbuntuにはUbuntu Tweakという便利なソフトがあります。&lt;div&gt;Windowsでいうところの「窓の手」のようなソフトでしょうか。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;標準のメニューからでは設定しにくい部分をカスタマイズしたり、&lt;/div&gt;&lt;div&gt;元々用意されている以外のアプリケーションのインストールを手助けしてくれます。&lt;/div&gt;&lt;div&gt;例えば、Firefoxの最新版、GoogleChromeの最新版、Chromiumのデイリービルド、&lt;/div&gt;&lt;div&gt;Dropbox、Skypeなどが簡単にインストールでき、目的のリポジトリを探し回る手間を省けます。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;それでは、UbuntuTweakをインストールしてみましょう。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;「システム」→「システム管理」→「ソフトウェア・ソース」を開きます。&lt;/div&gt;&lt;div&gt;「他のソフトウェア」タブで「追加」ボタンを押して&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ppa:tualatrix/ppa&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;を追加します。その後、Synapticで「ubuntu-tweak」を検索してインストールします。&lt;/div&gt;&lt;div&gt;UbuntuTweakは、「アプリケーション」→「システムツール」の所に入ります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;試しに、UbuntuTweakからGoogleChromeをインストールしてみましょう。&lt;/div&gt;&lt;div&gt;UbuntuTweakを立ち上げたら左側のメニューから「ソースセンター」を選びます。&lt;/div&gt;&lt;div&gt;「Browser」の中にある「Google Stable Source」をチェックして「更新」を押します。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;次に左側のメニューの「アプリケーションセンター」を選ぶと、&lt;/div&gt;&lt;div&gt;「Brwoser」の中で「Google-Chrome-Beta」と「Google-Chrome-Unstable」というのが&lt;/div&gt;&lt;div&gt;選べるようになっていると思います。&lt;/div&gt;&lt;div&gt;好みの方をチェックして、「適用」ボタンを押してください。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;また、当然ですが、UbuntuTweakで追加したソース・リポジトリにあるソフトは、&lt;/div&gt;&lt;div&gt;Synapticの方にも現れるようになります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-6704612066230560218?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/6704612066230560218/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9103ubuntutweak.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6704612066230560218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/6704612066230560218'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9103ubuntutweak.html' title='Ubuntu9.10作業メモ3：UbuntuTweakを使って標準以外のソフトウェアをインストール'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-50349567359869669</id><published>2010-02-14T15:57:00.007+09:00</published><updated>2010-02-14T18:54:51.263+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu9.10作業メモ2：.Xmodmapを使ってキーバインドを変更する</title><content type='html'>Ubuntuでは、 $HOME/.Xmodmap ファイルに設定を書き込むことで&lt;div&gt;キーバインドを変更することができます。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;設定を書くためには、変更したいキーを特定するための&lt;/div&gt;&lt;div&gt;「番号」あるいは「呼び方」がわからなければなりません。&lt;/div&gt;&lt;div&gt;この「番号」と「呼び方」がキーコードとKeySym名です。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;キーコードとKeySym名を調べるためには、xevコマンドを使います。&lt;/div&gt;&lt;div&gt;端末で xev と打つとキーボードやマウスの操作内容が端末に&lt;/div&gt;&lt;div&gt;反映されるようになるので、他の箇所に触らないように目的のキーを押してください。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;例えば自分の環境でEnterキーを押すと以下のように表示されました。&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;br /&gt;KeyRelease event, serial 36, synthetic NO, window 0x5200001,&lt;br /&gt;root 0x109, subw 0x0, time 96083768, (110,502), root:(701,553),&lt;br /&gt;state 0x10, keycode 36 (keysym 0xff0d, Return), same_screen YES,&lt;br /&gt;"   XLookupString gives 1 bytes: (0d) "&lt;br /&gt;XFilterEvent returns: False&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;ここでは、keycodeと書かれている横にある「36」がキーコード、&lt;/div&gt;&lt;div&gt;keysymと書かれている横にある「Return」がKeySym名になります。&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;キーの特定方法がわかったところで設定の具体的な書き方ですが、&lt;/div&gt;&lt;div&gt;普通のキーとAlt／Ctrl／Shift／Superキー／Caps Lockキー（修飾キー）では&lt;/div&gt;&lt;div&gt;書き方が少し異なります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;普通のキーを塗り替えたい場合は、&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;keycode [keycode] = [keysym]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;と書きます。[keycode]の所にxevで調べたキーコード、&lt;/div&gt;&lt;div&gt;[keysym]の所にxevで調べたKeySym名を指定するわけです。&lt;/div&gt;&lt;div&gt;これで、=の左のキーコードに指定したキーが、&lt;/div&gt;&lt;div&gt;=の右のKeySym名で指定したキーに変わります。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;もしくは&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;keysym [keysym] = [keysym]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;という書き方もあるようです。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;次に、修飾キーが絡む場合ですが、こっちはaddとremoveを使って&lt;/div&gt;&lt;div&gt;修飾キーの機能をキーに付加したり外したりします。&lt;/div&gt;&lt;div&gt;キーを塗り替えるのとは考え方が違うので注意してください。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;修飾キーの機能を取り去るには、&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;remove [修飾キー名] = [keysym]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;修飾キーの機能を付加するには&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;add [修飾キー名] = [keysym]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;とります。=の右側で指定したキーが修飾キーになる（ならなくなる）キーです。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;修飾キー名ですが、ターミナルで xmodmap -pm と打った時に&lt;/div&gt;&lt;div&gt;左側に並んでいるshift、lock、control、mod1などのことです。&lt;/div&gt;&lt;div&gt;また、このコマンドで現在の修飾キーの割り当てがわかるので、参考にしてください。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;設定を書き終わったら一旦ログインしなおすとキーバインドが反映されるはずです。&lt;/div&gt;&lt;div&gt;もっと詳しく調べたい場合は、「xmodmap」等で検索してみてください。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-50349567359869669?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/50349567359869669/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9102xmodmap.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/50349567359869669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/50349567359869669'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9102xmodmap.html' title='Ubuntu9.10作業メモ2：.Xmodmapを使ってキーバインドを変更する'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2310485404319956884.post-8834994178805032177</id><published>2010-02-14T09:28:00.007+09:00</published><updated>2010-02-14T17:01:13.797+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu9.10作業メモ1：本家版のCDで英語でインストールした場合に日本語入力をする</title><content type='html'>&lt;div&gt;Ubuntuには日本語環境にカスタマイズされたバージョンのイメージが用意されています。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ubuntu Japanese Team&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.ubuntulinux.jp/"&gt;http://www.ubuntulinux.jp/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;これを利用してUbuntuをインストールするか、Ubuntu Japanese Team様が用意した&lt;/div&gt;&lt;div&gt;リポジトリから日本語セットアップヘルパをインストールすることでも&lt;/div&gt;&lt;div&gt;日本語環境を使用することができます。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;しかし、以上の方法を用いない本家版のCDイメージのみでも、&lt;/div&gt;&lt;div&gt;日本語入力を行うことは可能です。&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;（ただ、Ubuntu Japanese Team版では「日本語入力」以外にも様々な日本語向け&lt;/div&gt;&lt;div&gt;　カスタマイズがされているので、普通はそちらを使った方がいいと思います）&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;やり方は、「System」→「Administration」→「Language Support」を選択し、&lt;div&gt;日本語をインストールしてメニューを日本語に変更するだけです。&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;ただし、&lt;/b&gt;この作業を行う前に自分でiBusの設定をいじっていると、&lt;/div&gt;&lt;div&gt;Language Supportから日本語に変更しても何故かうまく日本語入力できません。&lt;/div&gt;&lt;div&gt;（ひらがな入力はできるけど、スペースキーを押しても変換できない）&lt;/div&gt;&lt;div&gt;本当は後からでもちゃんとした設定方法があるのかもしれませんが…&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ということで、本家版を使うけどとりあえず日本語入力だけをやりたいという場合は、&lt;/div&gt;&lt;div&gt;まっさきにLanguage Supportから日本語に変更すると、日本語入力ができるようになります。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2310485404319956884-8834994178805032177?l=keijinsonyaban.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keijinsonyaban.blogspot.com/feeds/8834994178805032177/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9101cd.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/8834994178805032177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2310485404319956884/posts/default/8834994178805032177'/><link rel='alternate' type='text/html' href='http://keijinsonyaban.blogspot.com/2010/02/ubuntu9101cd.html' title='Ubuntu9.10作業メモ1：本家版のCDで英語でインストールした場合に日本語入力をする'/><author><name>O-Show</name><uri>http://www.blogger.com/profile/00810605240730990712</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_KJLBBSxY7xs/TMnppi5-sBI/AAAAAAAAAN8/ELJQCsfGCOM/S220/kin_normal.png'/></author><thr:total>0</thr:total></entry></feed>
