]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/all/git.subr
modularize ./all a lot
[xonotic/xonotic.git] / misc / tools / all / git.subr
1 check_mergeconflict() # overrides the one in ./all
2 {
3         if git ls-files -u | grep ' 1   '; then
4                 $ECHO
5                 $ECHO "MERGE CONFLICT."
6                 $ECHO "change into the \"$1\" project directory, and then:"
7                 $ECHO "- edit the files mentioned above with your favorite editor,"
8                 $ECHO "  and fix the conflicts (marked with <<<<<<< blocks)"
9                 $ECHO "- for binary files, you can select the files using"
10                 $ECHO "  git checkout --ours or git checkout --theirs"
11                 $ECHO "- when done with a file, 'git add' the file"
12                 $ECHO "- when done, 'git commit'"
13                 $ECHO
14                 exit 1
15         fi
16 }
17
18 visible_repo_name()
19 {
20         case "$1" in
21                 .)
22                         $ECHO "the root directory"
23                         ;;
24                 *)
25                         $ECHO "\"$1\""
26                         ;;
27         esac
28 }
29
30 fix_upstream_rebase()
31 {
32         if [ -z "$r_me" ] || [ -z "$r_other" ]; then
33                 return
34         fi
35
36         # one of the two sides of the merge should be remote upstream, or all is fine
37         r_r=`git symbolic-ref HEAD`
38         r_r=${r_r#refs/heads/}
39         r_rem=`git config "branch.$r_rem.remote" || $ECHO origin`
40         r_bra=`git config "branch.$r_bra.merge" || $ECHO "$r_r"`
41         r_bra=${r_bra#refs/heads/}
42         if [ x"$r_me" != x"`git rev-parse "$r_rem/$r_bra"`" ]; then
43                 if [ x"$r_other" != x"`git rev-parse "$r_rem/$r_bra"`" ]; then
44                         return
45                 fi
46         fi
47
48         r_base=`git merge-base "$r_me" "$r_other"`
49
50         # no merge-base? upstream did filter-branch
51         if [ -n "$r_base" ]; then
52                 # otherwise, check if the two histories are "similar"
53                 r_l_me=`git log --pretty="format:%s" "$r_other".."$r_me" | grep -v "^Merge" | sort -u`
54                 r_l_other=`git log --pretty="format:%s" "$r_me".."$r_other" | grep -v "^Merge" | sort -u`
55
56                 # heuristics: upstream rebase/filter-branch if more than 50% of the commits of one of the sides are in the other too
57                 r_lc_me=`$ECHO "$r_l_me" | wc -l`
58                 r_lc_other=`$ECHO "$r_l_other" | wc -l`
59                 r_lc_together=`{ $ECHO "$r_l_me"; $ECHO "$r_l_other"; } | sort -u | wc -l`
60                 r_lc_same=$(($r_lc_me + $r_lc_other - $r_lc_together))
61
62                 if [ $(( $r_lc_same * 2 )) -gt $(( $r_lc_me )) ] || [ $(( $r_lc_same * 2 )) -gt $(( $r_lc_other )) ]; then
63                         if yesno "Probable upstream rebase detected, automatically fix?" 'git log --oneline --graph --date-order --left-right "$r_other"..."$r_me"'; then
64                                 git reset --hard "$r_me"
65                                 git pull --rebase
66                                 return 1
67                         fi
68                 fi
69         fi
70
71         return 0
72 }
73
74 fix_upstream_rebase_mergeok()
75 {
76         r_me=`git rev-parse --revs-only HEAD^1 2>/dev/null || true`
77         r_other=`git rev-parse --revs-only HEAD^2 2>/dev/null || true`
78         fix_upstream_rebase
79 }
80
81 fix_upstream_rebase_mergefail()
82 {
83         r_me=`git rev-parse --revs-only HEAD 2>/dev/null || true`
84         r_other=`git rev-parse --revs-only MERGE_HEAD 2>/dev/null || true`
85         fix_upstream_rebase
86 }
87
88 fix_git_config()
89 {
90         if ! [ -f ".git/config" ]; then
91                 $ECHO "Not a git repository. Bailing out to not cause damage."
92                 exit 1
93         fi
94         verbose git config remote.origin.url "$1"
95         if [ -n "$2" ]; then
96                 verbose git config remote.origin.pushurl "$2"
97         else
98                 verbose git config --unset remote.origin.pushurl || true
99         fi
100         verbose git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
101         case ",`repoflags "$d"`," in
102                 *,noautocrlf,*)
103                         verbose git config --unset core.autocrlf || true
104                         ;;
105                 *)
106                         verbose git config core.autocrlf input
107                         ;;
108         esac
109         if [ -z "`git config push.default || true`" ]; then
110                 verbose git config push.default current # or is tracking better?
111         fi
112         verbose git config filter.mapclean.clean "tr -d '\r' | grep '^[^/]'"
113         verbose git config filter.mapclean.smudge "cat"
114 }
115
116 mirrorspeed()
117 {
118         # first result is to be ignored, but we use it to check status
119         git ls-remote "$1" refs/heads/master >/dev/null 2>&1 || return 1
120         { time -p git ls-remote "$1" refs/heads/master; } 2>&1 >/dev/null | head -n 1 | cut -d ' ' -f 2 | tr -d . | sed 's,^0*,,'
121                 # unit: clock ticks (depends on what "time" returns
122 }
123
124 bestmirror()
125 {
126         pre=$1; shift
127         suf=$1; shift
128
129         if ! { time -p true; } >/dev/null 2>&1; then
130                 msg "Cannot do timing in this shell"
131                 return 1
132         fi
133
134         bestin=
135         bestt=
136         for mir in "$@"; do
137                 case "$mir" in
138                         *:*)
139                                 in=${mir%%:*}
140                                 op=${mir#*:}
141                                 ;;
142                         *)
143                                 in=$mir
144                                 op=
145                                 ;;
146                 esac
147                 m=$pre$in$suf
148                 if t=`mirrorspeed "$m"`; then
149                         if [ -n "$t" ]; then
150                                 tt=$(($t$op)) # fudge factor
151                                 msg "$m -> $t$op = $tt ticks"
152                                 if [ -z "$bestt" ] || [ "$tt" -lt "$bestt" ]; then
153                                         bestin=$in
154                                         bestt=$tt
155                                 fi
156                         else
157                                 msg "$m -> error"
158                         fi
159                 else
160                         msg "$m -> FAIL"
161                 fi
162         done
163         if [ -n "$bestin" ]; then
164                 msg "Best mirror seems to be $pre$bestin$suf"
165                 $ECHO "$bestin"
166         else
167                 return 1
168         fi
169 }
170
171 handled=true
172 case "$cmd" in
173         fix_upstream_rebase)
174                 for d in $repos; do
175                         enter "$d0/$d" verbose
176                         verbose fix_upstream_rebase_mergefail && verbose fix_upstream_rebase_mergeok
177                 done
178                 ;;
179         fix_config)
180                 for d in $repos; do
181                         url=`repourl "$d"`
182                         pushurl=`repopushurl "$d"`
183                         branch=`repobranch "$d"`
184                         if [ -f "$d0/$d/.git/config" ]; then
185                                 verbose cd "$d0/$d"
186                                 fix_git_config "$url" "$pushurl"
187                                 cd "$d0"
188                         fi
189                 done
190                 ;;
191         keygen)
192                 # enable the ssh URL for pushing
193                 "$SELF" update -N -p
194
195                 if [ -f ~/.ssh/id_rsa.pub ]; then
196                         msg ""
197                         msg "A key already exists and no new one will be generated. If you"
198                         msg "already have done the procedure for getting your key approved, you"
199                         msg "can skip the following paragraph and already use the repository."
200                         msg ""
201                         msg "To get access, your key has to be approved first. For that, visit"
202                         msg "$devsite_url, then log in, create a \"New Issue\" on"
203                         msg "the \"Support\" tracker in the \"Repository\" category where you"
204                         msg "apply for access and paste the following output into the issue:"
205                         msg ""
206                         msg "`cat ~/.ssh/id_rsa.pub`"
207                         msg ""
208                         msg "Note that you will only have write access to branches that start"
209                         msg "with your user name."
210                 elif [ -f ~/.ssh/id_dsa.pub ]; then
211                         msg ""
212                         msg "A key already exists and no new one will be generated. If you"
213                         msg "already have done the procedure for getting your key approved, you"
214                         msg "can skip the following paragraph and already use the repository."
215                         msg ""
216                         msg "To get access, your key has to be approved first. For that, visit"
217                         msg "$devsite_url, then log in, create a \"New Issue\" on"
218                         msg "the \"Support\" tracker in the \"Repository\" category where you"
219                         msg "apply for access and paste the following output into the issue:"
220                         msg ""
221                         msg "`cat ~/.ssh/id_dsa.pub`"
222                         msg ""
223                         msg "Note that you will only have write access to branches that start"
224                         msg "with your user name."
225                 else
226                         msg ""
227                         msg "No key has been generated yet. One will be generated now."
228                         msg "If other people are using your computer, it is recommended"
229                         msg "to specify a passphrase. Otherwise you can simply hit ENTER"
230                         msg "when asked for a passphrase."
231                         msg ""
232                         ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
233                         msg ""
234                         msg "To get access, your key has to be approved first. For that, visit"
235                         msg "$devsite_url, then log in, create a \"New Issue\" on"
236                         msg "the \"Support\" tracker in the \"Repository\" category where you"
237                         msg "apply for access and paste the following output into the issue:"
238                         msg ""
239                         msg "`cat ~/.ssh/id_rsa.pub`"
240                         msg ""
241                         msg "Note that you will only have write access to branches that start"
242                         msg "with your user name."
243                 fi
244                 ;;
245         update|pull)
246                 allow_pull=true
247                 location=current
248                 oldbase=$base
249                 oldpushbase=$pushbase
250                 while :; do
251                         if [ x"$1" = x"-N" ]; then
252                                 allow_pull=false
253                         elif [ x"$1" = x"-p" ]; then
254                                 pushbase=$pushsite_url
255                         elif [ x"$1" = x"-ps" ]; then
256                                 pushbase=$pushsite_url
257                         elif [ x"$1" = x"-ph" ]; then
258                                 pushbase=$httppushsite_url
259                         elif [ x"$1" = x"-s" ]; then
260                                 base=$pushsite_url
261                         elif [ x"$1" = x"-g" ]; then
262                                 base=$gitsite_url
263                                 location=best
264                         elif [ x"$1" = x"-h" ]; then
265                                 base=$httpsite_url
266                                 location=best
267                         elif [ x"$1" = x"-l" ]; then
268                                 case "$2" in
269                                         nl) ;;
270                                         de) ;;
271                                         us) ;;
272                                         best) ;;
273                                         default) ;;
274                                         *)
275                                                 msg "Invalid location!"
276                                                 msg "Possible locations for the -l option:"
277                                                 msg "  nl (Netherlands, run by merlijn)"
278                                                 msg "  de (Germany, run by divVerent)"
279                                                 msg "  us (United States of America, run by detrate)"
280                                                 msg "  best (find automatically)"
281                                                 msg "  default (currently nl)"
282                                                 exit 1
283                                                 ;;
284                                 esac
285                                 location=$2
286                                 shift
287                         else
288                                 break
289                         fi
290                         shift
291                 done
292                 case "$location" in
293                         current)
294                                 if [ x"`git config xonotic.all.mirrorselection 2>/dev/null || true`" != x"done" ]; then
295                                         location=best
296                                 fi
297                                 ;;
298                 esac
299                 case "$location" in
300                         best)
301                                 # if we fetched via ssh://, switch to git:// for fetching and keep using ssh:// for pushing
302                                 case "$base" in
303                                         ssh://*|*/login/*)
304                                                 pushbase=$base
305                                                 base=$gitsite_url
306                                                 ;;
307                                 esac
308                                 newbase=`$ECHO "$base" | sed "s,://\(.*\.\)\?git.xonotic.org/,:// .git.xonotic.org/,"`
309                                 case "$newbase" in
310                                         *\ *)
311                                                 if location=`bestmirror $newbase"xonotic.git" de us nl:'*6/5'`; then # 20% malus to the NL server to not overload it too much
312                                                         git config xonotic.all.mirrorselection done
313                                                 else
314                                                         location=current
315                                                 fi
316                                                 ;;
317                                         *)
318                                                 location=current
319                                                 ;;
320                                 esac
321                                 ;;
322                 esac
323                 case "$location" in
324                         default)
325                                 location=
326                                 ;;
327                         current)
328                                 case "$base" in
329                                         *://*.git.xonotic.org/*)
330                                                 location=${base%%.git.xonotic.org/*}
331                                                 location=${location##*://}
332                                                 ;;
333                                         *)
334                                                 location=
335                                                 ;;
336                                 esac
337                                 ;;
338                 esac
339                 if [ -n "$location" ]; then
340                         base=`$ECHO "$base" | sed "s,://\(.*\.\)\?git.xonotic.org/,://$location.git.xonotic.org/,"`
341                 else
342                         base=`$ECHO "$base" | sed "s,://\(.*\.\)\?git.xonotic.org/,://git.xonotic.org/,"`
343                 fi
344                 pushbase=`$ECHO "$pushbase" | sed "s,://\(.*\.\)\?git.xonotic.org/,://xonotic@push.git.xonotic.org/,"`
345                 if [ x"$base" != x"$oldbase" ] || [ x"$pushbase" != x"$oldpushbase" ]; then
346                         url=`repourl .`
347                         pushurl=`repopushurl .`
348                         fix_git_config "$url" "$pushurl"
349                         "$SELF" fix_config
350                 elif $allow_pull; then
351                         "$SELF" fix_config
352                 fi
353                 for d in $repos; do
354                         url=`repourl "$d"`
355                         pushurl=`repopushurl "$d"`
356                         branch=`repobranch "$d"`
357                         if [ -f "$d0/$d/.git/config" ]; then
358                                 # if we have .no file, skip
359                                 if [ -f "$d0/$d.no" ]; then
360                                         msg "Repository $d disabled by a .no file, delete $d.no to enable; thus, not updated"
361                                         continue
362                                 fi
363                                 if $allow_pull; then
364                                         enter "$d0/$d" verbose
365                                         r=`git symbolic-ref HEAD`
366                                         r=${r#refs/heads/}
367                                         if git config branch.$r.remote >/dev/null 2>&1; then
368                                                 if ! verbose git pull; then
369                                                         fix_upstream_rebase_mergefail || true
370                                                         check_mergeconflict "$d"
371                                                         $ECHO "Pulling failed. Press ENTER to continue, or Ctrl-C to abort."
372                                                         read -r DUMMY
373                                                 else
374                                                         fix_upstream_rebase_mergeok || true
375                                                 fi
376                                         fi
377
378                                         cd "$d00"
379                                         checkself "$cmd" "$@"
380                                         cd "$d0/$d"
381                                         verbose git remote prune origin
382                                         cd "$d0"
383                                 fi
384                         else
385                                 if [ -d "$d0/$d" ]; then
386                                         if yesno "$d0/$d is in the way, get rid of it and reclone?"; then
387                                                 verbose rm -rf "$d0/$d"
388                                         else
389                                                 echo "Note: $d0/$d will stay broken."
390                                                 continue
391                                         fi
392                                 fi
393                                 verbose git clone "$url" "$d0/$d"
394                                 enter "$d0/$d" verbose
395                                 fix_git_config "$url" "$pushurl"
396                                 if [ "$branch" != "master" ]; then
397                                         verbose git checkout --track -b "$branch" origin/"$branch"
398                                 fi
399                                 cd "$d0"
400                         fi
401                 done
402                 ;;
403         checkout|switch)
404                 checkoutflags=
405                 if [ x"$1" = x"-f" ]; then
406                         checkoutflags=-f
407                         shift
408                 fi
409                 remote=$1
410                 branch=$2
411                 if [ -z "$branch" ]; then
412                         case "$remote" in
413                                 origin/*)
414                                         branch=${remote#origin/}
415                                         remote=origin
416                                         ;;
417                                 *)
418                                         branch=$remote
419                                         remote=origin
420                                         ;;
421                         esac
422                 fi
423                 if [ -n "$checkoutflags" ]; then
424                         set -- -f "$@" # to make checkself work again
425                 fi
426                 exists=false
427                 for d in $repos; do
428                         enter "$d0/$d" verbose
429                         b=$branch
430                         if [ -n "$b" ] && git rev-parse "refs/heads/$b" >/dev/null 2>&1; then
431                                 exists=true
432                                 verbose git checkout $checkoutflags "$b"
433                         elif [ -n "$b" ] && git rev-parse "refs/remotes/$remote/$b" >/dev/null 2>&1; then
434                                 exists=true
435                                 verbose git checkout $checkoutflags --track -b "$b" "$remote/$b"
436                         else
437                                 b=`repobranch "$d"`
438                                 if git rev-parse "refs/heads/$b" >/dev/null 2>&1; then
439                                         verbose git checkout $checkoutflags "$b"
440                                 elif git rev-parse "refs/remotes/$remote/$b" >/dev/null 2>&1; then
441                                         verbose git checkout $checkoutflags --track -b "$b" "$remote/$b"
442                                 else
443                                         $ECHO "WTF? Not even branch $b doesn't exist in $d"
444                                         exit 1
445                                 fi
446                         fi
447                         cd "$d00"
448                         checkself "$cmd" "$@"
449                         cd "$d0"
450                 done
451                 if ! $exists; then
452                         $ECHO "The requested branch was not found in any repository."
453                 fi
454                 exec "$SELF" branch
455                 ;;
456         branch)
457                 remote=$1
458                 branch=$2
459                 srcbranch=$3
460                 if [ -z "$branch" ]; then
461                         branch=$remote
462                         remote=origin
463                 fi
464                 if [ -z "$branch" ]; then
465                         for d in $repos; do
466                                 enter "$d0/$d"
467                                 r=`git symbolic-ref HEAD`
468                                 r=${r#refs/heads/}
469                                 $ECHO "$d is at $r"
470                                 cd "$d0"
471                         done
472                 else
473                         for d in $repos; do
474                                 dv=`visible_repo_name "$d"`
475                                 enter "$d0/$d" verbose
476                                 if git rev-parse "refs/heads/$branch" >/dev/null 2>&1; then
477                                         $ECHO "Already having this branch in $dv."
478                                 else
479                                         if yesno "Branch in $dv?"; then
480                                                 if [ -n "$srcbranch" ]; then
481                                                         b=$srcbranch
482                                                 else
483                                                         b=origin/"`repobranch "$d"`"
484                                                         verbose git fetch origin || true
485                                                 fi
486                                                 # TODO do this without pushing
487                                                 verbose git checkout -b "$branch" "$b"
488                                                 verbose git config "branch.$branch.remote" "$remote"
489                                                 verbose git config "branch.$branch.merge" "refs/heads/$branch"
490                                         fi
491                                 fi
492                                 cd "$d0"
493                         done
494                         "$SELF" branch
495                 fi
496                 ;;
497         branches)
498                 for d in $repos; do
499                         cd "$d0/$d" # am in a pipe, shouldn't use enter
500                         git branch -r -v -v | cut -c 3- | sed "s/^(no branch)/(no_branch)/" | sed "s,^,$d ,"
501                         cd "$d0"
502                 done | {
503                         branches_list=
504                         # branches_repos_*=
505                         while read -r d BRANCH REV TEXT; do
506                                 if [ x"$BRANCH" = x"`repobranch "$d"`" ]; then
507                                         continue
508                                 fi
509                                 if [ x"$REV" = x"->" ]; then
510                                         continue
511                                 fi
512                                 BRANCH=${BRANCH#remotes/}
513                                 ID=`$ECHO "$BRANCH" | tr -c "A-Za-z0-9." "_"`
514                                 branches_list="$branches_list $BRANCH" # TEH SORT MAKEZ IT UNIEQ
515                                 eval "r=\$branches_repos_$ID"
516                                 r="$r $d"
517                                 eval "branches_repos_$ID=\$r"
518                         done
519                         $ECHO -n "$branches_list" | xargs -n 1 $ECHO | sort -u | while IFS= read -r BRANCH; do
520                                 ID=`$ECHO "$BRANCH" | tr -c "A-Za-z0-9." "_"`
521                                 eval "r=\$branches_repos_$ID"
522                                 printf "%-60s %s\n" "$BRANCH" "$r"
523                                 #$ECHO "$BRANCH: $r"
524                         done
525                 }
526                 ;;
527         push|commit)
528                 submit=$1
529                 for d in $repos; do
530                         dv=`visible_repo_name "$d"`
531                         enter "$d0/$d" verbose
532                         r=`git symbolic-ref HEAD`
533                         r=${r#refs/heads/}
534                         diffdata=`git diff --color HEAD`
535                         if [ -n "$diffdata" ]; then
536                                 # we have uncommitted changes
537                                 if yesno "Uncommitted changes in \"$r\" in $dv. Commit?" '$ECHO "$diffdata" | less -r'; then
538                                         verbose git commit -a
539                                 fi
540                         fi
541                         rem=`git config "branch.$r.remote" || $ECHO origin`
542                         bra=`git config "branch.$r.merge" || $ECHO "$r"`
543                         upstream="$rem/${bra#refs/heads/}"
544                         if ! git rev-parse "$upstream" >/dev/null 2>&1; then
545                                 upstream="origin/`repobranch "$d"`"
546                         fi
547                         logdata=`git log --color "$upstream".."$r"`
548                         if [ -n "$logdata" ]; then
549                                 if yesno "Push \"$r\" in $dv?" '$ECHO "$logdata" | less -r'; then
550                                         verbose git push "$rem" HEAD
551                                 fi
552                         fi
553                         if [ x"$submit" = x"-s" ]; then
554                                 case "$r" in
555                                         */*)
556                                                 verbose git push "$rem" HEAD:"${bra%%/*}/finished/${bra#*/}"
557                                                 ;;
558                                 esac
559                         fi
560                         cd "$d0"
561                 done
562                 ;;
563         each|foreach)
564                 keep_going=false
565                 if [ x"$1" = x"-k" ]; then
566                         keep_going=true
567                         shift
568                 fi
569                 for d in $repos; do
570                         if verbose cd "$d0/$d"; then
571                                 if $keep_going; then
572                                         verbose "$@" || true
573                                 else
574                                         verbose "$@"
575                                 fi
576                                 cd "$d0"
577                         fi
578                 done
579                 ;;
580         clean)
581                 "$SELF" fix_config
582                 "$SELF" update -N
583                 force=false
584                 gotoupstream=false
585                 fetchupstream=false
586                 gotomaster=false
587                 rmuntracked=false
588                 killbranches=false
589                 # usage:
590                 #   ./all clean [-m] [-f | -fu | -fU] [-r] [-D]
591                 #   ./all clean --reclone
592                 found=false
593                 for X in "$@"; do
594                         if [ x"$X" = x"--reclone" ]; then
595                                 force=true
596                                 fetchupstream=true
597                                 gotoupstream=true
598                                 gotomaster=true
599                                 rmuntracked=true
600                                 killbranches=true
601                         elif [ x"$X" = x"-f" ]; then
602                                 force=true
603                         elif [ x"$X" = x"-u" ]; then
604                                 gotoupstream=true
605                         elif [ x"$X" = x"-U" ]; then
606                                 gotoupstream=true
607                                 fetchupstream=true
608                         elif [ x"$X" = x"-fu" ]; then
609                                 force=true
610                                 gotoupstream=true
611                         elif [ x"$X" = x"-fU" ]; then
612                                 force=true
613                                 gotoupstream=true
614                                 fetchupstream=true
615                         elif [ x"$X" = x"-m" ]; then
616                                 gotomaster=true
617                         elif [ x"$X" = x"-r" ]; then
618                                 rmuntracked=true
619                         elif [ x"$X" = x"-D" ]; then
620                                 killbranches=true
621                         elif $ECHO "$X" | grep '^-FFFF*UUUU*$' >/dev/null; then
622                                 msg ''
623                                 msg "        _____"
624                                 msg "    ,--'-\\P/\`\\  FFFFFFF"
625                                 msg " __/_    B/,-.\\  FFFFFFF"
626                                 msg " /  _\\  (//  O\\\\  FFFFFF"
627                                 msg "| (O  \`) _\\._ _)\\  FFFUU"
628                                 msg "| |___/.^d0~~\"\\  \\ UUUU"
629                                 msg "|     |\`~'     \\ |  UUUU"
630                                 msg "|     |    __,C>|| UUUU"
631                                 msg "\\    /_ ,-/,-'   |  UUUU"
632                                 msg " \\\\_ \\_>~'      /  UUUU-"
633                                 msg ''
634                         else
635                                 msg "Unknown arg: $X"
636                         fi
637                         found=true
638                 done
639                 if ! $found; then
640                         rmuntracked=true
641                 fi
642                 for d in $repos; do
643                         verbose cd "$d0/$d"
644                         if $gotoupstream; then
645                                 if ! $force; then
646                                         msg "Must also use -f (delete local changes) when using -u"
647                                         exit 1
648                                 fi
649                                 if $gotomaster; then
650                                         if $fetchupstream; then
651                                                 verbose git fetch origin
652                                                 verbose git remote prune origin
653                                         fi
654                                         verbose git checkout -f "`repobranch "$d"`"
655                                         verbose git reset --hard origin/"`repobranch "$d"`"
656                                 else
657                                         r=`git symbolic-ref HEAD`
658                                         r=${r#refs/heads/}
659                                         rem=`git config "branch.$r.remote" || $ECHO origin`
660                                         bra=`git config "branch.$r.merge" || $ECHO "$r"`
661                                         upstream="$rem/${bra#refs/heads/}"
662                                         if $fetchupstream; then
663                                                 verbose git fetch "$rem"
664                                                 verbose git remote prune "$rem"
665                                         fi
666                                         if ! git rev-parse "$upstream" >/dev/null 2>&1; then
667                                                 upstream="origin/`repobranch "$d"`"
668                                         fi
669                                         verbose git reset --hard "$upstream"
670                                 fi
671                         elif $gotomaster; then
672                                 if $force; then
673                                         verbose git checkout -f "`repobranch "$d"`"
674                                         verbose git reset --hard
675                                 else
676                                         verbose git checkout "`repobranch "$d"`"
677                                 fi
678                         elif $force; then
679                                 verbose git reset --hard
680                         fi
681                         if $rmuntracked; then
682                                 case "$d" in
683                                         .)
684                                                 verbose git clean -df || true
685                                                 ;;
686                                         *)
687                                                 verbose git clean -xdf || true
688                                                 ;;
689                                 esac
690                         fi
691                         if $killbranches; then
692                                 git for-each-ref --format='%(refname)' refs/heads/ | while IFS= read -r B; do
693                                         if [ x"$B" != x"`git symbolic-ref HEAD`" ]; then
694                                                 verbose git branch -D "${B#refs/heads/}"
695                                         fi
696                                 done
697                                 git rev-parse refs/heads/master >/dev/null 2>&1 || verbose git branch --track master origin/master || true
698                                 git rev-parse "refs/heads/`repobranch "$d"`" >/dev/null 2>&1 || verbose git branch --track "`repobranch "$d"`" origin/"`repobranch "$d"`" || true
699                         fi
700                         checkself "$cmd" "$@"
701                 done
702                 ;;
703         help)
704                 $ECHO "  $SELF branch <branch>"
705                 $ECHO "  $SELF branch <remote> <branch> [<srcbranch>]"
706                 $ECHO "  $SELF branches"
707                 $ECHO "  $SELF checkout|switch <branch>"
708                 $ECHO "  $SELF checkout|switch <remote>/<branch>"
709                 $ECHO "  $SELF clean [-m] [-f | -fu | -fU] [-r] [-D]"
710                 $ECHO "  $SELF clean --reclone"
711                 $ECHO "  $SELF each|foreach [-k] command..."
712                 $ECHO "  $SELF fix_upstream_rebase"
713                 $ECHO "  $SELF keygen"
714                 $ECHO "  $SELF push|commit [-s]"
715                 $ECHO "  $SELF update|pull [-N] [-s | -h [-p] | -g [-p]] [-l de|nl|default]"
716                 handled=false
717                 ;;
718         *)
719                 handled=false
720                 ;;
721 esac