ラベル ツール の投稿を表示しています。 すべての投稿を表示
ラベル ツール の投稿を表示しています。 すべての投稿を表示

2014年10月22日水曜日

vimdiffで単語単位の差分表示: diffchar.vimが超便利

今日もプログラミングや文書作成にvimを巧みに操り続ける全国のvimmerの皆様におかれましては、vimを利用した差分表示であるvimdiffは欠かせないツールであることと思います。

当方も今までvimdiffについては色を見やすくしたり差分計算アルゴリズムを賢くしたりと、カスタマイズによって使い勝手を向上させてきましたが、唯一実現できていなかったのが、「単語単位の差分表示」なのであります。

しかしついに、vimdiffで単語単位の差分を表示できるようにするvimプラグイン「diffchar.vim」を先日見つけました。最初の公開が今年5月という新しいプラグインです。
diffchar.vim - Highlight the exact differences, based on characters and words : vim online

ということで、早速インストール。このプラグインはGithubにもミラーされており、すでにNeoBundleをお使いであれば導入はとっても簡単で次の一行を.vimrcに追加して ":NeoBundleInstall" するだけです。それ以外の場合については省略。

NeoBundle 'vim-scripts/diffchar.vim'

実際サンプルで試してみましょう。まず、vimdiffで差分を表示させると、次のようになりますね。


一つの行に複数箇所の変更が含まれる場合も、最初の変更から最後の変更までを含むような大きな1つの変更として認識されてしまっています。

しかしここで<F7>キーを押すと!


うおおおおぉ!すばらしい。単語単位の差分を表示できました。一行に複数の変更があってもちゃんと認識して表示。しかも、追加部分と変更部分で色分けもされています。

ちなみに、再度<F7>キーを押すと元に戻ります。なお、<F7>キーは文書全体について単語単位の差分表示を切り替えますが、<F8>キーを押すと現在の行のみ単語単位の差分表示を切り替えることができます。

これだけでも便利ですが、欲を言えば、vimdiffコマンド実行時やgit diftoolにvimdiffを使っている時に、いちいち<F7>を押すのは面倒。そんな時には、

" vimdiffで起動した際自動的に単語単位の差分(diffchar.vim)を有効にする
if &diff
  augroup enable_diffchar
    autocmd!
    autocmd VimEnter * execute "%SDChar"
  augroup END
endif

と.vimrcに書いておけばOK。vimdiffコマンドで起動した時には自動的に単語単位の差分が有効になります。(この場合、単語単位の差分をOFFにしたければ<F7>キーを押す、という使い方になります。)

これでvimdiffで差分をチェックする作業が一層はかどりますね。

※補足:autocmdのイベントはFilterWritePost、BufReadPost 、BufWinEnterなども試しましたが、FilterWritePostでは効果がなく、BufReadPostやBufWinEnterだとどうやらdiff表示途中に実行されてしまうらしく余計な箇所まで単語単位で差分表示しようとしてしまい表示が崩れます。VimEnterを指定したら期待した動作になりました。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年8月8日金曜日

gitコミットとRedmineチケットは1対1にする

ソフトウェア開発のプロジェクトでgit(あるいはSubversion)を使っていない方が珍しいと思います。と同時に、極めてよく使われるツールがRedmineなどのプロジェクト管理ツールですね。

昔はバグトラッキングシステム(BTS)と呼ばれていましたが、バグの管理はもちろんのこと、プロジェクトのタスク管理につかうシステムとしても非常に優れており、広く使われるようになったことから最近では "プロジェクト管理ソフトウェア" などと呼ばれているようです。BTSに変わる決まった呼び方があるのかどうかはよく知りません。

ともあれ、git と redmine を連携させて使っているプロジェクトも多いことでしょう。Redmine 上のプロジェクトには git のリポジトリを関連付けることができ、gitのコミットメッセージにチケット番号を特定の書式で書くと、自動的にRedmine上のチケットとgitのコミットが関連付けされます。チケットの表示画面にgitコミットの概要とリンクが表示され、またコミットの表示画面ではチケットへのリンクが表示されます。これは後からソースコードの変更を確認したいときに、タスクの記録と一緒に追うことができて大変便利です。

ところで、1つのチケットに複数のコミットを関連付けることもできます。また逆に1つのコミットに複数のチケットを関連付けることもできます。ただし、僕の意見としては、極力チケットとコミットを1対1に対応させると、後から過去の変更を調べる際にすごく楽になります。(当然完全には無理でしょうから、出来る限りということです。)

例えば、1つのコミットに複数のチケットに関する変更を入れてしまうと、それらの変更がそれぞれどのチケットに関するものか判別するのは、変更した本人でない限り結構手間がかかるものです。あるいは、1つのチケットの解決に要した変更が複数のコミットにまたがっていると、これまたどんな変更がそのチケットに関連してなされたのかの結論を確認するのに骨が折れます。

だから、チケットとコミットを1対1に対応させるのがよいのです。もちろん、自分の手元でコミットを1回きりで済ませるのは大変だと思いますので、例えばローカル専用ブランチを作ってそこにコミットし、1つのチケットの分がまとまったら提出用ブランチにmerge --squash でまとめるといった方法をとればよいと思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月25日金曜日

git diffって多用するよね

git diffは非常によく使うコマンドの1つで、僕の仕事のクオリティを支えてくれているツールでもあります。また、difftoolにvimdiffを用いたgit difftoolも同じくらいよく使います。

僕はかなりこまめにgit diffを使います。プログラミングをしていると、ちょっと書いたらgit diffで差分を見て、動作確認し、またちょっと書く、みたいな感じです。差分を確認せずに一気に書くことはほとんどないです。

あとコミット前にはインデックスとHEADの差分をgit diffとgit difftoolの両方で確認します。ここで原則として差分については全て余すところなく確認します。

あと、ローカルブランチのコミットをgit merge --squashでまとめて提出用ブランチにした際も、提出用ブランチの直前との差分を確認しますが、この際はざっと目を通す感じですね。

こんな感じです。実に利用シーンは多いです。ちなみに差分アルゴリズムはhistogramがおすすめです。difftoolにvimdiffを用いる場合に、差分作成アルゴリズムを変更する方法については過去の記事を参照。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月13日日曜日

gitのpush前にmerge --squashとpullとrebaseを

gitでどうブランチを切ってコミット・プッシュするかの運用方法については様々な意見というか流派(?)があるように思います。僕自身も複数人数のチームで開発を実際に行う中で、こうしたらいいんじゃないかって思っている方法を書いてみようと思います。

まず開発のタスク管理にはredmineを使っている、という背景があります。gitの共有リポジトリはredmineと連携させていて、共有リポジトリにプッシュしたコミットのメッセージにチケット番号を記載しておくと、自動的にredmineのチケットからリポジトリビューアにリンクされるようになっています。そのような背景から、チケットごとにコミットを1つにまとめています。

さらに、共有リポジトリへプッシュする際は、自分の名前が付けられたブランチにプッシュすることにしています。(masterへのマージはmasterブランチ管理者以外は行わない。)例えば僕はkasaiという名前のブランチを作成して、そこへ自分が担当するチケットを解決するコミットを行い、それを共有リポジトリへプッシュします。

masterブランチ管理者は、共有リポジトリへプッシュされた他の担当者のブランチをローカルリポジトリへプルしてmasterへのマージを行い、改めて共有リポジトリへプッシュします。(つまり、共有リポジトリのmasterへのプッシュを行えるのはmasterブランチ管理者だけです。)

この辺までは結構よくある運用方法でしょうね。ここまで全体的な流れの話を書きましたが、次に、各担当者が個人的に行う運用方法についてです。

僕の場合、ローカルリポジトリにはローカル用ブランチを作って作業しています。ローカル用ブランチは自分のためだけのブランチで、一度行った変更を後のコミットで元に戻したり、試行錯誤の汚い履歴が混在していて、そのまま共有リポジトリにプッシュするなんて考えられない代物です。ちなみに僕はローカル用ブランチには local/yy.mm.dd という名前を付けています(yy.mm.ddは作成時の日付、1日に複数作成した場合はyy.mm.dd-2などとする)。

とういことで、ローカル用ブランチで試行錯誤して、完成したら提出用ブランチ(前述した例ではkasai)にまとめて取り込むという方法を採っています。その際にはmerge --squashを使います。

なお、提出用ブランチにmerge --squashされた後のローカル用ブランチは消してもいいのですが、バックアップの意味もあるし、コードが動かなくなった際に履歴が残っていると原因究明にも役立ったり、元に戻したりできるので残しておくことにしています。

では、提出用ブランチをこのままpushすればいいかというと、ちょっと考えるべき問題があります。pushする前に、共有リポジトリのmasterに、自分が元にした時点から変更がいくつも加わっている場合、コミット内容がmasterと競合しないにもかかわらず、仕様変更によりコードが動かなくなってしまう可能性があります。例えば、他人の担当範囲で定義されていた関数やメソッドを呼び出してコードを書いたが、自分がローカルで作業している間に、その関数やメソッドの挙動を変えるコミットがmasterに既にマージされていた、といった場合です。(この問題に関してはGitユーザマニュアルの「マージコミットの分割が1本線の履歴の分割よりも困難となる理由」の解説が分かりやすいです。)

だから、push直前に、最新のmasterを改めてpullで取得し、その最新のmasterにこれからpushしようとする変更を統合した状態で動作することを確認しておきたいんですね。そのためにrebaseを行ます。つまりpush直前に、自分のブランチをpullで取得した最新のmaster上にrebaseするのです。

こうすることで、上記のようにmaster側に知らないうちに仕様変更が加わっていて、競合が発生しないにもかかわらずコードが動かなくなる、という事態に陥る危険性を(ゼロではないにしても)かなり減らすことができます。また、もしそのような事態になったとしても、rebaseしておくことで原因の究明はぐっとやりやすくなります(当然ながら、これはpush前のコミットだからrebaseしてもいいのであって、たとえ提出用ブランチでも、一旦pushした後のコミットは決してrebaseしてはいけません)。

まとめると、こういう流れになります。
  1. ローカル用ブランチを作成し開発を行う。コミットは適宜好きなように行う。
  2. 提出用ブランチにてmerge --squash でローカル用ブランチの変更をまとめて取り込む。まとめる単位はredmineのチケット単位とする。
  3. masterブランチにてpullで共有リポジトリの最新の状態を取り込む。
  4. 提出用ブランチにてrebaseで変更を最新のmaster上に移し替える。
  5. rebaseされた提出用ブランチにて共有リポジトリへpushする。
  6. (masterブランチ管理者のみ) 各担当者の提出用ブランチブランチをpullし、ローカルでmasterへのマージを行い、共有リポジトリへpushする。
これが今のところいいんじゃないかと思っている方法です。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月8日火曜日

vimdiffでより賢いアルゴリズム(patience,histogram)を使う

vimdiff使ってますか?差分を取る際には非常に便利ですよね。git difftoolに設定して使っている人も多いと思います。しかしgit diffは差分計算のアルゴリズムを選択できますが、vimdiffはデフォルトでは差分計算のアルゴリズムを選択できません。

git diffの差分アルゴリズムには標準のもの以外にpatienceやhistogramがあり、より人間に読みやすい差分を表示してくれる「賢い」アルゴリズムになっています。それぞれgit diffコマンドのオプション--patienceや--histogramを付けるか、または~/.gitconfig設定ファイルにアルゴリズムを指定することで利用できます。

具体的なアルゴリズムの詳細は僕も詳しくないですが、patienceアルゴリズムは「ファイル内でユニークかつ比較ファイル同士で一致する行をなるべく"変化していない行"と認識する」よう働きます。また、histogramアルゴリズムは「patienceアルゴリズムの基本的ルールを継承しつつ高速化を図ったアルゴリズム」で、多くのファイルでpatienceアルゴリズムと同一の結果が得られるようです。また、histogramアルゴリズムはEclipseに統合されたGitクライアントEGit(が使うJGit)の標準アルゴリズムです。僕はコマンドラインツールのgitにおいてもhistogramアルゴリズムを使ってます。

さて、vimdiffにおいてもhistogramアルゴリズムを使いたいところです。vimの設定ではvimdiffの差分計算に使用するコマンドをdiffexprという設定値で指定できます。そして、git diffコマンドも--no-indexオプションを指定することでdiffコマンドと同じようにスタンドアロンツールとして利用できます。じゃあ、diffexprにgit diff --no-indexを指定すればいいのか・・・というと実はそれだけでは失敗します。

理由は、vimがdiffexprに設定したコマンドから受け付ける差分形式が、diffコマンドのnormal形式かed形式でなければならないからです(vimのヘルプにはed形式とだけ書いてあるのですが、normal形式も受け付けます)。そして、git diffコマンドでは直接diffコマンドのnormal形式やed形式で出力することができずunified形式のみに対応しています。

そこで、unified形式をnormal形式に変換するrubyスクリプトを書いて使うことにしました。以下がその変換スクリプトです。利用にはrubyが必要です。

#!/usr/bin/env ruby
iwhite = ''
if (ARGV[0] == '-b')
  iwhite = ARGV.shift.dup << ' '
end

diffout = `git diff --no-index --no-color -U0 #{iwhite}#{ARGV[0]} #{ARGV[1]}`
diffout.sub!(/\A.*?@@/m, '@@')
diffout.gsub!(/^\+/, '> ')
diffout.gsub!(/^-/, '< ')
diffout.gsub!(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@.*/) do
  before_start = $1
  before_size = $2
  after_start = $3
  after_size = $4

  action = 'c'
  if (before_size == '0')
    action = 'a'
  elsif (after_size == '0')
    action = 'd'
  end

  before_end = ''
  if (before_size && before_size != '0')
    before_end = ",#{before_start.to_i + before_size.to_i - 1}"
  end

  after_end = ''
  if (after_size && after_size != '0')
    after_end = ",#{after_start.to_i + after_size.to_i - 1}"
  end

  "#{before_start}#{before_end}#{action}#{after_start}#{after_end}"
end
diffout.gsub!(/^(<.*)(\r|\n|\r\n)(>)/, '\1\2---\2\3')
print diffout

上記スクリプトを~/bin/git-diff-normal-formatとして保存し、~/binにPATHを通しておきます。そしたら、.vim設定ファイルに次の記述を追加します。

" diffのコマンド
set diffexpr=MyDiff()
function MyDiff()
  let opt = ""
  if &diffopt =~ "iwhite"
    let opt = opt . "-b "
  endif
  silent execute "!git-diff-normal-format " . opt . v:fname_in . " " . v:fname_new . " > " . v:fname_out
  redraw!
endfunction

最後に、git diffで使うアルゴリズムを指定します。下記記述ではgit difftoolで起動するコマンドにvimdiffを指定する設定も一緒に行っています。

[diff]
  tool = vimdiff
  algorithm = histogram

これでvimdiffやgit difftoolを実行した時にhistogramアルゴリズムが使えるようになります(patienceを使いたい場合は、上記設定のalgorithmの値をpatienceに変えてください)。

では具体的な効果を見てみましょう。サンプルとして用意した2つの比較対象のファイルをvimでウィンドウを分割して並べたものが下の画像です(クリックで拡大できます)。


まずは、今回の設定をする前、デフォルトのアルゴリズムでvimdiffによる差分をとった結果が以下です(クリックで拡大できます)。


そして、今回の設定をした後の、histogramアルゴリズムでvimdiffによる差分をとった結果が以下です(クリックで拡大できます)。


こちらのほうが、より差分内容も分かりやすく、かつ実際に手で行った変更の操作に近いものになっていますね。
※ちなみにこのvimdiffの色設定は過去に書いたこの記事を参照。

※2014/07/10更新:diffupdateを実行した際に画面の描画がおかしくなることがあったので、回避のためMydiff()にredraw!を追加

※参考記事
Making your Git Diff/Merge More Useful | The Interim Developer
Alfedenzo - Patience Diff, a brief summary
Bram Cohen's Journal - Patience Diff Advantages
HistogramDiff (JGit - Core 2.0.0.201206130900-r API)

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年7月4日金曜日

gitでマージの事前に衝突するかどうか確認する

gitを使っていて、特定のブランチとマージしたら衝突が起きないかどうか知りたい場合があります。例えば、プロジェクトチームで共有しているリポジトリにコミットをプッシュする前に、現在作業中のブランチがmasterブランチと衝突を起こさないか確認しておきたい、なんて場合です。

そんな時は、mergeコマンドの —no-commit オプションで master をマージしてコミットせずに止めてみればいいです。あとで簡単に元に戻せます。(本来確かめたい向きとは逆向きのマージですが、衝突の確認をするだけなら結果は同じですから問題ありません。)

[user@host]% git merge master --no-commit
Auto-merging /some/file/path
Automatic merge went well; stopped before committing as requested

同一ファイルに編集があったが、自動的にマージされた場合には上記のような表示になります。衝突を起きて自動的に解決できない場合はその旨がここで表示されるはずです。

確認は終わりましたが、そのままではワーキングツリーとインデックスが変更されたままですので、元に戻します。mergeコマンドの --abort オプションを使えばいいです。

[user@host]% git merge --abort

これで元通り。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年5月21日水曜日

Rubyのコメント形式とYARD

PHPの時はPhpDoc形式のコメントをIDEが読み取って連携してくれるという事情もあり、ソースコードにはPhpDoc形式のコメントをつけるようにしてました。このPhpDocでは様々なタグを付けることができて、例えば関数の引数は@paramタグで指定できたりします。

ではRubyの場合はどうかと思って、今さらながら調べてみました。Rubyの場合、ソースコード内に記述するコメントのパーサとしてはRDocが代表的みたいですね。

調べてみると、RDocのコメントには、特に関数の引数や引数の型を指定する形式とか、そういうのはないみたいです。ちょっとイメージが湧かないので、有名なライブラリのソースコードをあたってみました。

ActiveRecordの場合、クラスやモジュールの先頭にガッツリ長文で説明が例も交えて解説してあります。

Rackの場合、ドバっと書いてあるファイルと、全然書いてないファイルの差が激しいです。まあ、必要なとこだけ絞って書いてあるんでしょう。

正直、決まりとか慣例とかあまり無いように思いました。うーん、自由に書けばいいのかなぁ。

などと思っていたら、どうやら、PhpDocに似たYARDってのがあるらしいじゃないですか。
※詳細はリンク先参照。
参考1 http://d.hatena.ne.jp/kitamomonga/20110825/ruby_yardoc_tag
参考2 http://morizyun.github.io/blog/yard-rails-ruby-gem-document-html/

そうそう、こういうのを探してたわけですよ。これならPhpDocと同じような感覚で書けますね。YARD自体の解説は上記リンク先に素晴らしい解説があるのでここではしませんが、やっぱりソースコードにコメントを入れるものとしては引数と戻り値を指定するタグくらいはあって欲しいわけで、そういう意味ではYARDはバッチリですな。

というわけで、今後YARD形式でコメントを書いていこうと思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年5月1日木曜日

さあ、IEを捨てよう

さて、IE(Internet Explorer)のVer6〜11という幅広いバージョンに影響のある脆弱性が見つかり、さらにXPはサポート終了につきマイクロソフトは対応する予定も当然ない、というニュースが流れてますね。

いい機会です。もういい加減にIEやめましょう。と言いますかまだIE使ってるなんて勘弁して下さい。ましてやIE6とか、もう化石かと突っ込みたくなります。

もちろん、脆弱性が修正されないまま放置されるPCが多く出現するという状況自体は憂慮すべきことなのかもしれませんが、これを切っ掛けに皆がIEに見切りをつけ、FirefoxやChromeなどの他のブラウザに乗り換えてくれるなら(特にXPユーザが)、Web系エンジニアにとっては大変喜ばしい状況になるという側面も出てくるる気がします。そうなってほしい。

それにしても、IE6の呪縛が本当の意味で終わるまでにこんなに時間がかかるとは・・・。僕の周囲ではかなり消えつつありますが、まだゴキブリ並みのしつこさで生き残っている場所はあるんでしょうねぇ。ほんと、早く消えて欲しいものです。

さあ、今こそIEを捨てる時。ChromeかFirefoxに乗り換えよう。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月26日土曜日

一人プロジェクトでもGitは役に立つ

ちょいと先日ある人が、「一人でやってるとGitもあまりありがたみがない」なんてことを言ってましたけれども、そんなことは無いと思いますよ。

そういう僕も昔はSubversionしか知らなくて、Gitを知った時もメリットが理解できず、移行したのは単に「将来性がありそうだから」くらいの理由だったんですがね。使ううちに、「これは明らかにGitに優位性がある」と実感できるようになりました。さらに、「たとえ一人のプロジェクトだとしてもやはりGitは有効活用できる」と思ってます。

ポイントは、リモートリポジトリとローカルリポジトリの使い分けにあります。開発中は色々と試行錯誤をしながら進めていくものですが、それらをコミットしていくと、結構変更が入り乱れてきます。一段落したところで変更をまとめてスッキリさせたいと思うわけですよ。

そういう時に、ローカルリポジトリに試行錯誤のためのブランチを作ってそこでにコミットしていき、一段落したところで、それらの変更をまとめて改めて別のブランチにコミットします。具体的には、以前この記事に書いたような merge --squash を使う方法が有用です。リモートリポジトリにプッシュするのは変更をまとめたブランチのみとしておけば、リモートリポジトリのコミットログもスッキリし、分かりやすくなります。

そういえば、ブランチの概念もSubversionとGitでは全然違いますよね。Subversionだとブランチはあくまで派生であって、trunkを更新するのが基本。Gitの方はmasterとは別のブランチにコミットして、masterにマージして取り込む、というのがよくあるパターンです。ですので一人プロジェクトでも気軽にブランチを切っていきます。

というわけで、一人プロジェクトでもGitは相当役に立ちますよ、という話でした。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月10日木曜日

Vim使いにもお勧めするEclipseの併用方法

もともと昔から開発はEclipseで行っていましたが、今はRubyを書いていくのがVimの方がやりやすいため、コードはVimで書いています。さらに、gitのコミットなどの操作もEclipseからではなく、ターミナル上のgitコマンドで行うようにしています(こちらは、Eclipseはシンボリックリンクを含むgitリポジトリの扱いにバグがあるため)。

逆に、Eclipseを使っていない人もいると思うんですよね。僕の周囲にはそういう人も居ます。確かに、Vimとターミナル上の各種コマンドで全てのことはできるっちゃできるんですが、Eclipseを併用すると色々な場面で効率を上げることができます。

僕がEclipseで活用している機能のうち、特に役立つと思うものをいくつか紹介します。

・ファイル検索

grepコマンドやfindコマンドでも同様のことができますが、Eclipseは結果表示の一覧性が良く、結果からエディターのヒット箇所へジャンプしつつ、結果を次々と見ていけたりできます。検索範囲をファイルツリーから選ぶのも直感的にできますし、使える正規表現もgrepより多いです。
操作方法:プロジェクト・エクスプローラ上で、検索したい範囲を選択した上でメニューから「検索>検索...」を選びます。

・gitヒストリー(コミットグラフ)の閲覧

これがあるからEclipseを併用していると言っても過言ではないです。gitのコミットグラフを可視化するツールはいくつも試しましたが、Eclipse(の標準プラグインEGit)が一番綺麗で見やすいと思います。
操作方法:プロジェクト・エクスプローラ上でプロジェクトのトップディレクトリを右クリックして「チーム>ヒストリーに表示」を選びます。

・gitコミット直前の確認ダイアログ

コミットする際に変更のあったファイル一覧は、ターミナル上でgitコマンドによるコミットを行う場合も出てきますけれども、Eclipseの場合ダイアログが表示されて変更のあったファイルと変更の種類を一覧で出すとともに、その一覧のファイルをダブルクリックすると、コミットしようとしている差分を表示してくれます。僕はここで差分だけ確認したらキャンセルして、実際のコミット操作はターミナル上のgitコマンドで行っています。
操作方法:プロジェクト・エクスプローラ上でプロジェクトのトップディレクトリを右クリックして「チーム>コミット...」を選びます。

