Skip to content

Instantly share code, notes, and snippets.

@wincent
Created April 19, 2013 08:38
Show Gist options
  • Save wincent/5418980 to your computer and use it in GitHub Desktop.
Save wincent/5418980 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# Show how many lines people are "responsible" for, according to `git-blame`.
# optionally take a pathspec to use as a filter
pathspec = ARGV.any? ? "-- #{ARGV.join(' ')}" : ''
# grab all the files in the source tree, filtered by the pathspec
files = `git ls-tree -r HEAD #{pathspec}`.split("\n").map do |line|
metadata, path = line.split("\t")
end
# look only at blobs
paths = files.select { |metadata, _| metadata =~ /blob/ }.
map { |_, path| path.chomp }
global_stats = Hash.new(0)
BLAME_FORMAT_REGEX = Regexp.compile /^author-mail <(.+)>$/
paths.each do |path|
print "Processing : #{path}"
begin
file_stats = Hash.new(0)
blame = `git blame --line-porcelain HEAD -- #{path}`
blame.split("\n").each do |line|
next unless line.match(BLAME_FORMAT_REGEX)
author = $~[1]
global_stats[author] += 1
file_stats[author] += 1
end
most_guilty = file_stats.sort_by { |_, count| -count }.first(3)
if most_guilty.any?
authors = most_guilty.map { |author, count| "#{author} [#{count}]" }
print "; (most guilty: #{authors.join '; '})"
end
rescue StandardError => e
# don't choke on binary files or other unexpected input
print "; [***] rescued #{e}"
end
puts
end
# calculate appropriate width for display
longest_author = global_stats.keys.max { |a, b| a.length <=> b.length }
width = longest_author ? longest_author.length : 0
puts "\nOverall stats:"
global_stats.
sort_by { |_, count| -count }.
each { |author, count| puts " %#{width}s : %d" % [author, count] }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment