Skip to content

Instantly share code, notes, and snippets.

@jjb
Last active March 25, 2025 13:36
Show Gist options
  • Save jjb/4129e13c810e8b5dcc5738e6c425c636 to your computer and use it in GitHub Desktop.
Save jjb/4129e13c810e8b5dcc5738e6c425c636 to your computer and use it in GitHub Desktop.
delete old branches on github
#!/usr/bin/env ruby
require 'date'
require 'shellwords'
REMOTE = 'origin'
PROTECTED_BRANCHES = ['master']
YEARS_OLD = 2
def run_command(cmd)
puts " Running: #{cmd}" if ENV['DEBUG']
`#{cmd}`.chomp
end
cutoff_date = (Date.today - (YEARS_OLD * 365)).to_s
puts "Checking for branches older than #{cutoff_date}"
run_command("git fetch #{REMOTE} --prune")
remote_branches = run_command("git branch -r --list '#{REMOTE}/*' --format='%(refname:short)'")
.split("\n")
.reject { |b| b.end_with?('HEAD') }
branches_to_delete = []
remote_branches.each do |branch|
print '.'
next if PROTECTED_BRANCHES.any? { |protected| branch.end_with?(protected) }
last_commit_date = run_command("git log -1 --format=%ai #{Shellwords.escape(branch)}")
date_only = last_commit_date.split(' ').first
if date_only < cutoff_date
branches_to_delete << { branch: branch, last_commit: date_only }
end
rescue
require 'irb'; binding.irb
end
puts
if branches_to_delete.any?
puts "The following branches will be deleted:"
branches_to_delete.each do |b|
puts " #{b[:branch]} (last commit: #{b[:last_commit]})"
end
puts
puts "Press enter to delete the branches, control-c to quit"
gets
branches_to_delete.each do |b|
run_command("git push #{REMOTE} --delete #{Shellwords.escape(b[:branch]).gsub("#{REMOTE}/", '')}")
end
else
puts "No branches older than #{YEARS_OLD} years found."
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment