@ledsun blog

Hのキーがhellで、Sのキーがslaveだ、と彼は思った。そしてYのキーがyouだ。

続々 Gitのdiffを振り返る

続 Gitのdiffを振り返る - @ledsun blog で1000行以上の変更があるコミットはツールによるフォーマット変更であることがわかりました。

また、日付でまとめてしまうと一日の変更行数が2000を超えます。 これはgit rev-listのbeforeやafterの挙動によるものです。 必ずしもコミットした日にまとまっていません。

例えば、つぎとコミットがあったとします。

  • 1/10に機能追加のコミットA
  • 1/15にバグ修正のコミットB

バグ修正を先にpushしたかったので、rebaseして、コミットBをコミットAの前に移動します。 するとコミットAは1/15日以降のコミットにカウントされます。 このように実際の作業日とはずれて集計されます。 特にリリース直前の日に作業が固まりやすい傾向があります。

そこで期間中の全コミットをもってきて、そのままグラフ化します。

次のRubyスクリプトを使います。

require "Time"

Commit = Struct.new(:at, :insertions, :deletions)

# カウントしたくないファイルを除外
EXCLUDE = "':(exclude)package-lock.json' ':(exclude)*.min.js' ':(exclude)*.css' ':(exclude)dist/*' ':(exclude)dev/vender' ':(exclude)src/lib/modules' ':(exclude)*.md'"

`git log --after='2019-05-22 00:00' --format=format:'---%n%ai' --shortstat #{EXCLUDE}`
  .split("---\n")[1..] # 1行目は空なので捨てる
  .map { _1.split("\n") }
  .filter { |time, stats| !stats.empty? } # 除外しているファイルがあるのでstatsが出ないことがある
  .map { |time, stats| Commit.new(Time.parse(time), stats.split(",")[1].to_i, stats.split(",")[2].to_i) } # " 1 file changed, 10 insertions(+), 9 deletions(-)" をパース
  .filter { _1.insertions < 1000 } # 1000行以上の変更はツールによるので除外する
  .sort_by { _1.at.to_i }
  .each { puts "#{_1.at.strftime("%F_%T")} #{_1.insertions} #{_1.deletions}" }

次のような行が3000行続きます。

2020-12-25_17:22:45 4 4
2020-12-25_17:24:41 10 9
2020-12-25_17:27:11 9 3

結果をファイルにいれてgnuplotで表示します。

gnuplot> set xdata time
gnuplot> set timefmt "%Y-%m-%d_%H:%M:%S"
gnuplot> plot 'all_log.dat' using 1:2 with line title 'insertions', 'all_log.dat' using 1:3 with line title 'deletions'

f:id:ledsun:20201229222555p:plain
Gitコミット毎 の ファイルへの追加行数と削除行数

2019年と2020年で、プログラミングのピーク性能は特段変わっていないことがわかりました。