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 |