Last active
October 8, 2023 23:21
-
-
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.
This file contains 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 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