Gitをバックエンドに使ったプログラマ向きWiki - Gitit

25th May, 2011 | git

Wikiというものはとても便利なんだけど、

  1. 大量の文章を書くにはWebブラウザのインターフェースはまだまだ辛い
  2. オフラインで使えない(文章書くのは電車が一番)
  3. 複数の文章を再構成したり、一括で検索したり、置換したりは、Webだとやっぱりきびしい

と言った欠点がある。

とは言え、誰でも気軽に編集できるWikiの魅力も捨てがたい。

そこで、「Wikiではあるんだけど、ローカルでも自分の好きなエディタで簡単に編集できるツールないかなー」と探してみたら、 Gitit というWikiを発見した。

ここ数日、結構な量のドキュメントをGititで書いてみて、わりと満足しているのだけど、検索してもGititの日本語の情報があまり出てこないので紹介してみる。

Gititの特徴

  1. コンテンツをGitのレポジトリに保存する。
  2. そのGItレポジトリをcloneして好きなようにいじってからcommit/pushすれば即座にWikiに反映される。
  3. Wikiとしてはとても普通。マークアップはmarkdownがデフォルトだけど他にも選べる。各種言語のコードを綺麗に色付きでフォーマットしてくれる。
  4. Haskell製でpluginとかもHaskellで書く。
  5. Webサーバを内蔵している。
  6. 独自のメタ情報のようなものを持たずに、Gitレポジトリ内のディレクトリ/ファイル構成がそのままWikiになる。ファイル名がそのままWiki名になる。もしやめたくなった場合に他のツールへの移行も楽。
  7. テキスト以外の画像とかもそのままGitレポジトリに入る。もちろん、cloneしたレポジトリに画像を入れてcommit/pushすればアップロードされる。
  8. Gitそのままなので分散Wikiみたいのも簡単に作れるし、branchを使ってのドキュメントの管理とかもできる。

Github製の gollum と似ているが、Gititの方が良さそう。

デモサイトはこちら。 Wikiとしては、普通中の普通なので面白くないけど。

Haskell製と知って、インストールめんどくさそうだなーと思ったんだけど簡単だった。

簡単な導入手順 – Ubuntu編

$ sudo apt-get install ghc
$ sudo apt-get install cabal-install

$ cabal update
$ cabal install pandoc gitit -fhighlighting --reinstall
(pandocとgititを同時にinstallしないとhightlightが有効にならなかった)

path に ${HOME}/.cabal/bin を追加

$ mkdir ~/hogehoge
$ cd ~/hogehoge
$ gitit --print-default-config > gitit.conf
$ <editor> gitit.conf
$ gitit -f gitit.conf

これで、port 5001で起動するので、 http://localhost:5001/ とかで。外に公開するなら、apacheとかnginxでreverse proxyすればいいだろう。

コンテンツを直接いじりたい場合は、

git clone ssh://example.com:~/hogehoge/wikidata

とかで、普通にcloneして後はお好きなエディタでファイルを編集して、commit/push すればその場で反映される。

こんな感じで、Gititを使うと、gitを使ったプログラミングと同じフロー/リズムでドキュメントを書けるところが気に入ったのでした。

オススメ。



Gitリポジトリにあるコードを追う / コードレビュー

21st Feb, 2010 | development git

これまではcommitされたコードを、commit(push時)メールでなんとなく見ていたが、取りこぼしも多いし、忙しいと、つい見なくなってしまうので、なんかいい方法はないかなとここ数カ月くらいぼんやり考えていた。で、簡単なスクリプトでできそうと気づいたのでメモ。Githubに置いてあるようなオープンソースなコードとかも追いやすいんじゃないかなー。

ちなみに、このスクリプトを書く前に、コードレビューシステム的なのを導入しようかとGerritとか、Review Boardを少し試してはみた。でも、うちで使うにはちょっと大げさ過ぎるので、導入してもツールに踊らされる or 使わなくなる、という感じがしたので、とりあえずやめた。

いまいち気に入らない点としては、Gerritとかは完全にcommit単位でのレビューなんで、ちょっとしたパッチレベルならいいのだが、がりがり書いていく中ではちょっと現実的ではないかな、という感じがした。同じ機能追加/修正のために、同じ日に同一のファイルの同じような場所に複数回commitする、ということはよくあると思うが、そういう場合に1 commitずつ見る意味はあまりないかな、という感じ。それと、普段エディタで書いてるので、レビューもエディタでしたい、ってのもある。