・ディレクトリ単位での比較

比較結果がディレクトリ構造にのっとってツリー状に表示されるため、変更箇所が分かりやすいです。
操作方法:プロジェクト・エクスプローラ上で比較したい2つのディレクトリを選択した状態で右クリックして「比較>相互」を選びます。

他にも色々機能はありますが、上で述べた機能が最もよく使いますし、これらだけでも使いこなせば、Vimとターミナルだけで開発を進めるよりも一段高い生産性を発揮できることでしょう。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月2日水曜日

Eclipse EGitでサブモジュールを含むリポジトリが常に変更ありになる件

Eclipse の EGit プラグインでは、サブモジュールを含むリポジトリをチェックアウトすると、まだ何も変更していないはずなのに、変更ありのマークが付くという不可思議な状況になります。

最初はいきなり変更ありのマークが付いて何かミスったのかと思いましたが、やり直しても変わらないのでEGitがおかしいってことですね。

ちなみにシンボリックリンクも同じように変更していないはずなのに変更ありのマークが就いてしまいます。

調べてみたら、どうやらEgitが使うgitのJava上の実装であるJGitのバグのようです。シンボリックリンクの扱いが原因みたいですね。

https://bugs.eclipse.org/bugs/show_bug.cgi?id=391280

Eclipseはクロスプラットフォームである以上、シンボリックリンクの扱いをどうするのかは難しい問題なのかもしれません。上記リンク先を見ると、まだバグの対処は手付かずのようです。

仕方ないのでとりあえず、僕は端末上から git コマンドを併用することにしています。ステータスを見る時やgit コマンドによる各種操作はEclipseでなく端末上の git から行うようにしています。Eclipseはヒストリー(コミットグラフ)が見やすいのと、コミット時に出る、変更一覧を選択して差分を見るダイアログが見やすいので、実際のコミットは行わずコミット時のダイアログだけ見るといった使い方をしています。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年3月29日土曜日

VimとEmacs両方に慣れておくべき理由

エディタ界の2大巨塔といえば、言わずと知れた Vim と Emacs でございますが、まあ僕は不毛な宗教論争に関わるつもりはありませんので、どっちを使うべきだなんて言うつもりは毛頭ございません。

学生時代にUnix/Linuxに触って最初に使ったエディタがEmacsでした。その頃はVimは全く使わず、Emacsで全てのテキスト編集を行っていた時期が2年くらい続いたと思います。Lispでカスタマイズも色々やりました。

ある時とある先輩にVimを強力にお勧めされて使い始め、慣れるために卒論を全部Vimで書いたことでVim使いになりました。慣れるまでには結構苦労しましたけど、慣れると便利ですよね。プログラミングをするなら断然Vim派です。普段使うエディタはVimになっていきました。

こんな経緯があって、両方のキー操作の流儀を身に付けたんですが、普段エディタとしてはVimを使っていますが、Emacsのキー操作でテキストを編集することも結構あるのです。

例えばメールを書く時は、昔はメーラー、今はGmailを使いますけれども、この時はEmacsのキー操作を使います。WindowsでしたらAutoHotKeyなんかで結構簡単に実現できますし、MacだとデフォルトでEmacs風のキー操作を受け付けてくれます。。それに限らず、テキストエディタ以外の部分でのテキスト入力はほぼすべてEmacsのキー操作でやっています。

その上で、テキストエディタはVimですね。カーソル移動やコピー&ペースト、入力などを使いこなすと非常に便利で、繰り返しになりますけれどもプログラミングをするなら断然Vimが快適です。

ということで、Emacs風のキー操作とVim風のキー操作の両方に慣れておくと、状況に応じて使い分けられて便利ですよ、という話でした。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年3月28日金曜日

vimdiffの色設定を変更して見やすくする(黒背景用)

Linuxにおける差分表示ツールとしてはdiffコマンドがありますけれども、複雑な変更になってくるとvimdiffが使いやすい場面も多々あるわけでございます。特に横に並べて比較できるのは大きなメリットですよね。

ところが、デフォルトの設定ですと結構色が見辛いわけで、何とかしたいわけです。ちょっと検索して調べてみましたが、自分が思うような色設定がどっかに載ってたりとかしなかったので、自分で設定してみることにしましたよ。いつも黒背景で使っておりますので、そこに最適化してあることにご注意ください。

というわけで、下記の記述を .vimrc に加えればOKです。

" vimdiffの色設定
highlight DiffAdd    cterm=bold ctermfg=10 ctermbg=22
highlight DiffDelete cterm=bold ctermfg=10 ctermbg=52
highlight DiffChange cterm=bold ctermfg=10 ctermbg=17
highlight DiffText   cterm=bold ctermfg=10 ctermbg=21

これでvimdiffコマンドを実行するとこのようになります。


背景の色を差分の種類によって分けており、追加行は緑、削除行は赤、変更行は青で変更部分が明るい青になってます。

これでだいぶ見やすくなるんじゃないかと思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年3月27日木曜日

Macの端末内Vimで挿入モード時カーソル形状切り替え

Macで端末を起動してリモートにSSH接続し、Vimでソースコードを編集するって使い方を普段良くするんですけれども、以前からの不満の1つが挿入モードの時のカーソル形状を切り替えできないことでした。

MacVimであれば、ノーマルモードのカール形状はブロックで、挿入モードの時はカーソル形状が垂直バーとなります。これにより現在が挿入モードかどうかすぐ分かりますし、文字が挿入される位置も見やすくなります。

で、端末上で起動するVimにしても、実はカーソル形状の切り替えができるらしいことが調べてわかったんですが、いかんせんMacのOS X標準で用意されている"ターミナル.app"は、カーソル形状の切り替えに対応していないようです。しかしながら、"iTerm2"という端末アプリが対応しているらしいとのこと。

ということで、標準の"ターミナル.app"から"iTerm2"へ乗り換えるとともに、カーソル形状をモードによって切り替える設定をしました。

iTerm2のインストールと設定


下記からダウンロードして解凍し、出てきたアプリを直接「アプリケーション」フォルダにドラッグ&ドロップしてください。
http://www.iterm2.com/#/section/home

設定は好みですが、プロファイルの以下の部分は重要と思われますので書いておきます。

「Text」タブ
Treat ambiguous-width characters as double width にチェック → これにチェックを入れておかないと、□や◯といった記号の混じった文章がおかしくなります。

「Window」タブ
Disable session-initiated window resizing のチェックを外す → ウィンドウサイズを変更した時に追随させるにはチェックを外します。

「Terminal」タブ
Save lines to scrollback in alternate screen mode のチェックを外す → Vim起動中にウィンドウサイズを変更した場合に、Vim終了後の端末ヒストリーがおかしくならないようにするにはチェックを外す必要があります。

Report Terminal Type: "xterm-256color"に設定 → デフォルトだと"xterm"ですが、カラー表示が一部不完全になるので、この設定に変更します。

「Key」タブ
ターミナル上でMac側のショートカットキーが効かなくなる場合がありますので、ここで設定して回避します。僕の場合、日本語/英数の入力切り替えに使うキーを効くようにするために次のように設定しました。
Ctrl+Shift+J → Do not Remap Modifiers
Ctrl+Shift+: → Do not Remap Modifiers

Vimの設定


さて、カーソル形状をモードによって切り替えるには、下記の設定を.vimrcに記述してVimを再起動します。

" 挿入モードでカーソル形状を変更する
let &t_SI.="\e[6 q"
let &t_EI.="\e[2 q"
" カーソル形状がすぐに元に戻らないのでタイムアウト時間を調整
set ttimeoutlen=10
" 挿入モードを抜けた時にカーソルが見えなくなる現象対策(なぜかこれで治る)
inoremap <ESC> <ESC>

最初のt_SIとt_EIの設定では、エスケープシーケンスを用いてカーソル形状を設定しています。

また、ttimeoutlenはエスケープシーケンスをその時間内に入力すれば認識するという意味で、逆に言えばその時間まで待って初めてエスケープシーケンスの効果を認識するということになります。この時間が認識できるくらい長いと挿入モードを抜けた際にカーソル形状がすぐにもどらない、なんて事が起きます。エスケープシーケンスは手入力しないことがほとんどだと思うので、10msecに設定しています。(0でもいいという情報もみかけましたが念のため10msecにしてます。)

さらに、なぜか挿入モードを抜けた時にカーソルが次の操作をするまで見えなくなるという現象がたまに発生したので、上記設定をしたら治りました。なぜ治るのかの理由は不明ですが、追求しても仕方ないのでよしとします。(分かる人いたら教えてください。)

ちなみに、iTerm2は標準でマウスイベントに対応してまして、mouse=aと.vimrcに書いておけばホイールスクロールできますし、マウスドラッグがビジュアルモード選択になります。なおMac側でコピペしたい時にはOptionキーを押しながらドラッグするとできます。

これで快適にVimで操作できるでしょう。楽しいVimライフを!

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年3月26日水曜日

Macのターミナル上のvimでマウスホイールスクロール

僕もvim愛用者の一人ですけれども、MacBookではMacVimとターミナル上のvimの両方を使い分けております。また、sshでリモート接続してターミナル上でvimを使うこともしばしばあります。そこで前から、ターミナル上でvimを使う時もマウスホイールでスクロールできたら便利だと思っておりまして、方法を調べてみました。

要点としては、

  • EasySIMBLをインストールする
  • MouseTermをインストールする
  • vimの設定でマウスを有効にする

の3点です。

EasySIMBLをインストールする


SIMBLは、MacのCocoaアプリケーションの動作をカスタマイズできる機能拡張です。このSIMBLの上にさらに用途別のプラグインをインストールすることで様々なカスタマイズができます。EasySIMBLは、本家SIMBLを改良して、ドラッグアンドドロップで簡単にプラグインをインストールできるようにしたものです。ダウンロード先はこちら↓
https://github.com/norio-nomura/EasySIMBL/

MouseTermをインストールする


Macのターミナルがマウスイベントを送信できるようにするSIMBLプラグインです。先ほど上で述べたEasySIMBLを使ってインストールします。ダウンロード先はこちら↓
https://bitheap.org/mouseterm/

ダウンロードして解凍インストーラが出てきますが、このインストーラは使わずに、直接拡張子が「.bundle」のファイルをEasySIMBLの画面にドラッグアンドドロップしてください。

MouseTermをインストールすると、ターミナルの「シェル」メニューに「Send Mouse Events」が出現し、チェックのON/OFFで切り替えができるようになります。普段はONにしておき、Mac内の別のアプリにターミナル上の文字をコピペしたいときなどはOFFにするとよいでしょう。

vimの設定でマウスを有効にする


.vimrcに次の記述を追加します。

set mouse=a
set ttymouse=xterm2

なお、僕の環境ではttymouseは元々xterm2になっていたので2行目の設定は不要でした。

これで、ターミナル上のvimでもマウスが効くようになります。マウスホイールでのスクロールに加えて、クリックした部分へのカーソル移動、ドラッグによるビジュアルモード選択もできるようになります。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年3月20日木曜日

[Ruby]開発環境をEclipse(Aptana)からVimに変更した件

開発環境にはEclipseを愛用してきた僕ですけれども、Rubyでの開発プロジェクトを本格的に進めるにあたり、色々試行錯誤の結果Vimに乗り換えることにしました。いえ、乗り換えるというと語弊がありますね。正確に言えば、コーディングすなわちソースコードをガリガリ書く部分にはVimを使いますが、EclipseはGitリポジトリの状態を見るのに使ったりするので併用していく方式にした、ということです。適材適所。

PHPの時にはEclipseのPDTプラグインが大変良く働いて、例えば文脈に応じての補完機能などは非常に便利でした。これは動的にコードから補完ができる優れ物で、自分で書いたクラス定義を参照してインスタンスのメソッド名を補完できたりしたんですね。さらに、フレームワークのソースコードをライブラリを読み込ませることで、フレームワークに用意されたクラスやクラス内のメソッドまで補完が効きました。あとクラスやメソッドにカーソルを合わせてショートカットで定義元にジャンプできたりとか。

一方、EclipseでRuby開発に使えるプラグインとしてはAptana Studio3がありますが、動的にコードから補完するところまではできないようでした。また、フレームワークのクラス名やメソッド名も補完が働きませんでした。もしかしたら僕の設定が間違っていた可能性もありますが、ある程度時間を掛けたところで諦めました。

そもそも、純粋なテキストエディタとしての使い勝手としてはVimが好きで、EclipseにVim風のキーバインドを実現するプラグインのvrapperを入れて愛用していたくらいです。PHPで開発していた時には、文脈を理解した動的な補完とライブラリからの補完がよく出来ていたので書きやすさを少し犠牲にしてEclipseを使っていましたが、それがイマイチならEclipseを使う優位性は薄れてしまいます。

調べてみると、Vimで一定レベルの補完や自動文法チェックもプラグインでできるので、それならRubyを書くのにはVimの方がいいかと思ったんですね。ということでコーディングはVimで行うことにしました。

ちなみに、Gitリポジトリの状態を見るためにEclipseは併用します。コミットグラフが見やすいので。ヒストリービューはほぼリアルタイム(長くても5秒くらいの遅延)でコミットグラフを更新してくれるので、状態を把握しつつブランチ間を移動したりコミットしたりできます。Eclipseは検索なんかも結果が見やすいですし。タスク・タグの一覧とかも便利です。普段はVimでコードを書きつつ、裏でEclipseを起動させておいて必要な時だけ見る、という使い方になると思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年3月18日火曜日

[Ruby] Cucumberで日本語テスト定義がエラーになる時の対処

最近初めてCucumberを導入したんですが、日本語でテストケースやステップ定義をする際に日本語をうまく認識できずエラーが出たので、それに対する対処と、若干のTipsをメモしておきます。

最初はネットにあるCucumberのサンプル通りfeacureファイルと対応するstep定義ファイルを記述して実行しました(この時は日本語なし)。これはうまくいきました。今度は、記述を日本語に変更して実行。ところがエラー。下記のように対処しました。

featureファイル


最初に出たのはこんなエラーでした。

Lexing error on line 1


調べてみると、そもそも全く文法を識別できない時のエラーだとか。そんなバカな。しかしどうやら原因は、日本語を使っていると認識できていないようでした。調べた結果、1行目に下記のようにコメントを入れることで日本語を使っていると認識でき、このエラーは出なくなりました。

#language:ja


step定義ファイル


ところが上記エラーを修正すると、今度はこんなエラーが出ます。

invalid multibyte char (US-ASCII)


勘弁してくれ。ただ、今度はエラーメッセージから明らかに文字コード認識の問題だと分かります。調べた結果、step定義ファイルも1行目に下記のようにコメントを入れないと、正しく文字コードを判別できないようです。(先ほどとは違うコメントなので注意。)

#encoding:utf-8


これらの記述をすることで、日本語で記述したテストが実行できるようになりました。

2014/03/20追記:step定義ファイルの文字コード認識の問題は、Ruby1.9系が上で書いたようなコメントを入れないとエンコーディングを正しく認識できないことが原因みたいなので、Ruby2.0以上をお使いの場合は不要かもしれません。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年3月15日土曜日

[Ruby] Padrinoをフルスタックで使う時にどのコンポーネントを使うか

以前にSinatraについて書きましたが、その後検討した結果Sinatraベースの軽量フレームワークであるPadrinoを使うことにしました。結局MVCの構造にするんだし、TDDやるし、となるとSinatraの上に色々作り込むことになるわけで、だったらひと通り用意されているものを使ったほうがよさそうだからです。以前PHPのフレームワークSymfonyを使っていた経験もあって、フルスタックフレームワークの恩恵はよく知ってましたので。でも自由度はPadrinoの方が高そうです。

さて、Padrinoはフルスタックフレームワークではおなじみのプロジェクト・ジェネレーターがありまして、コマンド一発でプロジェクトの雛形を生成できるようになってます。しかしながら、このプロジェクト・ジェネレーターには、機能ごとにどのコンポーネントを選ぶか、様々なオプションを付けることができ、迷うこともあるんじゃないかと思います。

ということで、今回どのコンポーネントを使うことにしたかと、その理由について書いてみたいと思います。

とりあえず、一覧はこちらです。(ちなみに選択可能な他の選択肢はここに載ってます。)

  • orm: activerecord
  • test: cucumber
  • script: jquery
  • renderer: erb
  • stylesheet: scss
  • mock: none

プロジェクト・ジェネレーターのコマンドは

padrino g project <the_app_name> -d activerecord -t cucumber -s jquery -e erb -c scss

ですね。

それぞれ理由について書いてみます。

orm: activerecord


ORマッパーです。activerecordを選んだのは、Railsで標準的に採用されていて情報が手に入りやすそうだったからです。もちろんここでactiverecordのやり方を習得したら、Railsのプロジェクトをやることになった際も役立つだろうという計算もあります。他の選択肢はよく知りません。

test: cucumber


テスト駆動開発のファンとしては重要なテスティングフレームワーク。これは以前も書いたようにcucumberをチョイス。ちなみに、選んでみて後から気づいたんですが、cucumberを指定すると自動的にcapybaraも組み込まれて使用されます(もちろんrspecも)。他の選択肢はrspec以外はよく知りません。

script: jquery


javascriptフレームワークはjQueryをチョイス。まあ最もメジャーで資料も豊富だし使いやすいしこれが一番ですかね。prototypeは古いイメージがあります。extcoreは書き方が好きじゃないです。dojoは面倒そう。rightjs, mootoolsはよく知りません。

renderer: erb


テンプレートエンジン。迷いました。hamlは確かに構造的に美しいかも知れませんが、学習コストが高く慣れるまで時間かかりそうなのと、後々デザイナーさんとの協業の際非常に面倒になりそうなのでパス。slimも同様の理由でパス。一瞬liquidのPHPでいうところのsmartyに似たシンプルさに惹かれましたが、調べてみると情報がとても探しにくい。柔軟性の高さも勘案して結局erbにしました。

