Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
executable file 160 lines (134 sloc) 5.5 KB
ABOUT_THIS_SCRIPT="
Q: Would you lose any work if your local clone of a git repository were lost?
A: Run this script to find out.
Please see the Readme.md for more discussion.
License: CC BY SA [creative commons, attribution, share-alike]
By Ben Klemens. See http://modelingwithdata.org/arch/00000194.htm for discussion.
Some portions based on:
http://0xfe.blogspot.com/2010/04/adding-git-status-information-to-your.html
http://0xfe.blogspot.com/2010/04/improved-git-enabled-shell-prompt.html
"
green="\033[0;32m"
bold_green="\033[1;32m"
cyan="\033[0;36m"
bold_cyan="\033[1;36m"
red="\033[0;31m"
bold_red="\033[1;31m"
no_color="\033[0m"
Red_X="${bold_red}✘${no_color}"
Check="${bold_cyan}✓${no_color}"
Divider="${bold_cyan}―――${no_color}"
Dirty=0
test "$1" = "-a"
Action=$?
onetest () { if eval $3 ; then printf "$Red_X $2\n"; Dirty=1; else printf "$Check $1\n"; fi }
# unpushed branches, which is the list of remote branches that are not synced to the local HEAD.
# Original author had:
## Returns "unpushed:N" where N is the number of unpushed local and remote branches (if any).
## local unpushed=`expr $( (git branch --no-color -r --contains $1; git branch --no-color -r) | sort | uniq -u | wc -l )`
# I just need to know that a given branch is contained by at least one remote.
# Assume the network of repos is not super-complicated so there's just the origin
allbranches(){
for i in `git branch --no-color | grep -v "(HEAD.*)" | sed 's/\* //'`; do
unpushed=`expr $( (git branch --no-color -r --contains $i) | wc -l )`
onetest "$i pushed to origin" "$i not pushed to origin" '[ "$unpushed" = "0" -o "`git branch -r`" = "" ]'
if [ "$unpushed" = "0" ] || [ "`git branch -r`" = "" ] ; then
if [ $Action = 0 ] ; then
echo -n "Run git push origin $i? [y/n] "
read yesno
if [ "$yesno" != "n" -a "$yesno" != 'N' ]; then
git push origin $i
fi
fi
fi
done
}
# Optional test to add for unmerged branches, if that's your workflow.
# local unmerged=`expr $(git branch --no-color -a --no-merged | wc -l)`
# onetest "no unmerged files" "unmerged files" '[ "$unmerged" != "0" ]'
# main sequence: run each test
if [ "$1" = "-h" ]; then echo "Check whether a git repository can be deleted. Use -a to automatically run some next steps."; fi
is_repository=$(git status > /dev/null 2> /dev/null; echo $?)
if [ $is_repository -gt 0 ]; then
printf "$Red_X Not a git repository\n"; Dirty=1;
if [ $Action -eq 0 ] ; then
echo -n "Initialize repository? [y/n] "
read yesno
if [ "$yesno" != "n" -a "$yesno" != 'N' ]; then
git init
fi
fi
fi
if [ $is_repository -eq 0 ]; then #skip to the end if not a repository
Untracked=$Dirty
if [ $Action -eq 0 ] && [ "$Untracked" != 0 ]; then git status -s; Action=1; fi;
onetest "no untracked files" "untracked files" '[ `git ls-files --others --exclude-standard | wc -l` -ne 0 ]'
Untracked=$Dirty
if [ $Action = 0 ] && [ "$Untracked" != 0 ]; then git status -s; Action=1; fi;
onetest "no unstaged diffs" "diffs to commit" '[ "$(git diff --shortstat 2> /dev/null)" != "" -o "$(git diff --staged --shortstat 2> /dev/null)" != "" ]'
Diffs=$((Dirty - Untracked))
if [ $Action = 0 ] && [ "$Diffs" != 0 ]; then git --no-pager diff; Action=1; fi;
stash=`expr $(git stash list 2>/dev/null| wc -l)` # Return the number of stashed states, not just 0|1.
onetest "no pending stashes" "stashes pending" '[ "$stash" != "0" ]'
if [ $Action = 0 ] && [ "$stash" != "0" ] ; then
if [ $stash -eq 1 ]; then
git --no-pager stash show -p
elif [ $stash != 0 ]; then
git stash list
fi
Action=1
fi
unpushed_tags=`git show-ref --tags | grep -v -F "$(git ls-remote --tags origin | grep -v '\^{}' | cut -f 2)" | sed 's#.*tags/##'`
onetest "no unpushed tags" "unpushed tags: $unpushed_tags" '[ ! -z "$unpushed_tags" ]'
if [ $Action = 0 ] && [ ! -z "$unpushed_tags" ] ; then
echo -n "Push all tags? [y/n] "
read yesno
if [ "$yesno" != "n" -a "$yesno" != 'N' ]; then
git push --tags
fi
Action=1
fi
detached=`grep -v "^ref" "$(git rev-parse --show-toplevel)/.git/HEAD" |wc -l`
onetest "head attached" "detached head" '[ $detached -gt 0 ]'
if [ $Action = 0 ] && [ $detached -gt 0 ] ; then
if [ $detached -eq 1 ]; then
echo -n "Merge detached head into master? [y/n] "
read yesno
if [ "$yesno" != "n" -a "$yesno" != 'N' ]; then
git checkout -b HEADregraft
git commit -m "Check in HEAD to merge"
git checkout master
git merge HEADregraft
git branch -d HEADregraft
fi
Action=1
else
echo "Multiple detached HEADs. This is biologically impossible."
fi
fi
allbranches
# run this very program foreach submodule
if [ -e "`git rev-parse --show-toplevel`/.gitmodules" ] ; then
echo -e "${Divider}Checking submodules"
if [ $Action = 0 ] ; then
git submodule foreach "$0 -a"
else
git submodule foreach "$0"
fi
Subdirty=$?
Dirty=$((Dirty + $Subdirty))
#else: submodules are so infrequently used, don't even mention this test if no .gitmodules.
#$onetest "no submodules to check" "--" false
fi
#OK, checks done. Check to remove working directory
if [ "$1" = "-a" ] && [ "$Dirty" = 0 ]; then
WD="`git rev-parse --show-toplevel`"
echo -n "Removing $WD. OK? [y/n] "
read yesno
if [ "$yesno" != "n" -a "$yesno" != 'N' ]; then
cd "$WD/.."
rm -rf "$WD"
fi
fi
fi #if isnt_repository we skipped almost all of the above
[ $Dirty -eq 0 ] #return value