-
Notifications
You must be signed in to change notification settings - Fork 3
/
git-xcleaner
executable file
·150 lines (128 loc) · 4.26 KB
/
git-xcleaner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/bin/bash
git status >/dev/null || (echo "The current directory does not seem to be valid git repo" && exit 1)
type whiptail &>/dev/null || (echo "Missing 'whiptail' dependency" && exit 1)
BORDER=5
WIDTH=$(( $COLUMNS - $BORDER))
HEIGHT=$(( $LINES - $BORDER))
WHEIGHT=$(( $LINES - $BORDER - 8))
WIDTH_MENU=78
HEIGHT_MENU=18
WHEIGHT_MENU=$(( $HEIGHT_MENU - 8))
SMALL_WIDTH=60
SMALL_HEIGHT=8
delete_action_selection() {
# construct the checkbox command
CHECKBOX_CMD=""
for b in $BRANCH_LIST; do
[[ -z "${STATE[$b]}" ]] && STATE[$b]=0
CHECKBOX_CMD+="$b ${STATE[$b]} "
done
# open the checkbox list
TO_BE_DELETED=()
for b in $(whiptail --title "The git xcleaner - branch selection" \
--separate-output --noitem \
--checklist "Select branches to be deleted and be careful:" \
$HEIGHT $WIDTH $WHEIGHT $CHECKBOX_CMD 3>&1 1>&2 2>&3); do
TO_BE_DELETED+=($b)
done
CONFIRMED=0
if [ ${#TO_BE_DELETED[@]} -ne 0 ]; then
# explicitly confirm the action
if (whiptail --title "The git xcleaner - delete confirmation" \
--yesno "Are you sure to delete selected branches (${#TO_BE_DELETED[@]})?" $SMALL_HEIGHT $SMALL_WIDTH) then
CONFIRMED=1
fi
fi
}
delete_action() {
if [ $CONFIRMED -eq 1 ]; then
PERCENT=$(( 100 / ${#TO_BE_DELETED[@]} ))
GAUGE=0
{
for b in "${TO_BE_DELETED[@]}"; do
eval $1 1>&2
echo $GAUGE
GAUGE=$(( $GAUGE + $PERCENT ))
done
echo 100
} | whiptail --title "The git xcleaner - working" \
--gauge "Deleting selected branches..." $SMALL_HEIGHT $WIDTH 0
fi
}
action_local() {
git branch -D $b &>>$HOME/.git-xcleaner.log
}
action_remote() {
git push $REMOTE :${b/$REMOTE\//} &>>$HOME/.git-xcleaner.log
}
while true; do
ACTIVE_BRANCH=$(git rev-parse --abbrev-ref HEAD)
# hash with preselect state (0/1)
BRANCH_LIST=$(git branch | sed -E 's/^\*?\s*//' | sort)
declare -A STATE; STATE=()
# load all branch names
for b in $BRANCH_LIST; do
STATE[$b]=0
done
ACTION=$(whiptail --title "The git xcleaner - main menu" --cancel-button "Help" --default-item "Exit" \
--menu "Select action. This is safe, review on the next screen." $HEIGHT_MENU $WIDTH_MENU $WHEIGHT_MENU \
"Merged" "Delete merged branches (--merged)" \
"Messages" "Delete (rebased) branches with the same commit messages" \
"Pruned" "Delete pruned branches (deleted tracking branches)" \
"Manual" "Interactive manual deletion" \
"Exit" "Return to shell" \
"Help" "Show help" \
3>&1 1>&2 2>&3)
#"Prune" "Delete stale remote-tracking branches" \
case $ACTION in
Manual)
delete_action_selection
delete_action action_local
;;
Merged)
# checkout base branch
BASE=$(whiptail --title "The git xcleaner - branch to search" \
--inputbox "Base branch:" $HEIGHT $WIDTH master 3>&1 1>&2 2>&3)
# preselect merged branch names
for b in $(git branch --merged $BASE | sed -E 's/^\*?\s*//' | sort); do
[ "x$b" != "x$BASE" ] && STATE[$b]=1
done
delete_action_selection
delete_action action_local
;;
Pruned)
# preselect pruned branches (must do git fetch --prune prior this)
for b in $(git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads | grep '\[gone\]' | awk '{ print $1 }' | sort); do
[ "x$b" != "x$ACTIVE_BRANCH" ] && STATE[$b]=1
done
delete_action_selection
delete_action action_local
;;
Messages)
# checkout base branch
BASE=$(whiptail --title "The git xcleaner - branch to search" \
--inputbox "Base branch:" $HEIGHT $WIDTH master 3>&1 1>&2 2>&3)
git checkout $BASE &>/dev/null || exit 1
# search commit messages and preselect branches
for b in "${!STATE[@]}"; do
last_commit_msg="$(git log --oneline --format=%f -1 $b)"
if [[ "$(git log --oneline --format=%f | grep "$last_commit_msg" | wc -l)" -eq 1 ]]; then
[ "x$b" != "x$ACTIVE_BRANCH" ] && STATE[$b]=1
fi
done
delete_action_selection
delete_action action_local
;;
Exit)
exit 0
;;
*)
HELP_TEXT=/usr/share/doc/git-xcleaner/git-xcleaner.1.txt
if [ -f $HELP_TEXT ]; then
whiptail --title "The git xcleaner - help" --textbox $HELP_TEXT $HEIGHT $WIDTH
else
whiptail --title "The git xcleaner - help" --infobox "Help not available - use packaged version" $HEIGHT $WIDTH
fi
;;
esac
done