stylesheet: scss


これもlessとscssどっちにしようか迷いました。たぶんコーディングの観点からは差はありません。しかしrubyのプロジェクトなので、ビルドエンジンがrubyであるscssとは相性が良さそうで、lessは結局node.jsの導入が面倒なので止めました。

mock: none


モックフレームワークは実は存在自体今回調べてて初めて知りましたが、あまり必要性を感じなかったので指定しませんでした。なんかJava界隈では結構活躍してるっぽいですね。誰かどんな風に便利なのか知ってたら是非コメント書いて教えてください。

以上、コンポーネントを選んだ理由でした。参考になれば。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年3月13日木曜日

gitでmasterブランチへのマージを --no-ff で行う理由(コミットグラフ例つき)

gitを用いてローカルリポジトリで開発する際の1つの手法として、ローカル専用ブランチを切って、変更を自分の名前のブランチにmerge --squashで反映する方法を以前紹介しました。

そして、自分の名前のブランチを中央リポジトリへとブッシュし、中央リポジトリへの管理者が各開発者の名前のブランチからmasterブランチにマージするわけですけれども、その際、masterブランチに各開発者の名前のブランチの変更を反映する時には、常にfast-forwardのマージを避けて--no-ffでマージしています。

これはなぜかというと、各開発者の行った変更・修正がどのタイミングでmasterブランチに統合されたのかを明確に記録するためです。

また、コミットグラフを見た際にも、開発者の名前がついたブランチが1直線につながるので綺麗に見えるという利点もあります。

例をお見せしましょう。EclipseのEgitプラグインでコミットグラフを見てみるとこんな感じに見えます。


上の図で、一番左の線がローカル専用ブランチ、真ん中の線が開発者の名前のブランチ(tkasai)、一番右の線がmasterブランチです。
※上から2番目のコミットだけmasterのグラフが左に行ってますが、脳内で右に位置を替えてみてるとすっきりします。

真ん中の線のtkasaiブランチへのコミットは、左の線のローカル専用ブランチ(local/日付)をmerge --squashでまとめたものです。例えば、真ん中あたりのコミットID:689b51aはコミットID:6e1b3b7〜60f3d8e(つまりlocal/14.02.18ブランチにおけるコミット)をまとめたものになっています。そして、tkasaiブランチを任意のタイミングでmasterブランチへと--no-ffでマージしています。ここではローカル専用ブランチをmerge --squashした直後が多いですね。

こうしてみると、いつmasterにどのブランチをマージしたのかが明確にわかります。

ちなみに、Egitのコミットグラフは現在のブランチに直接つながりのないブランチを隠すことができます。するとこうなります。今度は左の線がmaster、右の線がtkasaiで、さっきの図と位置が逆になっているので注意。


スッキリして見えますよね。最新以外のローカル専用ブランチが省略されてこうなるのです。まだ開発者ブランチが僕一人の分しか無いからこれだけですが、もっと開発者が増えたら、コミットグラフが整理されて見える恩恵はもっと大きくなると思います。

関連記事:gitでローカルリポジトリにローカル専用ブランチを作って開発する

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

2014年3月11日火曜日

Debianでパッケージからrbenvとruby-install入れて使う

ソフトウェア開発では、成果物をリリースする際にはプログラミング言語のバージョンを固定するため、後からメンテナンスする際にその言語のそのバージョンで固有のバグを再現して修正するため、言語をリリース時のバージョンで実行できるような環境を残して置かなければなりません。また、複数プロジェクトを持つことになった場合は、それぞれのプロジェクトで言語のバージョンが違ったりすると、言語のバージョンを切り替えつつ作業をしなければならなくなります。

そこで、1つのマシン上で特定のディレクトリごとに使う言語のバージョンを切り替えられる仕組みが存在します。Rubyではその1つにrbenvがあります。以前からrvmもあったらしいですが、最近ではより軽量なrbenvが人気で乗り換える人も多いようです(rvmは使ったこと無いので詳しいことはググってください)。

で、開発にDebian7を使ってて、パッケージも用意されてるようなのでrbenvを入れました。ここでは利用するRubyのバージョンは1.9.3-p194としましょう。rubyをrbenv経由でインストールするにはruby-buildパッケージも必要です。

[user@host]% aptitude install rbenv ruby-build
[user@host]% rbenv install 1.9.3-p194
[user@host]% rbenv rehash
[user@host]% rbenv global 1.9.3-p194

~/.zshrc に以下の行を追記します。PATHに$HOME/.rbenv/binを追記するのはrbenvをソースからインストールした場合だけに必要なので、パッケージから入れた場合は下記だけで大丈夫です。

eval "$(rbenv init -)"

これで source ~/.zshrc で読み直すかログインしなおすと、先ほどインストールしたrubyがrbenvの制御下にあることがrubyのパスから確認できると思います。ちなみにgemも同様にrbenvの制御下にありますね。

[user@host]% which ruby
/home/user/.rbenv/shims/ruby
[user@host]% ruby --version
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
[user@host]% which gem
/home/tkasai/.rbenv/shims/gem

特定のディレクトリ以下でrubyのバージョンを切り替えるには、

[user@host]% rbenv local <version>

のようにします。するとそのディレクトリに.rbenv-versionというファイルが作られて、使用するバージョンが記録され、次回からrbenvが自動的にバージョンを切り替えてくれます。

さらにgemの管理のためBundlerも入れましょう。rbenvはrubyのバージョン切り替えだけを行うのでプロジェクトごとにgemも切り替えたい場合はBundlerが必要です。インストール後の rbenv rehash を忘れずに。

[user@host]% gem install bundler
[user@host]% rbenv rehash

念のため、ログアウトしてログインし直します。bundleコマンドのパスを調べると、rbenv制御下に入っています。

[user@host]% which bundle
/home/user/.rbenv/shims/bundle

あとは通常のbundleコマンドと同じ使い方でOKです。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。