ton-tech-ton

gitのサブコマンドを自分で作る

git, python

この記事はGit Advent Calendar 2013の12日目の記事です.
前日は@sonotsさんのgit current-branch, git fetch-pulls, git pull-dry-run など git alias ネタでした.

gitはコマンドを実行するとき,まずgit --exec-pathのパスの中からコマンドを探し,なければユーザーのPATHの中からコマンドを探して実行します.

1
2
$ git --exec-path
/usr/lib/git-core

そのためPATHの通った場所にgit-コマンド名という実行ファイルを置くだけでユーザーが自由にサブコマンドを作れる便利な仕組みとなっています.

ということで,pythonでgitのサブコマンドを作ってみました.

git-ls-date

ton1517/git-ls-date

このサブコマンドはファイルを最初にコミットした日付と最後にコミットした日付(とそのハッシュ)を表示するコマンドです.

こんな感じ

1
2
3
$ 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

最後にコミットした日時でファイルをソートしたり

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ 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

そのファイルを最後にコミットしたハッシュのみを表示させたり

1
2
3
$ git ls-date --format="{lh} {f}"
7ab1b16 README.rst
2826492 git_ls_date.py

githubっぽく最後にコミットした日付を相対日時で表示したりできます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
% 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を見てください.

1
pip install git-ls-date

でインストールできます.

git-ls-dateというコマンドが実行できるようになるので,git ls-dateでも実行できるというわけです.

gitconfigを使う

せっかくなので,gitのサブコマンドらしくgitconfigに設定を書けるようにします.

1
2
$ git config --global git-ls-date.date relative
$ git config --global git-ls-date.format "{ld: >20} {f}"

と実行すると.gitconfigの中に以下のように書き込まれます.

1
2
3
[git-ls-date]
  date = relative
  format = {ld: >20} {f}

このような項目はユーザーが自由に設定することができるので,あとはコマンド側でこれを読み取るようにするだけです.

読み取るにはgit config --get-regexp nameを実行すればnameの項目の設定一覧が返ってくるので,それをパースすればおkです.

1
2
3
$ 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で取得できます.

1
2
$ git config --get git-ls-date.date
relative

気をつけたこと

他のライブラリに依存しない

サブコマンドを使うために他のライブラリに依存させるのは嫌だったので,ライブラリを使わないようにしました.

そのため,ファイルをwgetで取ってきてPATHの通った場所に置くだけでも使えるようになります.

1
2
3
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ライフを!

明日は@horimislimeさんのgit mergeでコンフリクトが発生するか前もって調べる方法です.

Comments