Just a simple snippet to show some basic statistics regarding git commits:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
require 'open3'
require 'date'

def get_commit_list(author_name)
commit_list = []

git_log_command = "git log --author='#{author_name}' --pretty='format:%H|%ad|%an' --numstat"
Open3.popen3(git_log_command) do |stdin, stdout, stderr, wait_thr|
commit_info = {}

stdout.each_line do |line|
# puts "line: #{line.strip}"

if line =~ /\|/
# start of this commit
commit_id, date_str, author = line.chomp.split("|")
date = Date.parse(date_str)

commit_info = {
commit_id: commit_id,
date: date,
author: author,
added_lines: 0,
removed_lines: 0
}
elsif line =~ /^(\d+)\s+(\d+)/
added_lines = $1.to_i
removed_lines = $2.to_i
commit_info[:added_lines] += added_lines
commit_info[:removed_lines] += removed_lines
elsif line.strip.empty?
## end of this commit
commit_list << commit_info
end
end

# Add the last commit to the list
commit_list << commit_info unless commit_info.empty?
end

commit_list
end

def commits_histogram(commits)
histogram = Hash.new { |hash, key| hash[key] = { commits: 0, added_lines: 0, removed_lines: 0 } }

commits.each do |commit|
year = commit[:date].year

# calendar- or fiscal- year
start_new_year = Date.new(year, 1, 1)
# start_new_year = Date.new(year, 7, 1)

# Determine the appropriate year for the commit
target_year = commit[:date] >= start_new_year ? year : year - 1

hist = histogram[target_year]
hist[:commits] += 1
hist[:added_lines] += commit[:added_lines]
hist[:removed_lines] += commit[:removed_lines]
end

# Descending order: reversed chronological order
histogram.sort.reverse.to_h
end

COLOR_GREEN = 32
COLOR_RED = 31

def colorize(text, color_code)
"\e[#{color_code}m#{text}\e[0m"
end

def format_added(num)
text = format('+%5d', num)
colorize(text, COLOR_GREEN)
end

def format_removed(num)
text = format('-%5d', num)
colorize(text, COLOR_RED)
end

def format_net(num)
color_code = num >= 0 ? COLOR_GREEN : COLOR_RED
text = format('%5d', num)
colorize(text, color_code)
end

author_name = 'First \(Middle \)\?Last'

commits = get_commit_list(author_name)

histogram = commits_histogram(commits)

puts "Yearly stats:"
total_commits = 0
total_added_lines = 0
total_removed_lines = 0

histogram.each do |year, data|
net_color = data[:added_lines] >= data[:removed_lines] ? COLOR_GREEN : COLOR_RED

commits_line = format('%4d: %3d commits; LOC: %s, %s, net: %s',
year, data[:commits],
format_added(data[:added_lines]),
format_removed(data[:removed_lines]),
format_net(data[:added_lines] - data[:removed_lines])
)
puts commits_line

total_commits += data[:commits]
total_added_lines += data[:added_lines]
total_removed_lines += data[:removed_lines]
end

puts "===="
sum_line = format("Sum: %4d commits; LOC: %s, %s, net: %s",
total_commits,
format_added(total_added_lines),
format_removed(total_removed_lines),
format_net(total_added_lines - total_removed_lines)
)
puts sum_line

Output:

1
2
3
4
5
6
7
Yearly stat:
2023: 64 commits; LOC: + 1098, - 2680, net: -1582
2022: 150 commits; LOC: + 1932, - 4668, net: -2736
2021: 126 commits; LOC: + 2152, - 3709, net: -1557
2020: 48 commits; LOC: + 1449, - 1427, net: 22
====
Sum: 388 commits; LOC: + 6631, -12484, net: -5853