Skip to content

Instantly share code, notes, and snippets.

@oggy
Created October 8, 2015 18:32
Show Gist options
  • Save oggy/e86aab056cc42092a97d to your computer and use it in GitHub Desktop.
Save oggy/e86aab056cc42092a97d to your computer and use it in GitHub Desktop.
Command to delete old remote branches
#!/usr/bin/env ruby
require 'time'
class App
CUTOFF_DAYS = 30
def initialize(args)
args.size <= 1 or
abort "USAGE: #$0 [remote]"
@remote = args.first || 'origin'
end
def run
branches = stagnant_branches
if confirm(branches)
delete_branches(branches)
else
abort 'Aborted.'
end
end
private
def stagnant_branches
cutoff = Time.now - CUTOFF_DAYS*24*60*60
all_branches.select { |b| b.last_updated_at.nil? || b.last_updated_at < cutoff }
end
def all_branches
`git branch --no-color -r`.lines.map do |line|
line =~ /\A..#@remote\/(\S+)/ or
next
Branch.new(@remote, $1)
end.compact.sort_by { |b| b.last_updated_at || Time.at(0) }.reverse
end
def confirm(branches)
branches.each do |branch|
puts " #{branch.info}"
end
$>.sync = true
loop do
$>.print "Delete these branches? [y/n] "
case $<.gets.strip
when /\Ay(?:es)?\z/i
return true
when /\Ano?\z/i
return false
end
end
end
def delete_branches(branches)
puts "Deleting:"
branches.each do |branch|
puts " #{branch.name}: #{branch.sha}"
end
refspecs = branches.map { |b| ":#{b.name}" }
#sh "git push #@remote #{refspecs.join(' ')}"
end
def sh(command)
puts "++ #{command}"
system command
end
class Branch
def initialize(remote, name)
@remote = remote
@name = name
end
attr_reader :remote, :name
def last_updated_at
@last_updated_at ||= find_last_reflog_date || find_last_commit_date
end
def info
if num_commits > 0
"#{name} - #{age}, #{num_commits} commits by #{authors.join(', ')}"
else
"#{name} - #{age}, no commits"
end
end
def sha
`git log -n 1 --format=%H #@remote/#@name`.chomp
end
private
def age
if last_updated_at
seconds_ago = Time.now - last_updated_at
days_ago = (seconds_ago / 24 / 60 / 60).round
"#{days_ago} days old"
else
"age unknown"
end
end
def num_commits
@num_commits ||= commits.size
end
def authors
@authors ||= commits.map { |sha, author| author.split(/&/).map(&:strip) }.flatten.uniq.sort
end
def commits
@commits ||= `git log --format=%H:%an #@remote/master..#@remote/#@name`.lines.map do |line|
line.chomp.split(/:/)
end
end
def find_last_reflog_date
output = `git log -g -n 1 --date=local --pretty=%gd #@remote/#@name`
time_string = output[/(?<=@\{)(.*)(?>\})/] or
return nil
DateTime.parse(time_string).to_time
end
def find_last_commit_date
output = `git log -n 1 --format=%cd #@remote/#@name`.chomp
DateTime.parse(output).to_time
end
end
end
App.new(ARGV).run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment