Skip to content

Instantly share code, notes, and snippets.

@TALlama
Last active May 16, 2024 17:01
Show Gist options
  • Save TALlama/70f2baf58111888a364c994a8b9075d7 to your computer and use it in GitHub Desktop.
Save TALlama/70f2baf58111888a364c994a8b9075d7 to your computer and use it in GitHub Desktop.
Keep your local git branches clean! This is a script I use to loop through all my local branches, then delete any branches that have already landed in upstream. It will notice if it landed as a merge commit or a rebase. It will list out what's merged and not for any branches it keeps, so you can tell what you should revisit and what you should g…
#!/usr/bin/env ruby
require "colorize"
class Branch
attr_reader :name, :base_branch
def initialize(name, base)
@name = name
@base_branch = base || %x{git log -1 --format="%h" @{u}}.chomp
end
def to_s
[
can_pit? ? "[PIT] " : "",
name,
"\n",
"-"*80,
"\n",
commits,
"\n",
"-"*80,
].flatten.join
end
def commits_to_s
return '' if commits.empty?
"# ".blue + commits.join("\n# ".blue)
end
def commits
@commits ||= %x{git cherry -v #{base_branch} #{name}}.chomp.split("\n").reject(&:empty?).map {|l| l.start_with?("+") ? l.green : l }
end
def can_pit?
@can_pit ||= commits.all? {|c| c.start_with? '-'}
end
def self.all_names
%x{git branch}.split - ["*"]
end
def self.find(base: nil, names: (ARGV.length > 0 ? ARGV : Branch.all_names))
names.map {|n| Branch.new(n, base)}
end
def self.current
@current ||= (%x{git branch}.split("\n").grep(/[*]/) || ['']).first[2..-1]
end
end
dry_run = ARGV[0] == '--dry-run'
ARGV.shift if dry_run
base_branch = (ARGV.shift; ARGV.shift) if ARGV[0] == '--branch'
all = Branch.find(base: base_branch)
puts "# PITTING #{"#"*70}".blue.bold
puts "# (dry run only; will not delete branches)".blue if dry_run
all.select(&:can_pit?).each do |b|
puts(*["git br -D #{b.name}", b.commits_to_s].reject(&:empty?))
if b.name == Branch.current
puts "# (can't delete; it's the current branch)".blue
else
%x{git br -D #{b.name}} unless dry_run
end
puts
end
puts "# KEEPING #{"#"*70}".blue.bold
all.reject(&:can_pit?).each {|b| puts "# keeping ".blue + b.name.blue.bold + "; green commits have not merged", b.commits_to_s, ""}
@TALlama
Copy link
Author

TALlama commented May 16, 2024

Sample output:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment