Skip to content

Commit cfc5565

Browse files
committed
New feature to select repos.
It is now possible to conditionnally execute the command. Available conditions are: - when the repo is or is not “clean” regarding `git status` (various levels available), - when the repo is in detached HEAD or not, - when the HEAD is behind or ahead its remote-tracking branch.
1 parent 618bbc0 commit cfc5565

File tree

1 file changed

+254
-36
lines changed

1 file changed

+254
-36
lines changed

git-iterate

Lines changed: 254 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,132 @@
1-
#!/bin/sh
1+
#!/bin/bash
22
#
33
# Execute Git commands on multiple directories and subdirectories
4-
# > git iterate [-q|--quiet] DIR1 DIR2 ... -- GIT_COMMAND ...
5-
# > git iterate [-q|--quiet] DIR1 DIR2 ... foreach SHELL_COMMAND ...
4+
# > git iterate [-v|-V] DIR1 DIR2 ... -- GIT_COMMAND ...
65
#
76
# Parameters:
8-
# -q: Remove all non-error output
9-
# --quiet: Remove announcement of the directories in which there are operations
7+
# -v: Tell in standard error output in which directory the Git command is operating
8+
# -V: Tell in standard output in which directory the Git command is operating
109
# DIR*: list of super-directories, Git commands will be executed on each valid sub-directory
1110
# GIT_COMMAND and next parameters: Git commands to be executed on each Git directory
12-
#
13-
# License: WTFPL 2.0 - Seb35
1411

15-
# Recursively search all Git directories
16-
search_git_folders() {
17-
git --git-dir="$1" branch >/dev/null 2>&1
18-
if [ $? = 0 ]
12+
IFS=$'\n'
13+
export GIT_PROGRESS_DELAY=-1
14+
15+
function search_git_folders() {
16+
if [ ! -d "$1" ]
17+
then
18+
return
19+
elif [ ! -f "$1/.git" -a ! -d "$1/.git" -a ! -d "$1/refs" ]
1920
then
20-
echo "$1"
21+
for folder in $(find "$1" -mindepth 1 -maxdepth 1 -type d)
22+
do
23+
search_git_folders "$folder"
24+
done
2125
else
22-
git --git-dir="$1/.git" branch >/dev/null 2>&1
26+
git --git-dir="$1" branch >/dev/null 2>&1
2327
if [ $? = 0 ]
2428
then
2529
echo "$1"
2630
else
27-
for folder in `find "$1" -mindepth 1 -maxdepth 1 -type d|sort`
28-
do
29-
search_git_folders "$folder"
30-
done
31+
git --git-dir="$1/.git" branch >/dev/null 2>&1
32+
if [ $? = 0 ]
33+
then
34+
echo "$1"
35+
else
36+
for folder in $(find "$1" -mindepth 1 -maxdepth 1 -type d)
37+
do
38+
search_git_folders "$folder"
39+
done
40+
fi
3141
fi
3242
fi
3343
}
3444

35-
# Catch "verbose" option
36-
quiet="false"
37-
if [ "$1" = "-q" ]
38-
then
39-
quiet="true"
40-
shift
41-
elif [ "$1" = "--quiet" ]
42-
then
43-
quiet="moderate"
44-
shift
45-
fi
46-
4745
# Get folders
4846
folders=""
4947
foreach="false"
48+
options=""
49+
quiet="false"
50+
display_only="false"
51+
clean=""
52+
behind=""
53+
ahead=""
54+
detached=""
5055
for folder in "$@"
5156
do
57+
if [ -z "$options" ]; then
58+
if [ "$folder" = "-q" ]; then
59+
shift
60+
quiet="moderate"
61+
continue
62+
elif [ "$folder" = "-qq" -o "$folder" = "--quiet" ]; then
63+
shift
64+
quiet="true"
65+
continue
66+
elif [ "$folder" = "--to-be-cleaned" ]; then
67+
shift
68+
clean="-3"
69+
continue
70+
elif [ "$folder" = "--very-unclean" ]; then
71+
shift
72+
clean="-2"
73+
continue
74+
elif [ "$folder" = "--unclean" ]; then
75+
shift
76+
clean="-1"
77+
continue
78+
elif [ "$folder" = "--almost-clean" ]; then
79+
shift
80+
clean="1"
81+
continue
82+
elif [ "$folder" = "--quite-clean" ]; then
83+
shift
84+
clean="2"
85+
continue
86+
elif [ "$folder" = "--clean" ]; then
87+
shift
88+
clean="3"
89+
continue
90+
elif [ "$folder" = "--very-clean" ]; then
91+
shift
92+
clean="4"
93+
continue
94+
elif [ "$folder" = "--very-very-clean" ]; then
95+
shift
96+
clean="5"
97+
continue
98+
elif [ "$folder" = "--late" -o "$folder" = "--behind" ]; then
99+
shift
100+
behind="1"
101+
continue
102+
elif [ "$folder" = "--not-late" -o "$folder" = "--not-behind" ]; then
103+
shift
104+
behind="-1"
105+
continue
106+
elif [ "$folder" = "--ahead" ]; then
107+
shift
108+
ahead="1"
109+
continue
110+
elif [ "$folder" = "--not-ahead" ]; then
111+
shift
112+
ahead="-1"
113+
continue
114+
elif [ "$folder" = "--late-or-ahead" -o "$folder" = "--behind-or-ahead" ]; then
115+
shift
116+
behind="2"
117+
ahead="2"
118+
continue
119+
elif [ "$folder" = "--detached" ]; then
120+
shift
121+
detached="true"
122+
continue
123+
elif [ "$folder" = "--not-detached" ]; then
124+
shift
125+
detached="false"
126+
continue
127+
fi
128+
fi
129+
options="1"
52130
shift
53131
if [ "$folder" = "--" ]
54132
then
@@ -58,8 +136,7 @@ do
58136
foreach="true"
59137
break
60138
fi
61-
folders="$folders
62-
$folder"
139+
folders="$folders"$'\n'"$folder"
63140
done
64141

65142
# If no folder is given, use local directory (recursively)
@@ -68,21 +145,162 @@ then
68145
folders=*
69146
fi
70147

148+
#echo quiet="$quiet"
149+
#echo foreach="$foreach"
150+
#echo clean="$clean"
151+
#echo folders="$folders"
152+
#echo $behind
153+
#echo $ahead
154+
155+
if [ "$#" = 0 ]; then
156+
display_only="true"
157+
fi
158+
71159
# Iterate over each folder
72160
first="true"
73161
for folder in $folders
74162
do
75-
folders=`search_git_folders "$folder"`
163+
folders=$(search_git_folders "$folder")
76164
for git_folder in $folders
77165
do
78166
cd "$git_folder"
167+
# First check if the Git repo is eligible regarding its status and remote-tracking status
168+
if [ "$clean" = "-3" ]; then
169+
status1=$(git status --short)
170+
status2=$(git stash list)
171+
status3=$(LANG="en" git branch --list -vv)
172+
status4=$(echo "$status3"|grep "^*"|grep -F -e " behind " -e " ahead ")
173+
status5=$(echo "$status3"|grep "^* (HEAD detached at ")
174+
# Display if ( $status1 !== "" || $status2 !== "" || $status3 === "" || $status4 !== "" || $status5 !== "" )
175+
if [ -z "$status1" -a -z "$status2" -a -n "$status3" -a -z "$status4" -a -z "$status5" ]; then
176+
cd "$OLDPWD"
177+
continue
178+
fi
179+
elif [ "$clean" = "-2" ]; then
180+
status=$(git status --short|grep -v "^??")
181+
if [ -z "$status" ]; then
182+
cd "$OLDPWD"
183+
continue
184+
fi
185+
elif [ "$clean" = "-1" ]; then
186+
status=$(git status --short)
187+
if [ -z "$status" ]; then
188+
cd "$OLDPWD"
189+
continue
190+
fi
191+
elif [ "$clean" = "1" ]; then
192+
status1=$(git status --short)
193+
status2=$(echo "$status1"|grep -v "^??")
194+
status3=$(git stash list)
195+
# Display if ( ( status1 !== "" && status2 === "" ) || ( status2 === "" && status3 !== "" ) )
196+
# Display if status2 === "" && ( status1 !== "" || status3 !== "" )
197+
# Do not display if ( ( status1 === "" || status2 !== "" ) && status3 === "" )
198+
# Do not display if status2 !== "" || ( status1 === "" && status3 === "" )
199+
#if [ \( -z "$status1" -o -n "$status2" \) -a -z "$status3" ]; then
200+
if [ -n "$status2" -o \( -z "$status1" -a -z "$status3" \) ]; then
201+
cd "$OLDPWD"
202+
continue
203+
fi
204+
elif [ "$clean" = "2" ]; then
205+
status=$(git status --short|grep -v "^??")
206+
if [ -n "$status" ]; then
207+
cd "$OLDPWD"
208+
continue
209+
fi
210+
elif [ "$clean" = "3" ]; then
211+
status=$(git status --short)
212+
if [ -n "$status" ]; then
213+
cd "$OLDPWD"
214+
continue
215+
fi
216+
elif [ "$clean" = "4" ]; then
217+
status=$(git status --ignored --short)
218+
if [ -n "$status" ]; then
219+
cd "$OLDPWD"
220+
continue
221+
fi
222+
elif [ "$clean" = "5" ]; then
223+
status1=$(git status --ignored --short)
224+
status2=$(git stash list)
225+
if [ -n "$status1" -o -n "$status2" ]; then
226+
cd "$OLDPWD"
227+
continue
228+
fi
229+
fi
230+
behind_found="0"
231+
if [ "$behind" = "1" -o "$behind" = "2" ]; then
232+
# TODO could be improved: there are false positive if the commit message contains " behind "
233+
status1=$(LANG="en" git branch --list -vv)
234+
status2=$(echo "$status1"|grep "^*"|grep -F " behind ")
235+
# Display if ( status1 !== "" && status2 !== "" )
236+
if [ -z "$status1" -o -z "$status2" ]; then
237+
if [ "$behind" != "2" -o "$ahead" != "2" ]; then
238+
cd "$OLDPWD"
239+
continue
240+
fi
241+
else
242+
behind_found="1"
243+
fi
244+
elif [ "$behind" = "-1" ]; then
245+
# TODO could be improved: there are false positive if the commit message contains " behind "
246+
status1=$(LANG="en" git branch --list -vv)
247+
status2=$(echo "$status1"|grep "^*"|grep -F " behind ")
248+
# Display if ( status1 !== "" && status2 === "" )
249+
if [ -z "$status1" -o -n "$status2" ]; then
250+
cd "$OLDPWD"
251+
continue
252+
fi
253+
fi
254+
if [ "$ahead" = "1" -o "$ahead" = "2" ]; then
255+
# TODO could be improved: there are false positive if the commit message contains " ahead "
256+
status1=$(LANG="en" git branch --list -vv)
257+
status2=$(echo "$status1"|grep "^*"|grep -F " ahead ")
258+
# Display if ( status1 !== "" && status2 !== "" )
259+
if [ -z "$status1" -o -z "$status2" ]; then
260+
if [ "$behind" != "2" -o "$ahead" != "2" -o "$behind_found" != "1" ]; then
261+
cd "$OLDPWD"
262+
continue
263+
fi
264+
fi
265+
elif [ "$ahead" = "-1" ]; then
266+
# TODO could be improved: there are false positive if the commit message contains " ahead "
267+
status1=$(LANG="en" git branch --list -vv)
268+
status2=$(echo "$status1"|grep "^*"|grep -F " ahead ")
269+
# Display if ( status1 !== "" && status2 === "" )
270+
if [ -z "$status1" -o -n "$status2" ]; then
271+
cd "$OLDPWD"
272+
continue
273+
fi
274+
fi
275+
if [ "$detached" = "true" ]; then
276+
status1=$(LANG="en" git branch --list -vv)
277+
status2=$(echo "$status1"|grep "^* (HEAD detached at ")
278+
# Display if ( status1 !== "" && status2 !== "" )
279+
if [ -z "$status1" -o -z "$status2" ]; then
280+
cd "$OLDPWD"
281+
continue
282+
fi
283+
elif [ "$detached" = "false" ]; then
284+
status1=$(LANG="en" git branch --list -vv)
285+
status2=$(echo "$status1"|grep "^* (HEAD detached at ")
286+
# Display if ( status1 !== "" && status2 === "" )
287+
if [ -z "$status1" -o -n "$status2" ]; then
288+
cd "$OLDPWD"
289+
continue
290+
fi
291+
fi
292+
if [ "$display_only" = "true" ]; then
293+
echo "$folder"
294+
cd "$OLDPWD"
295+
continue
296+
fi
79297
if [ "$quiet" = "true" ]
80298
then
81299
if [ "$foreach" = "false" ]
82300
then
83-
errors=`git $@ 2>&1`
301+
errors=$(git $@ 2>&1)
84302
else
85-
errors=`$@ 2>&1`
303+
errors=$($@ 2>&1)
86304
fi
87305
if [ "$?" != 0 ]
88306
then
@@ -91,14 +309,14 @@ do
91309
echo >&2
92310
fi
93311
first="false"
94-
echo "\033[1m$git_folder\033[0m" >&2
312+
echo $git_folder >&2
95313
echo "$errors" >&2
96314
echo "Error $? in $git_folder" >&2
97315
fi
98316
else
99317
if [ "$quiet" != "moderate" ]
100318
then
101-
echo "\033[1m$git_folder\033[0m"
319+
echo -e "\033[1m$git_folder\033[0m"
102320
fi
103321
if [ "$foreach" = "false" ]
104322
then

0 commit comments

Comments
 (0)