Skip to content

Instantly share code, notes, and snippets.

@apainintheneck
Last active October 8, 2023 23:21
Show Gist options
  • Save apainintheneck/bb2be57296a41fdf0979b8db36da6f56 to your computer and use it in GitHub Desktop.
Save apainintheneck/bb2be57296a41fdf0979b8db36da6f56 to your computer and use it in GitHub Desktop.
An interactive way to trim unused or unwanted git branches in the current directory.
#!/usr/bin/env awk -f
# An interactive way to trim unused or unwanted git branches in the current directory.
#
# 1. Go through the branches from oldest to newest.
# 2. Autoremove already merged-in branches.
# 3. Wait for user command on other branches.
#
# User commands:
# h: Help page
# l: Commit log
# d: Delete branch
# q: Quit
# : (Hit return to skip)
#
# Note:
# - It ignores the current branch and common branches (main, master, release, and develop).
BEGIN {
if(!is_git_installed()) exit(1)
if(!is_git_repo()) exit(1)
# Command line constants
git_with_color = "git -c color.ui=always "
pipe_to_less = " | less -Ri"
# Build list of branches to ignore
split("main master develop release", tmp)
for(i = 1; i <= length(tmp); ++i) {
ignore_branch[tmp[i]] = 1
}
ignore_branch[current_branch()] = 1
# Collect removable branchnames
while(git_branch_cmd() | getline line) {
split(line, args, "\t")
if(ignore_branch[args[1]]) continue
++total_branches
branch_name_list[total_branches] = args[1]
branch_update_list[total_branches] = args[2]
branch_author_list[total_branches] = args[3]
}
close(git_branch_cmd())
if(total_branches == 0) {
print "No branches to trim"
exit(0)
}
iterate_over_branches()
}
#---Event Loop---
## Interactive Commands
$1 == "h" { print_help(); next }
$1 == "l" { git_log($2); next }
$1 == "q" { exit(0) }
$1 == "d" { git_branch_D() }
# Unknown command
NF != 0 && $1 != "d" { print "?"; next }
{ iterate_over_branches() }
#---Functions---
## Main
function iterate_over_branches() {
while(++branch_idx <= total_branches) {
get_branch_info()
print_branch_info()
if(autoremove()) {
print "# Auto-removed merged-in branch"
} else {
print_prompt()
break
}
}
if(branch_idx > total_branches) exit(0)
}
## Utils
function print_branch_info() {
print "------------"
printf("branch: %s\n", branch_name)
printf("author: %s\n", branch_author)
printf("updated at: %s\n", branch_updated_at)
}
function autoremove() {
return git_branch_d()
}
function print_help() {
print "Commands:\n" \
"h:\tHelp page\n" \
"l:\tCommit log\n" \
"d:\tDelete branch\n" \
"q:\tQuit"
print_prompt()
}
function get_branch_info() {
branch_name = branch_name_list[branch_idx]
branch_updated_at = branch_update_list[branch_idx]
branch_author = branch_author_list[branch_idx]
}
function print_prompt() {
printf("* ")
}
## Git Commands
function is_git_installed() {
return system("git --version") == 0
}
function is_git_repo( cmd, res) {
cmd = "git rev-parse --is-inside-work-tree"
cmd | getline res
close(cmd)
if(res == "true") return 1
else {
print res
return 0
}
}
function current_branch( cmd, res) {
cmd = "git branch --show-current"
cmd | getline res
close(cmd)
return res
}
function git_log(limit, cmd) {
cmd = git_with_color " log " branch_name
if(limit ~ /[0-9]+/ && limit > 0) cmd = cmd " -n " limit
cmd = cmd pipe_to_less
system(cmd)
print_prompt()
}
function git_branch_d() {
return system("git branch -d " branch_name) == 0
}
function git_branch_D() {
return system("git branch -D " branch_name) == 0
}
# Returns the branches oldest to newest in the following format.
# '%(branch_name)\t%(last_updated)\t%(author)'
# It can easily be split on the tab character.
function git_branch_cmd( cmd) {
cmd = "git branch" \
" --sort='committerdate'" \
" --format='%(refname:short)\t%(committerdate:short)\t%(authorname)'"
return cmd
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment