Skip to content

Instantly share code, notes, and snippets.

@jamesarosen
Created December 13, 2016 21:47
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 jamesarosen/7dab76495c2fbbe28baa18509f07bbee to your computer and use it in GitHub Desktop.
Save jamesarosen/7dab76495c2fbbe28baa18509f07bbee to your computer and use it in GitHub Desktop.
Generate a histogram of line changes (insertions + deletions) from a GitHub repo, bucketed by week
require 'time'
class Commit
DATE = /^Date: +(\w{3} \w{3} \d{1,2}.+)$/
MERGE = /^Merge: +([a-z0-9]+) ([a-z0-9]+)$/
CHANGES = /^ *\d+ files? changed(?:, (\d+) insertions?...)?(?:, (\d+) deletions?...)? *$/
attr_reader :sha
def self.sha_for(pointer)
`git rev-list -n 1 #{pointer}`.strip
end
def initialize(pointer)
@sha = self.class.sha_for pointer
@stat = `git show #{@sha} --stat`
end
def year_week
@year_week ||= begin
match = DATE.match(@stat)
throw "No Date info in #{@stat}" unless match
Time.parse(match[1]).strftime('%G-%V')
end
end
def parent
@parent ||= begin
pointer = is_merge? ? MERGE.match(@stat)[1] : "#{@sha}~1"
Commit.new(pointer)
end
end
def change_count
@change_count ||= begin
match = CHANGES.match(@stat)
raise "No change info in #{@stat}" unless match
(match[1] || 0).to_i + (match[2] || 0).to_i
end
end
def same_sha?(other)
if other.is_a?(Commit)
sha == other.sha
else
sha == self.class.sha_for(other)
end
end
def is_merge?
@is_merge ||= MERGE =~ @stat
end
def inspect
"<Commit sha:#{sha.slice(0, 8)} bucket:#{year_week} lines:#{change_count}>"
end
end
class Histogram
def initialize
@buckets ||= {}
end
def <<(commit)
@buckets[commit.year_week] ||= 0
@buckets[commit.year_week] += commit.change_count
end
def print
@buckets.keys.sort.reverse.each do |week|
puts "#{week} #{@buckets[week]}"
end
end
end
def each_commit(start_pointer, end_pointer, &block)
current = Commit.new(start_pointer)
while !current.same_sha?(end_pointer)
yield current
current = current.parent
end
end
def run
if ARGV.length != 2
puts 'USAGE: ruby git-changes-histogram.rb head head~1000'
end
histogram = Histogram.new
each_commit ARGV[0], ARGV[1] do |commit|
histogram << commit
end
histogram.print
end
run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment