Skip to content

Instantly share code, notes, and snippets.

@smoser
Created September 23, 2020 17:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smoser/7615c929bf87be0bf5794270176bacd7 to your computer and use it in GitHub Desktop.
Save smoser/7615c929bf87be0bf5794270176bacd7 to your computer and use it in GitHub Desktop.
git branch cleanup tool, for deleting local and remote branches

git-branch-cleanup

git-branch-cleanup basically just allows me to do housekeeping more easily on my many branches.

#!/bin/bash
REMOTE="smoser"
VERBOSITY=0
TEMP_D=""
error() { echo "$@" 1>&2; }
errorp() { printf "$@" 1>&2; }
failp() { [ $# -eq 0 ] || errorp "$@"; exit 1; }
fail() { local r=$?; [ $r -eq 0 ] && r=1; failrc "$r" "$@"; }
failrc() { local r=$1; shift; [ $# -eq 0 ] || error "$@"; exit $r; }
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] <<ARGUMENTS>>
<<SUMMARY HERE>>
options:
<<OPTIONS HERE>>
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
cleanup() {
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
}
debug() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
error "${@}"
}
delRemote() {
local branch="$1" out="" r=""
out=$(git show "$REMOTE/$branch" 2>&1)
r=$?
if [ $r -eq 128 ]; then
# fatal: ambiguous argument '<remote>/<branch>': unknown revision or path...
echo "$branch does not exist on $REMOTE"
return 0
fi
out=$(git push --delete $REMOTE "$branch") && return 0
r=$?
case "$r:$out" in
1:*remote\ ref\ does\ not\ exist)
echo "$branch did not exist on $REMOTE. use git prune $REMOTE."
return 0
esac
error "Failed to delete branch $branch on remote $REMOTE"
return 1
}
delBranch() {
local branch="$1"
git branch --delete "$branch" || {
error "Failed to remove branch $branch. try D?"
return 1
}
delRemote "$branch"
}
delBranchForce() {
local branch="$1"
echo branch=$branch
git branch --delete --force "$branch" || return
delRemote "$branch"
}
main() {
local short_opts="ho:v"
local long_opts="help,output:,verbose"
local getopt_out=""
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return; }
local cur="" next=""
while [ $# -ne 0 ]; do
cur="$1"; next="$2";
case "$cur" in
-h|--help) Usage ; exit 0;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
--) shift; break;;
esac
shift;
done
git fetch "$REMOTE" || fail "probably your remote \$REMOTE ($REMOTE) is wrong"
#[ $# -ne 0 ] || { bad_Usage "must provide arguments"; return; }
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
fail "failed to make tempdir"
trap cleanup EXIT
set -f
local dataf="${TEMP_D}/data"
show "|" > "$dataf" || fail "Failed to show data"
local oifs="$IFS"
# read fd 3
echo "([s]kip, i[nfo] l[og], d[elete] D[force del] q[uit])"
exec 3<"$dataf" || fail "failed to get fd"
while read -u 3 line; do
IFS="|"; set -- $line; IFS="$oifs"
branch="$1"; hash="$2"; date="$3"; subject="$4"
while :; do
read -p "$date $hash $branch | $subject ?" action
case "$action" in
s) :;; # skip
i) git show "$branch"; continue;;
l) git log "$branch"; continue;;
d) delBranch "$branch" || continue;;
D) delBranchForce "$branch" || continue;;
q) exit;;
*) echo "bad action: $action"; continue;;
esac
echo
break
done
done
IFS="$oifs"
return 0
}
#!/bin/sh
# https://stackoverflow.com/questions/5188320/how-can-i-get-a-list-of-git-branches-ordered-by-most-recent-commit
show() {
local d="${1:- }"
local fmt="%(refname:short)$d%(objectname:short)$d%(committerdate:iso)$d%(subject)"
set -- git for-each-ref --sort=committerdate refs/heads/ --format="$fmt"
"$@" || {
error "Failed to execute command: $*"
return 1
}
return 0
}
main "$@"
# vi: ts=4 expandtab
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment