Created
February 28, 2012 22:26
-
-
Save zerowidth/1935703 to your computer and use it in GitHub Desktop.
git cleanup script
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
#!/bin/bash | |
# inspired by https://gist.github.com/1564252 | |
RED=$(tput setaf 1) | |
GREEN=$(tput setaf 2) | |
BLUE=$(tput setaf 4) | |
CYAN=$(tput setaf 6) | |
RESET=$(tput sgr 0) | |
function header() { | |
echo $1 | tr '[:print:]' '-' | |
echo $BLUE$1$RESET | |
echo $1 | tr '[:print:]' '-' | |
} | |
function debug() { | |
[[ $DEBUG ]] && { | |
echo "-" $@ >&2 | |
} | |
} | |
# Check for "real" merges | |
# | |
# Returns an empty string unless the branch has been merged. | |
function merged_normally() { | |
debug "checking normal merges" | |
git branch --list --merged origin/master $1 | |
} | |
# Checks for branches that have been entirely cherry-picked into master | |
# | |
# Returns an empty string unless the branch has been merged. | |
function merged_via_cherry_pick() { | |
debug "checking merges via cherry-pick" | |
[[ -z `git cherry origin/master $1 | grep "+"` ]] && { | |
echo "merged" | |
} | |
} | |
# Checks for branches that have been applied as a squashed patch. | |
# | |
# This is fairly brittle - if there's any overlap at all with a feature branch | |
# that has multiple patches and other commits that touch the same things, this | |
# won't be able to figure out that the branch has been applied. For smaller | |
# feature branches and bugfixes that are kept rebased and applied quickly, this | |
# should suffice. | |
# | |
# Returns an empty string unless the branch has been merged. | |
function merged_via_patch() { | |
debug "checking merges via patch" | |
merge_base=`git merge-base origin/master $1` | |
patch_id=`git diff $merge_base $1 | git patch-id | cut -d' ' -f1` | |
# only look at 50 commits, especially for old branches. if it hasn't been | |
# applied as a patch by then, it probably hasn't been applied | |
for sha in `git rev-list $merge_base..origin/master | tail -50`; do | |
line=`git show $sha | git patch-id | grep $patch_id` | |
[[ $line ]] && { | |
echo $line | |
break | |
} | |
done | |
} | |
function usage() { | |
cat << usage | |
Usage: cleanup -f [remotes] | |
List or remove branches from your local working copy and the listed remotes that | |
have had their changes integrated into origin/master. | |
NOTE: -f must come first, before any other arguments! | |
Options: | |
-h: this help message | |
-f: actually do the cleanup, don't just list out the status | |
usage | |
} | |
force=0 | |
[[ $ARGS == "--help" ]] && { | |
usage | |
exit | |
} | |
while getopts "hfo:" option | |
do | |
case $option in | |
h) | |
usage | |
exit | |
;; | |
f) | |
force=1 | |
;; | |
?) | |
usage | |
exit | |
;; | |
esac | |
shift $((OPTIND-1)) # remove the arg from $@ | |
done | |
# [[ "$@" = "" ]] && { | |
# echo -e "\nAt least one remote is required, e.g. '$(whoami)' or 'collab'\n" | |
# exit | |
# } | |
git diff --quiet | |
if [[ $? != 0 ]]; then | |
echo -e "\nSorry, can't do this on a dirty working copy! git stash first.\n" | |
exit | |
fi | |
[[ $force == "1" ]] && { | |
echo "${GREEN}updating remotes...${RESET}" | |
git fetch --all --prune | |
} | |
function cleanup() { | |
branch=$1 | |
remote=$2 | |
header $branch | |
if [[ | |
"$(merged_normally $branch)" || | |
"$(merged_via_cherry_pick $branch)" || | |
"$(merged_via_patch $branch)" ]]; then | |
echo "${GREEN}branch has been applied$RESET" | |
[[ $force == 1 ]] && { | |
echo | |
read -p "delete ${branch}? [y/N] " | |
if [[ "$REPLY" == "y" ]]; then | |
if [[ $remote ]]; then | |
rbranch=`echo $branch | sed "s/^$remote\///"` | |
echo "${RED}removing remote branch $rbranch from ${remote}${RESET}" | |
git push $remote :$rbranch | |
else | |
echo "${RED}removing local branch ${branch}${RESET}" | |
git branch -D $branch | |
fi | |
else | |
echo "skipping..." | |
fi | |
} | |
# TODO figure out what other branches are the same based on SHA, and ask to | |
# delete all of them, instead of having explicit remotes | |
# git branch --all --contains <sha> will do it | |
else | |
merge_base=`git merge-base origin/master $branch` | |
unmerged=`git rev-list $merge_base..$branch | wc -l | sed 's/ //g'` | |
echo "$unmerged commits are not in master:" | |
echo | |
git --no-pager log --shortstat --oneline $merge_base..$branch | |
fi | |
echo | |
} | |
# if [[ $@ == "" ]]; then | |
for branch in `git branch | grep -v "*" | grep -v master | cut -c3-`; do | |
cleanup $branch | |
done | |
# fi | |
for remote in $@; do | |
for remote_branch in `git branch -r | grep " $remote/" | grep -v master`; do | |
cleanup $remote_branch $remote | |
done | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment