ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

複数のコミットをsquashするコマンド「qs(quick squash)」を作った

前回書いたこれ、がv0.1.0 releaseされた。

blog.chaspy.me

コマンド自体のまじめな解説は作者の@kamontiaが書いてくれてる。

qiita.com

このエントリではどちらかというとこのOSS作りで感じたことを中心に綴りたいと思う。

OSSを作ってリリースすること

実は、はじめてだ。今回も、collaboratorとして参加していて、自分1人で作ったわけでもない。

ただ散々OSSを利用しておいて、供給側にまわっていないということは、この業界にいながら罪悪感に近い引っかかりを得ていた。別のこのOSSがまだ誰かに使われたわけでもないが、大きな一歩だと思った。

モチベーションと作ったもの

github.com

はなから2人で作ろう、としてはじめたものなので、organizationのnamespaceでやってもよかったが、なんだか中途半端な格好になることを前回別の(挫折した)アプリで感じたので、今回はkamontia以下のnamespaceで作った。別にそこにこだわりは僕としてはない。

基本的にラフにpushして、CI通るまで細かくなおして、通ったらcommitをまとめてforce pushする、という開発スタイルでやることが多いので、わりとsquashする機会は多い。

自分が本当に欲しいものを作ることこそがOSS活動だと思うので、今回欲しいもの、作りたいテーマがうまく見つかったのが一番の幸運であり、リリースまでこぎつけた成功要因だと思う。

ちなみにまあ、普通に使える。

使用例

適当に1ファイル追加するコミットが4つあったとして、それをまとめたい。

$ qs -n 2 -d -m "squashed"
WARN[0000] [ 3] pickup -> pickup  9e94b2d fileA
WARN[0000] [ 2] pickup -> pickup  262207a fileB
WARN[0000] [ 1] pickup -> squash  a4bede9 fixup! fileB
WARN[0000] [ 0] pickup -> squash  fcdda5f fixup! fileB
Do you squash the above commits?(y/n)

-n 2はHEAD..HEAD~2をまとめるという意味だ。-dはdebug option。-mはsquashed commitのメッセージだ。-mがない場合まとめ先の262207aのメッセージが使われるようになる。

squashといいつつ、内部実装的にはfixupでまとめてからメッセージ変更をする擬似的なsqaushになっている。

結果はこうなる。

$ git log --oneline
0cbbd9d (HEAD -> master) squashed
262207a fileB
9e94b2d fileA

gitはまぁ使いはじめて長いが、いまだにrebase時の順番とlogの順番が逆なのは結構気にくわないし毎回混乱している。慣れない。

複数人開発

とはいっても2人だけど。

開発はissueとPRベースで進めた。別にissueはなくてもいいが、あとあとlabelとかで整理する意味であったほうがいい気がしたのであえて採用した。わりとこれいるんじゃない?と思いつくと、slackに発言してpin、気づいたひとがissueを立てる。(備忘をかねている)そしてPRでrefarenceして実装、review、mergeという流れだ。まぁ、きっと一般的な開発フローだと思う。

現職で上司との1on1で「レビューって案外重要なんですよね、他の人のブロッカーになるから」ということを聞いて、確かにそうだなぁと思った。今回、2人だからこそ意識的にPRのレビューは素早くすることを心がけた。だいたい1日に2回はチェックする時間を作って、うまくいけば半日以内にmergeできるサイクル感を目指した。

プロダクトとしても、個人としても、停滞はモチベーション下がるじゃない?initial commitは14days agoになっている。そこから100 commit、29のPRをまわせたのはなかなかよかったのではないかと思う、実際結構稼働はかけたけどね。それでも1日1h〜2hぐらいだし、夏休みで触ってない日もあるし。

反省点としては、初期で結構デカいfeatureを実装しているときに、テストの変更をしてしまって、そのケアに時間がかかってしまったことが悔やまれる。テストやるならやるで最初に同期して作ってしまってやる、ということをすべきだったなと思う。立ち上げからinitial commitまでリモートペアプロでやったのはよかったけど、そこからしばらくはパラレルにやらず、assignはするけど順番にやったほうがよかったのかなぁと思った

テスト

今回はgitという外部コマンドと連携するプロダクトなので、UnitTest(は、まだない)というよりはE2Eテスト的なものが必要だ。今回はそれをbashで実装した。

github.com

最初はひどいもんだったけど、release前にリファクタをして、マシにしたって感じ。

テスト1回ごとにディレクトリを作成し、git initからサンプルコミットを作って、qsコマンドを実行して、期待値と比較する、ことを繰り返す。テストフレームワークを自前で実装した感じ。このへんはrspecを普段はよく使うのでそのへんの印象で作っている。

テストの数は少ないが、これがあるとないとではかなり違う。最初の頃はそれこそ手作業でテスト用のgit履歴を作っていたから、はやめに取り掛かってよかったと思う。もちろん大好きで大嫌いなCircleCIを使っている。

Go言語

正直、雰囲気で選択したし、まぁ書いたが、Tour of GOを半端にやったぐらいで、何も身についたとは言えない。実際、今のコードはbashでできることを3倍ぐらいの行数をかけてGoで実装したようなもんで、Go言語である必要性はまったく活かせていない(し別に理解もしていない)状況だ。

ただ、便利なCLI toolのためのframework、codegangsta/cliには助かったし、go getで配れるのは本当に楽だよなぁと思うので、今のところ享受しているメリットはそのあたり。

今回v0.1.0はとりあえず動くものをリリース、次でリファクタの予定なので、しっかりGoを学んで「なんだこのクソコード」と思えるようになってからリファクタしたい。

おわりに

2週間で動く、(自分にとって)有用なコマンドを作れたのは、なかなかない成功体験だと思う。今回の成功要因はこんなところか。

  • プロジェクトのinitializeをリモペアで合意し、同期的にやれたこと
  • PR -> mergeサイクルを可能な限り高速化したこと
  • 作りたいものが決して技術の学習用、とかではなく、本当に自分たちが欲しいものであったこと

特に一番最後がもっとも大切なことだと思った。技術は、解決したい課題に対する、手段である、どこまでも。

ペアを組んだのは本当に気のおけない友人であることももちろん大きい。ありがとう。

feedback

わりと破壊的な変更をするコマンドなので、慎重に、といいつつ、まぁまぁ使えるんじゃないかなあと思うので、実際に使ってみて、feedbackをissueにくれるとうれしい。GitHubのissueでもtwitterのリプ/DMでも構いません。よろしくお願いします。

github.com

twitter.com