Gitのログをワンライナーで整形する

  • 12
    いいね
  • 1
    コメント

Git Advent Calendar 2016の枠が空いていたのでおじゃまします。続編と合わせてよろしくお願いします。


はじめに

この記事はGitのログをPythonを使って集計し、品質管理・分析に役立てる方法を考察した記事の序章として、コマンドのみでワンライナーでログを集計できる手法をまとめたものです。まとめると記事が長くなったので分離しました。

git log コマンドはいつ誰が何をどのようにコミットしたかを知ることができる、バージョン管理に欠かせない便利なツールです。しかしこれを品質の管理・分析に活かそうとしたら少し工夫が必要です。そこでまず、コマンドを駆使してGitのログをワンライナーで整形する手法をまとめてみました。

コミットの多いファイルの特定(--name-only オプションの利用)

まずはじめに、たくさんコミットされているファイルを特定するコマンドについてまとめてみました。開発期間中にたくさんコミットされているファイルはそれだけバグが含まれている可能性も高くなるため、リスクベースでテスト計画をたてる時などにログを活用できます。

コミット数の多いファイルTop10

$ git log --name-only --pretty="format:" | grep -ve '^$' | sort | uniq -c | sort -r | head

コミットログからファイル名のリストを抽出した後、1回目の sort によってファイル名で並び替えし、 uniq で重複するファイルを集約してカウントし、2回目の sort でカウントが多い順に並び替えて head で上位10件を出力しています。

git log --name-only --pretty="format:" | grep -ve '^$' までがコミットログからファイル名を抜き出す手法で、知っておけば色々応用ができます。

変更された行数のカウント(--numstatオプションの利用)

ステップ数を品質や生産性の指標として使うのは古(いにしえ)より伝わる古典的手法ですが、目的は色々ありますが行数をカウントすることはいまだによくあるのではないでしょうか。

全追加・削除行数

$ git log --numstat --pretty="%H" | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("+%d, -%d\n", plus, minus)}'

git log --numstat --pretty="%H" を使うと以下のように追加行数、削除行数、ファイル名が出力されるためそれを awkで集計しています。

急にawkが出てきましたが、以下のように1行のログがスペースで区切られた3つの要素で出力されていて、1つ目と2つ目がファイルごとの追加行数、削除行数なので、それをawkでひたすら足し算していくだけです。

10       23       README.md

ファイル単位の追加行数、削除行数

次はファイル単位の追加行・削除行のTop10を出力する例です。

$ git log --numstat --pretty="%H" | awk 'NF==3 {add_sum[$3]+=$1; del_sum[$3]+=$2} END {for (key in add_sum) {printf("%d, %d, %s\n", add_sum[key],del_sum[key],key)}}' | sort -k1,1nr -k2,2nr -t,| head 

awkがもはや無理やり感いっぱいで1行にまとめられています。上記はコミット単位の集計なので同じファイルを何回もコミットした場合、別々に変更行が出力されます。これをさらにファイル単位にまとめて集計してみたいところですが、これ以上awkを駆使すると目的が変わってしまうので今回はここまでにしておきます。

ログの取得範囲を絞り込む

最後に視点を変えてログの対象となる範囲を指定する方法についてまとめます。コマンドを駆使するわけではなくgit logのオプションの紹介です。

Commit Limitingによる絞り込み

例えばプロジェクトの開発期間で絞りたい場合は--since --untilなどを使います。git logCommit Limiting の仕様を確認することで様々な絞込みができます。

例)6カ月内にコミットされた、コミット数の多いファイルTop10

$ git log --name-only --pretty="format:" --since="6 months ago" | grep -ve '^$' | sort | uniq -c | sort -r | head

ブランチの差異による絞り込み

ダブルドット構文 .. を使ってブランチ同士のログの差異を取得する方法もあります。revision range の仕様で確認できます。例えば experimentmaster にマージされる前の変更点を確認する場合は以下のようにします。

例)ブランチを切ってからコミット数の多いファイルTop10

$ git log --name-only --pretty="format:" master..experiment | grep -ve '^$' | sort | uniq -c | sort -r | head

なお、トリプルドット構文というのもあります。詳細はコミットの範囲指定の記事が参考になります。

おわりに

以上のようにワンライナーでもある程度のことができますが、品質管理というよりはコマンドで出来ることを基準に考えてしまいがちなので、次回はPythonを使ってGitのログを活用する発展的な手法を考えてみます。続きは ラクス Advent Calendar 2016へ投稿する予定です。

参考

git リポジトリからプロジェクトの概要をつかむ
gitでnumstatを利用して総追加行数、総削除行数を取得するワンライナー
branchを切った時点のコミットとbranchの最新コミットとのlogとdiffをみたい