追記: 指摘されたのだが、もちろんGitのsquash機能を使いこなせば、きれいな1 commitにまとめられることも多いだろう。でも、それでもやはり限界はあるし、綺麗なcommitセットとログを作ることに時間をかけるのも本末転倒な部分もあるかな、と。もちろん 1 commit は 1機能の追加/修正するという原則は基本的には徹底したいんだけど。それと、個人的には複数人が同じようなところ修正した場合も一個の差分として見た方がわかりやすい。

自分の中でやりたいことをまとめると、

  • 毎日レビューするという前提 > そこまで大量なコードを相手にするわけではない
  • リポジトリの(あるブランチ)中全部のコードを対象にしたい
  • 前回レビューしたところから現在までのソースの差分を見たい
  • 同一のファイルに対する複数回のcommitは一個の差分として表示
  • ただしcommitログはファイル毎に全部表示
  • レビューで問題や疑問があった場合には普段使っているBTS(Redmine)に投げる (ここはスクリプト化しない)
  • 毎日のことなので、上記のことをコマンド一発で簡単にやりたい

こんな感じのスクリプトを作った。ほとんどGitのコマンド並べただけだけど、短いので全文出しとこ。

#!/bin/sh

if [ ! -d ".git" ]; then
  echo "run in the git top directory."
  exit 1
fi

reviewed_repo="REPOSITORY_TO_STORE_REVIEWD_CODE"
reviewed_branch="BRANCH_FOR_REVIEWED_CODE"
reviewed_combined="${reviewed_repo}/${reviewed_branch}"

output_file="reviewing.patch"
rm -f ${output_file}
for file in `git diff --name-only ${reviewed_combined}`; do
  echo "==================================================================" >> ${output_file}
  git log ${reviewed_combined}.. -- $file >> ${output_file}
  echo "" >> ${output_file}
  git diff ${reviewed_combined}.. -- $file >> ${output_file}
  echo "" >> ${output_file}
done
if [ -f ${output_file} ]; then
  emacs -nw ${output_file}
  read -p "Approved?(y) " ans
  if [ "${ans}" == 'y' ]; then
    git push ${reviewed_repo} HEAD:${reviewed_branch}
  else
    echo 'ignored'
  fi
else
  echo "No unreviewed commit."
  exit 1
fi

処理の流れ: (1-2 をするようなGitコマンドがありそうだが、探せなかった)

  1. git diff --name-only で前回から変更があったファイルの一覧取得
  2. 変更があったファイル毎に、git logとdiffで自分が欲しい情報作成
  3. 作成した差分をエディタで開く
  4. エディタを終了したら、プロンプトを出して、reviewが終わったか聞く
  5. 終わった場合には、現在までのcommit情報をレビュー済branchにpush

「前回レビューしたところまで」という情報をGitにブランチとしておくことで、未読管理とかめんどくさいことを全部gitにお任せできるので楽。これを置くところはローカルでもリモートでもいいんだけど、今回は未読情報を一箇所に置いておきたのでリモートに置いている。

たったこれだけなんだけど、なかなか気に入っていて、一日の中で時間が空いたときに、reviewしたいリポジトリに行って、 rv (このスクリプトに付けてる名前) とタイプするだけで、前回レビュー時からの差分が、慣れている emacs に出てきて、レビューが開始できる。オリジナルのソースにジャンプしたい場合とかもemacsのdiffモードにお任せなので楽々。

前もってpullさえしてあれば、オフラインでも当然動くので(最後のpushは今はリモートのリポジトリにしてるのでそこだけは場合によってネットいるけど)、電車で移動中とかどこでもできるのもいい。

たいしたことではないけど、日常なことを簡単にできるようにするってのは効率化(=自分の本当にやりたいことの時間を増やす)ための一歩ですよね。

しばらくこれで行ってみて、きつくなったら、レビューシステムを再検討してみるつもり。

追記: はてブでわかりにくいという反応を頂いたので図を書いてみた。数字は上のリストの数字と対応してる。正確にはReviwed branchはローカルに持ってきてからlogとdiffをする感じ。

全体的に、なんかもっといいGit標準的なやり方がありそうで、ちょっと自信ないのだけど。