git-nowをサブコマンド化してみた

最近プロジェクトのVCSSubversionからGitに移行して、ホクホク顔でgit stashしまくっている今日この頃ですが、みなさんいかがおすごしでしょうか?

さてそんなお寒い時候(?)の挨拶はおいといて、hotfixとかfeatureのbranch上でgit-now使いまくっているわけなんです。
git-nowには--rebaseってオプションがあって、あとからcommitをいじっちゃうわけなんですが、それにさらにオプションはやしたり云々やってたらサブコマンド化したくなってやってしまいました><
homebrew化とかもしっちゃった関係(謎)でGitHub上にあげてるんですが、元々のscriptがgistでGitHubとしてforkできなくてid:sinsokuさん、すいません><

git-nowって?

temporaryのcommitを簡単にできるコマンドラインツールです。
詳しくはid:sinsokuさんの元ネタをみてください。

サブコマンドについて

いまのところrebaseとgrepというサブコマンドがあります。

rebase

rebaseは元々の--rebaseにいくつかオプションを加えたのと、引数でbranch名を指定できるようにしてます。
--rebaseつけるとrepository上の全てのコミットメッセージからgit-nowなコミットをgrepしてきちゃうわけなんですが、自分的にはいまのbranch上にあるgit-nowコミットだけrebaseしたいことがほとんどなので、branch名を与えると、いま自分がいるbranchと指定したbranchとの共通の先祖からgit-nowコミットをgrepしてくれます。

$ git now rebase master

git-nowコミットはtemporaryなんで普通は後から修正するんですが、間違ってそのメッセージがそのままpushされちゃってる場合なんかは、--rebaseする度に古〜いコミットもgrepに引っかかってきちゃうんで、これはかなり重宝してます><b

あとは--push|-pってオプションがあってrebaseのあとにgit pushをしてくれます。
手元でtest通ったらgit nowして、一通り機能ができたらgit now rebaseしてコメント修正後にremoteにpushって流れるになると思うんで、その辺を簡単にやるあれです。
remoteに一回もpushしていない場合、git pushできないんで、そういうときは--remote|-rオプションでpush先に指定できます。中では--set-upstreamやる感じですよ〜

$ git now rebase -p master
$ git now rebase -p -r origin master
grep

git-nowコミットをgrepして表示するサブコマンドです。
こいつもrebaseと同じように引数でbranch名を指定すると共通先祖からのgrepになります。
pushする前にgrepしてtemporaryコミットあったかな?って思ったときにサクっと確認できちゃうんです><

$ git now grep
$ git now grep master

インストール方法

GitHubのREADMEみてもらえば分かるんですが、Macでhomebrewな人は:

$ brew install https://github.com/iwata/git-now/raw/master/git-now.rb

それ以外の人は普通にgitでもってきてmake installでいけます。

shell scriptについて

今回はgit-flowのscriptを参考にしました。
ベースとなる部分はコピペです><

getoptのlong-optionとFormula

git-flowのパクりなので、shellのコマンドライン引数のパースにはshflagsっていうのを使っています。
helpとか書くのにかなり便利なんですが、Macだと--pushとかのlong-optionのパースがうまくいきませんでした。
-pはいけるんですが。
-pでいいっちゃいいんですが勝手にpushが走っちゃうんでできれば--pushとタイプ数が多くなる方が誤動作少なくできるんじゃないかと思ってlong-option動かねーのダメだなぁ…とか思ってました。
それでGoogle先生で色々調べてみるとshflagsのBTSFailed to parse long option on Mac OSX Snow Leopard with standard getoptっていうのを発見!しました。
それで一番下のやつをみると、

Final comment, for anyone having the same issue on Mac OS X, you can get the enhanced GNU getopt version via MacPorts (http://www.macports.org/).

$ sudo port install getopt
(after you installed MacPorts, see http://www.macports.org/install.php)

getoptのenhancedバージョンが必要だからMacPortsインスコすればいいお><bって書いてあります。
ってMacPortsかよ Σヾ(゜Д゜汗) …なのでhomebrewで同じのはないかな?って調べるとありました。gnu-getoptっていうのがそれらしいです。
(なのでFormulaのdepends_onにはgnu-getoptをいれてます、一応。)

ちなみに自分のgetoptがenhancedじゃないかどうかは以下を実行してみればわかります。

$ getopt --version

これで" --"って表示されたら--versionがパースできていないってことで普通のgetoptでバージョン情報が表示されたらenhancedってことになります。

そして早速インストール。

$ brew install gnu-getopt
$ getopt --version
 --

ってなんでやねん Σヾ(゜Д゜汗)
enhancedにならない><、whereしてみると、

$ where getopt
/usr/bin/getopt

あれ? homebrewでいれたやつじゃない、、、
gnu-getoptのFormulaをみてみると"keg_only"が指定されている!
なので以下のようにlinkを貼る。

$ brew link gnu-getopt
$ getopt --version
getopt (enhanced) 1.1.4

ktkr!!
これで--pushオプションが使えるようになりました。この辺の色々をやらないといけないので上のコマンドでは-pを使っています。でも間違い易いと思うので、使える環境なら--pushを打つようにしといた方が安全だと思います。

Formulaでは

  # for longopt
  depends_on 'gnu-getopt'

  def install
    system "make", "prefix=#{prefix}", "install"
    system "brew ln gnu-getopt"
  end

ってやっていてinstallの中で無理矢理linkさせてるんですが、これだとupdateのときいちいちbrew unlinkしないとinstallにコケるのでなんかイマイチです。
もしこの辺うまくできる方法を知っている人がいらっしゃったら教えてください><

追記

rebaseの後にpushとかしようとしてもrebase -iやっちゃうとshell抜けちゃって返ってこないですね><

…ということで--pushとかのオプション再考しまふ。。

追記2

とりあえず、--pushとか--removeオプションは廃止。

あと--author|-aオプションで自分のコミットだけから、grepしたり、rebaseすることができるようにした。