Skip to content

Instantly share code, notes, and snippets.

@mkasberg
Created August 31, 2022 02:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkasberg/18e1c3fcf5081ee747cc3d4cd41bf233 to your computer and use it in GitHub Desktop.
Save mkasberg/18e1c3fcf5081ee747cc3d4cd41bf233 to your computer and use it in GitHub Desktop.
Commit Message Ratio - a made up ratio defined as the ratio of the number of words in the message body to the lines of code changed
#!/usr/bin/env ruby
# Define the "commit message ratio" as (commit_body_words / commit_lines_changed).
#
# With no args, this script will find the commit message ratio of all commits in
# the git repo in the pwd, and will sort them by that ratio.
# (Commits with a high commit message ratio tend to be interesting commits!)
#
# With a commit hash as the only arg, provide the commit message ratio of that commit.
#
# Runs using git in the PWD.
def all_ratios
# Adapted from
# https://gist.github.com/samvrlewis/a4545386adb99556e7ff629d377e1769
msg_wc_out = `git rev-list --no-merges "${1:-HEAD}" | while read rev; do echo "$(git show -s --format='%b' $rev | wc -w) words: $rev"; done`
msg_wc_hash = msg_wc_out.lines.map { |line|
parts = line.split(":").map(&:strip)
words = parts.first.match(/(\d+) words/)[1].to_i
[parts.last, words]
}.to_h
# Adapted from
# https://stackoverflow.com/questions/21137477/how-to-get-git-log-with-short-stat-in-one-line
loc_out = `git log --oneline --pretty="@%H" --stat | grep -v \\| | tr "\\n" " " | tr "@" "\\n"`
loc_hash = loc_out.lines.map { |line|
line.match(/(?'commit'[0-9a-z]+) \d+ files? changed(?:, (?'ins'\d+) insertions?\(\+\))?(?:, (?'del'\d+) deletions?\(\-\))?/)
}.select { |m| !m.nil? }.map { |matches|
insertions = matches.named_captures['ins'].to_i || 0
deletions = matches.named_captures['del'].to_i || 0
[matches['commit'], insertions + deletions]
}.select { |_, lines| lines > 0 }.to_h
subject_out = `git log --pretty="%H::::%s"`
subjects = subject_out.lines.map { |line|
parts = line.split("::::").map(&:strip)
[parts.first, parts.last]
}.to_h
ratios = loc_hash.map { |commit, lines_changed|
msg_wc = msg_wc_hash[commit]
{commit: commit, ratio: (msg_wc.to_f / lines_changed).round(2), subject: subjects[commit]}
}
pp ratios.sort_by { |data| - data[:ratio] }
end
def single_ratio(commit)
msg_wc = `git show -s --format='%b' #{commit} | wc -w`.to_i
loc_out = `git log --oneline --pretty="@%H" --stat #{commit} ^#{commit}^ | grep -v \\| | tr "\\n" " " | tr "@" "\\n"`.strip
matches = loc_out.match(/(?'commit'[0-9a-z]+) \d+ files? changed(?:, (?'ins'\d+) insertions?\(\+\))?(?:, (?'del'\d+) deletions?\(\-\))?/)
insertions = matches.named_captures['ins'].to_i || 0
deletions = matches.named_captures['del'].to_i || 0
loc = insertions + deletions
puts " Word Count: #{msg_wc}"
puts " LOC: #{loc}"
puts "Commit Message Ratio: #{msg_wc.to_f / loc}"
end
if ARGV.size == 0
all_ratios
else
single_ratio(ARGV.first)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment