-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgit-bulk.sh
More file actions
executable file
·168 lines (145 loc) · 5.46 KB
/
git-bulk.sh
File metadata and controls
executable file
·168 lines (145 loc) · 5.46 KB
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env bash
ncolors=$(tput colors)
if [ -t 1 -a -n "$ncolors" -a $ncolors -ge 8 ]; then
invers=$(tput rev)
reset=$(tput sgr0)
txtbld=$(tput bold)
bldred=${txtbld}$(tput setaf 1)
fi
# default option settings
guardedmode=false
singlemode=false
allwsmode=false
#
# print usage message
#
usage() {
echo 1>&2 "usage: git bulk [-g] ([-a]|[-w <ws-name>]) <git command>"
echo 1>&2 " git bulk --addworkspace <ws-name> <ws-root-directory>"
echo 1>&2 " git bulk --removeworkspace <ws-name>"
echo 1>&2 " git bulk --addcurrent <ws-name>"
echo 1>&2 " git bulk --purge"
echo 1>&2 " git bulk --listall"
}
# add another workspace to global git config
function addworkspace { git config --global bulkworkspaces."$wsname" "$wsdir"; }
# add current directory
function addcurrent { git config --global bulkworkspaces."$wsname" "$PWD"; }
# remove workspace from global git config
function removeworkspace { checkWSName && git config --global --unset bulkworkspaces."$wsname"; }
# remove workspace from global git config
function purge { git config --global --remove-section bulkworkspaces; }
# list all current workspace locations defined
function listall { git config --global --get-regexp bulkworkspaces; }
# guarded execution of a git command in one specific repository
function guardedExecution () {
if $guardedmode; then
echo -n "${invers}git $gitcommand${reset} -> execute here (y/n)? "
read -n 1 -r </dev/tty; echo
if [[ $REPLY =~ ^[Yy]$ ]]; then atomicExecution; fi
else
atomicExecution
fi
}
# atomic git command execution with log
function atomicExecution () {
echo "${bldred}->${reset} executing ${invers}git $gitcommand${reset}" && git $gitcommand
}
# check if the passed command is known as a core git command
function checkGitCommand () {
if git help -a | grep -o -q "\b${corecommand}\b"; then
echo "Core command \"$corecommand\" accepted."
else
if git config --get-regexp alias | grep -o -q "\.${corecommand} "; then
echo "Alias ${corecommand} accepted."
else
usage && echo "error: unknown GIT command: $corecommand" && exit 1
fi
fi
}
# check if workspace name is registered
function checkWSName () {
while read workspace; do
parseWsName "$workspace"
if [[ $rwsname == "$wsname" ]]; then return; fi
done <<< "$(echo "$(listall)")"
# when here the ws name was not found
usage && echo "error: unknown workspace name: $wsname" && exit 1
}
# parse out wsname from workspacespec
function parseWsName () {
local wsspec="$1"
rwsdir=${wsspec#* }
rwsname=${wsspec#*.} && rwsname=${rwsname%% *}
}
# detects the wsname of the current directory
function wsnameToCurrent () {
while read workspace; do
if [ -z "$workspace" ]; then continue; fi
parseWsName "$workspace"
if echo "$PWD" | grep -o -q "$rwsdir"; then wsname="$rwsname" && return; fi
done <<< "$(echo "$(listall)")"
# when here then not in workspace dir
echo "error: you are not in a workspace directory. your registered workspaces are:" && \
wslist="$(echo "$(listall)")" && echo "${wslist:-'<no workspaces defined yet>'}" && exit 1
}
# helper to check number of arguments
function allowedargcount () {
( test "$paramcount" -ne "$1" ) && ( usage && echo 1>&2 "error: wrong number of arguments" && exit 1 )
}
# execute the bulk operation
function executBulkOp () {
checkGitCommand
if ! $allwsmode && ! $singlemode; then wsnameToCurrent; fi # by default git bulk works within the 'current' workspace
listall | while read workspacespec; do
parseWsName "$workspacespec"
if [[ -n $wsname ]] && [[ $rwsname != "$wsname" ]]; then continue; fi
eval cd "\"$rwsdir\""
local actual=$(pwd)
echo "Executing bulk operation in workspace ${invers}$actual${reset}"
eval find . -name ".git" | while read line; do
local gitrepodir=${line::${#line}-5} # cut the .git part of find results to have the root git directory of that repository
eval cd "\"$gitrepodir\"" # into git repo location
local curdir=$(pwd)
local leadingpath=${curdir#${actual}}
echo "Current repository: ${leadingpath%/*}/${bldred}${curdir##*/}${reset}"
guardedExecution
eval cd "\"$rwsdir\"" # back to origin location of last find command
done
done
}
paramcount="${#}"
# if no arguments show usage
if [[ $paramcount -le 0 ]]; then usage; fi
# parse command parameters
while [ "${#}" -ge 1 ] ; do
case "$1" in
--listall|--purge)
butilcommand="${1:2}" && break ;;
--removeworkspace|--addcurrent|--addworkspace)
butilcommand="${1:2}" && wsname="$2" && wsdir="$3" && break ;;
-a)
allwsmode=true ;;
-g)
guardedmode=true ;;
-w)
singlemode=true && shift && wsname="$1" && checkWSName ;;
-*)
usage && echo 1>&2 "error: unknown argument $1" && exit 1 ;;
--*)
usage && echo 1>&2 "error: unknown argument $1" && exit 1 ;;
*) # git core commands
butilcommand="executBulkOp" && corecommand="$1" && gitcommand="$@" && break ;;
esac && shift
done
# check option compatability
if $allwsmode && $singlemode; then echo 1>&2 "error: options -w and -a are incompatible" && exit 1; fi
# if single mode check the supplied workspace name
if $singlemode; then echo "Selected single workspace mode in workspace: $wsname" && checkWSName; fi
# check right number of arguments
case $butilcommand in
listall|purge) allowedargcount 1;;
addcurrent|removeworkspace) allowedargcount 2;;
addworkspace) allowedargcount 3;;
esac
$butilcommand # run user command