-
-
Save scotje/58257c6f7815cb0c0575 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'rubygems' | |
require 'fileutils' | |
require 'word_salad' | |
def decorate_log_with_branch(log, branch_name, root_sha, origin=[]) | |
cursor = root_sha | |
log[root_sha][:branch] = branch_name | |
while prev = log[cursor][:parents][0] do | |
# Break if we are following a branch and we reach the common ancestor. | |
break if origin.include?(prev) | |
log[prev][:branch] = branch_name | |
cursor = prev | |
end | |
end | |
def random_branch_name | |
candidate = 2.words.join("_") | |
while @_names_used.include?(candidate) | |
candidate = 2.words.join("_") | |
end | |
@_names_used << candidate | |
return candidate | |
end | |
@_names_used = [] | |
repo = ARGV[0] | |
mainline_branch = ARGV[1] | |
replay_depth = ARGV[2] | |
# R.I.P. memory | |
puts "Parsing git-log..." | |
commits_array = `/usr/bin/env GIT_DIR=#{repo} git log --branches --format="%H%x09%P%x09%s"`.lines.collect do |log_line| | |
sha, parents, subject = log_line.split("\t") | |
[sha, {parents: parents.split(" "), subject: subject}] | |
end | |
log = Hash[commits_array] | |
puts "Finding main branch history..." | |
mainline_head = `/usr/bin/env GIT_DIR=#{repo} git rev-parse #{mainline_branch}`.strip | |
decorate_log_with_branch(log, mainline_branch, mainline_head) | |
mainline_history = log.map { |sha, commit| sha if commit[:branch] == mainline_branch }.compact! | |
puts "Finding unmerged branches..." | |
head_refs_array = `/usr/bin/env GIT_DIR=#{repo} git show-ref --heads`.lines.collect do |ref_line| | |
sha, branch = ref_line.split(" ") | |
branch.gsub!(/refs\/heads\//, '') | |
@_names_used << branch | |
[branch, sha] | |
end | |
head_refs = Hash[head_refs_array] | |
head_refs.delete(mainline_branch) # We already walked mainline branch | |
head_refs.each do |branch, sha| | |
decorate_log_with_branch(log, branch, sha, mainline_history) | |
end | |
if depth = replay_depth.to_i | |
puts "Trimming to last #{depth} commits..." | |
trimmed_log = log.take(depth) | |
else | |
trimmed_log = log | |
end | |
puts "Finding merged branches..." | |
trimmed_log.each do |sha, commit| | |
if mainline_history.include?(sha) && commit[:parents].size == 2 | |
new_branch = random_branch_name | |
log[sha][:ends_branch] = new_branch | |
decorate_log_with_branch(log, new_branch, commit[:parents][1], mainline_history) | |
end | |
end | |
puts "Pruning orphan commits..." | |
trimmed_log.reject! { |sha, commit| !commit[:branch] } | |
puts "Replaying commits in original order, send USR1 to PID #{Process.pid} to advance..." | |
trimmed_log.reverse_each do |sha, commit| | |
@next = false | |
Signal.trap("USR1") { @next = true } | |
sleep(0.5) until @next | |
log_line = " #{commit[:branch]} -> #{sha}" | |
File.open("#{repo}/refs/heads/#{commit[:branch]}", "w") do |f| | |
f.puts(sha) | |
end | |
if commit[:ends_branch] && File.exists?("#{repo}/refs/heads/#{commit[:ends_branch]}") | |
FileUtils.rm("#{repo}/refs/heads/#{commit[:ends_branch]}", force: true) | |
log_line << " (Deleted branch #{commit[:ends_branch]})" | |
end | |
puts log_line | |
end | |
puts "Done!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment