この記事はGit Advent Calendar 2013の12日目の記事です.
前日は@sonotsさんのgit current-branch, git fetch-pulls, git pull-dry-run など git alias ネタでした.
gitはコマンドを実行するとき,まずgit --exec-path
のパスの中からコマンドを探し,なければユーザーのPATHの中からコマンドを探して実行します.
$ git --exec-path
/usr/lib/git-core
そのためPATHの通った場所にgit-コマンド名
という実行ファイルを置くだけでユーザーが自由にサブコマンドを作れる便利な仕組みとなっています.
ということで,pythonでgitのサブコマンドを作ってみました.
git-ls-date
このサブコマンドはファイルを最初にコミットした日付と最後にコミットした日付(とそのハッシュ)を表示するコマンドです.
こんな感じ
$ git ls-date
2013-11-05 7ab1b16 2013-11-05 7ab1b16 README.rst
2013-11-07 342ad26 2013-11-10 2826492 git_ls_date.py
最後にコミットした日時でファイルをソートしたり
$ git ls-date --date iso --format "{ld} {f}" | sort
2013-11-05 04:40:11 +0900 .gitignore
2013-11-05 04:40:11 +0900 README.rst
2013-11-07 23:22:29 +0900 setup.py
2013-11-07 23:34:59 +0900 LICENSE
2013-11-08 15:36:16 +0900 .python-version
2013-11-09 15:07:06 +0900 testfiles/testdirectory/testfile4
2013-11-09 19:11:38 +0900 testfiles/testfile2
2013-11-09 19:11:38 +0900 testfiles/testfile3
2013-11-09 21:03:55 +0900 testfiles/testfile1
2013-11-09 22:22:38 +0900 tox.ini
2013-11-10 15:32:19 +0900 test_git_ls_date.py
2013-11-10 18:28:24 +0900 git_ls_date.py
2013-11-10 19:45:40 +0900 MANIFEST.in
そのファイルを最後にコミットしたハッシュのみを表示させたり
$ git ls-date --format="{lh} {f}"
7ab1b16 README.rst
2826492 git_ls_date.py
githubっぽく最後にコミットした日付を相対日時で表示したりできます.
% git ls-date --date relative --format "{ld: >20} {f}"
5 weeks ago .gitignore
5 weeks ago .python-version
5 weeks ago LICENSE
5 weeks ago MANIFEST.in
5 weeks ago README.rst
4 weeks ago git_ls_date.py
5 weeks ago setup.py
4 weeks ago test_git_ls_date.py
5 weeks ago testfiles/testdirectory/testfile4
5 weeks ago testfiles/testfile1
5 weeks ago testfiles/testfile2
5 weeks ago testfiles/testfile3
5 weeks ago tox.ini
詳しくはREADMEを見てください.
pip install git-ls-date
でインストールできます.
git-ls-date
というコマンドが実行できるようになるので,git ls-date
でも実行できるというわけです.
gitconfigを使う
せっかくなので,gitのサブコマンドらしくgitconfigに設定を書けるようにします.
$ git config --global git-ls-date.date relative
$ git config --global git-ls-date.format "{ld: >20} {f}"
と実行すると.gitconfig
の中に以下のように書き込まれます.
[git-ls-date]
date = relative
format = {ld: >20} {f}
このような項目はユーザーが自由に設定することができるので,あとはコマンド側でこれを読み取るようにするだけです.
読み取るにはgit config --get-regexp name
を実行すればnameの項目の設定一覧が返ってくるので,それをパースすればおkです.
$ git config --get-regexp git-ls-date
git-ls-date.date relative
git-ls-date.format {ld: >20} {f}
1つだけ取得したい場合はgit config --get name.hoge
で取得できます.
$ git config --get git-ls-date.date
relative
気をつけたこと
他のライブラリに依存しない
サブコマンドを使うために他のライブラリに依存させるのは嫌だったので,ライブラリを使わないようにしました.
そのため,ファイルをwgetで取ってきてPATHの通った場所に置くだけでも使えるようになります.
cd ~/bin
wget https://raw.github.com/ton1517/git-ls-date/master/git_ls_date.py -O git-ls-date
chmod +x git-ls-date
複数バージョンで動作する
pythonは2系,3系とあり,サブコマンドがどちらかの環境でしか動かない,というのはめんどくさすぎるので,両方のバージョンに対応させました. 2.6⁄2.7⁄3.2⁄3.3で動作テストをしています.
テストをする
上記とも関係しますが,複数バージョンで動作確認するためには,自動で複数バージョンのテストをさせないとやってられません.
今回は単体テストをnose(とmock)で書き,それをtoxを使って複数バージョンで実行させました. さらにdetoxを使うことで,複数バージョンのテストを並列で実行させることができます.
作ってみると思ったより簡単にサブコマンドを作れました. 皆さんも自分で便利なサブコマンドを作って,より良いgitライフを!