]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/all/git.subr
if we can't time, still check availability
[xonotic/xonotic.git] / misc / tools / all / git.subr
1 initrepo_()
2 {
3         if [ x"$3" != x"." ]; then
4                 return
5         fi
6         case "$1" in
7                 *$4)
8                         base=${1%$4}
9                         ;;
10         esac
11         case "$2" in
12                 *$4)
13                         pushbase=${2%$4}
14                         ;;
15         esac
16 }
17 initrepo()
18 {
19         base=
20         pushbase=
21         allrepos initrepo_ "`git config remote.origin.url`" "`git config remote.origin.pushurl`"
22         if [ -z "$base" ]; then
23                 msg "The main repo is not xonotic.git, what have you done?"
24                 exit 1
25         fi
26         msg "Found main repo = $base"
27         if [ -n "$pushbase" ]; then
28                 msg "Found push repo = $pushbase"
29         fi
30 }
31 matchrepoflag()
32 {
33         case ",$2," in
34                 *",$1,"*)
35                         return 0
36                         ;;
37                 *)
38                         return 1
39                         ;;
40         esac
41 }
42 testrepoflag_()
43 {
44         [ x"$1" = x"$3" ] || return
45         if matchrepoflag "$6" "$2"; then
46                 echo 0
47         fi
48 }
49 testrepoflag()
50 {
51         allrepos testrepoflag_ "$1" "$2" | grep ^0 >/dev/null
52 }
53
54 mirrorspeed()
55 {
56         # first result is to be ignored, but we use it to check status
57         git ls-remote "$1" refs/heads/master >/dev/null 2>&1 || return 1
58         # if we can't time, we only check availability
59         if ! { time -p true; } >/dev/null 2>&1; then
60                 echo 0
61                 return
62         fi
63         # now actually time it
64         (
65                 set +x
66                 { 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*,,' | grep . || echo 0
67                         # unit: clock ticks (depends on what "time" returns
68         )
69 }
70 bestmirror()
71 {
72         oldurl="$1"
73         newprotocol="$2"
74         newlocation="$3"
75         oldprotocol=
76         oldlocation=
77         testrepo=
78         bestmirror_firstrepo()
79         {
80                 if [ -z "$testrepo" ]; then
81                         testrepo=$2
82                 fi
83         }
84         allrepos bestmirror_firstrepo
85         bestmirror_findold()
86         {
87                 if [ x"$oldurl" = x"$3" ]; then
88                         oldprotocol=$1
89                         oldlocation=$2
90                 fi
91         }
92         allmirrors bestmirror_findold
93
94         if [ -z "$newprotocol" ]; then
95                 newprotocol=$oldprotocol
96         fi
97         if [ -z "$newlocation" ]; then
98                 newlocation=$oldlocation
99         fi
100
101         besturl=
102         bestlocation=
103         besttime=
104         bestcount=
105         bestmirror_benchmark()
106         {
107                 if [ -z "$2" ]; then
108                         # empty location is not allowed
109                         return
110                 fi
111                 case " $newprotocol " in
112                         *"  "*)
113                                 # no protocol requested? all match
114                                 ;;
115                         *" $1 "*)
116                                 ;;
117                         *)
118                                 return
119                                 ;;
120                 esac
121
122                 # prefer location match
123                 case " $newlocation " in
124                         *" $2 "*)
125                                 ;;
126                         *)
127                                 case " $newlocation " in
128                                         *" $bestlocation "*)
129                                                 # worse
130                                                 return
131                                                 ;;
132                                 esac
133                                 ;;
134                 esac
135
136                 case " $newlocation " in
137                         *" $2 "*)
138                                 # see below
139                                 ;;
140                         *)
141                                 case " $newlocation " in
142                                         *" $bestlocation "*)
143                                                 # worse
144                                                 return
145                                                 ;;
146                                 esac
147                                 ;;
148                 esac
149                 msg "Testing speed of $3..."
150
151                 # only working mirrors
152                 if ! thistime=`mirrorspeed "$3$testrepo"`; then
153                         msg "-> FAILED"
154                         return
155                 fi
156                 thistime=$(($thistime $4))
157                 msg "-> $thistime"
158
159                 # anything is better than nothing
160                 if [ -z "$besttime" ]; then
161                         besturl=$3
162                         bestlocation=$2
163                         besttime=$thistime
164                         bestcount=1
165                         return
166                 fi
167
168                 # prefer location match
169                 case " $newlocation " in
170                         *" $2 "*)
171                                 case " $newlocation " in
172                                         *" $bestlocation "*)
173                                                 # equality
174                                                 ;;
175                                         *)
176                                                 # better
177                                                 besturl=$3
178                                                 bestlocation=$2
179                                                 besttime=$thistime
180                                                 bestcount=1
181                                                 return
182                                                 ;;
183                                 esac
184                                 ;;
185                         *)
186                                 # if newlocation matches bestlocation, then we already discarded it above
187                                 ;;
188                 esac
189
190                 # if we get here, we must compare mirror speed as we have more than one match
191                 if [ $thistime -gt $besttime ]; then
192                         return
193                 elif [ $thistime -lt $besttime ]; then
194                         besturl=$3
195                         besttime=$thistime
196                         bestcount=1
197                         return
198                 fi
199                 # both location and time match. Random decision.
200                 bestcount=$(($bestcount + 1))
201                 if [ $((($RANDOM + 0) % $bestcount)) -eq 0 ]; then
202                         besturl=$3
203                 fi
204         }
205         allmirrors bestmirror_benchmark
206         echo "$besturl"
207 }
208
209 testrepoflag_()
210 {
211         [ x"$1" = x"$3" ] || return
212         case ",$6," in
213                 *",$2,"*)
214                         echo 0
215                         ;;
216                 *)
217                         ;;
218         esac
219 }
220 testrepoflag()
221 {
222         allrepos testrepoflag_ "$1" "$2" | grep ^0 >/dev/null
223 }
224 listrepos_()
225 {
226         d=$1
227         f=$4
228         p="${d%dir}"
229         # if we have .no file, skip
230         if [ -f "$d.no" ]; then
231                 msg "Repository $d disabled by a .no file, delete $d.no to enable"
232                 return
233         fi
234         # if .yes file exists, always keep it
235         if [ -f "$d.yes" ]; then
236                 msg "Repository $d enabled by a .yes file"
237                 $ECHO "$d"
238                 return
239         fi
240         # remove broken clones so they don't mess up stuff
241         if [ x"$d" != x"." ] && [ -d "$d" ] && ! [ -d "$d/.git" ]; then
242                 msg "$d exists but has no .git subdir. Probably a broken clone. Deleting."
243                 verbose rm -rf "$d"
244                 return
245         fi
246         # if we have the dir, always keep it
247         if [ -d "$d" ]; then
248                 msg "Repository $d enabled because it already exists"
249                 $ECHO "$d"
250                 return
251         fi
252         # if we have matching pk3, skip
253         if [ x"$p" != x"$d" ] && [ -f "$p" ]; then
254                 msg "Repository $d disabled by matching .pk3 file, delete $p or create $d.yes to enable"
255                 return
256         fi
257         # if "no" flag is set, skip
258         if matchrepoflag "$f" no; then
259                 msg "Repository $d disabled by default, create $d.yes to enable"
260                 return
261         fi
262         # default: enable
263         msg "Repository $d enabled by default"
264         $ECHO "$d"
265 }
266
267 listrepos()
268 {
269         $ECHO `allrepos listrepos_`
270 }
271 initrepo
272 repos=`listrepos`
273
274 ifrepoenabled()
275 {
276         eval ire_test=\$$(($1 + 3))
277         shift
278         case " $repos " in
279                 *" $ire_test "*)
280                         "$@"
281                         ;;
282         esac
283 }
284 check_mergeconflict() # overrides the one in ./all
285 {
286         if git ls-files -u | grep ' 1   '; then
287                 $ECHO
288                 $ECHO "MERGE CONFLICT."
289                 $ECHO "change into the \"$1\" project directory, and then:"
290                 $ECHO "- edit the files mentioned above with your favorite editor,"
291                 $ECHO "  and fix the conflicts (marked with <<<<<<< blocks)"
292                 $ECHO "- for binary files, you can select the files using"
293                 $ECHO "  git checkout --ours or git checkout --theirs"
294                 $ECHO "- when done with a file, 'git add' the file"
295                 $ECHO "- when done, 'git commit'"
296                 $ECHO
297                 exit 1
298         fi
299 }
300
301 visible_repo_name()
302 {
303         case "$1" in
304                 .)
305                         $ECHO "the root directory"
306                         ;;
307                 *)
308                         $ECHO "\"$1\""
309                         ;;
310         esac
311 }
312
313 fix_upstream_rebase()
314 {
315         if [ -z "$r_me" ] || [ -z "$r_other" ]; then
316                 return
317         fi
318
319         # one of the two sides of the merge should be remote upstream, or all is fine
320         r_r=`git symbolic-ref HEAD`
321         r_r=${r_r#refs/heads/}
322         r_rem=`git config "branch.$r_rem.remote" || $ECHO origin`
323         r_bra=`git config "branch.$r_bra.merge" || $ECHO "$r_r"`
324         r_bra=${r_bra#refs/heads/}
325         if [ x"$r_me" != x"`git rev-parse "$r_rem/$r_bra"`" ]; then
326                 if [ x"$r_other" != x"`git rev-parse "$r_rem/$r_bra"`" ]; then
327                         return
328                 fi
329         fi
330
331         r_base=`git merge-base "$r_me" "$r_other"`
332
333         # no merge-base? upstream did filter-branch
334         if [ -n "$r_base" ]; then
335                 # otherwise, check if the two histories are "similar"
336                 r_l_me=`git log --pretty="format:%s" "$r_other".."$r_me" | grep -v "^Merge" | sort -u`
337                 r_l_other=`git log --pretty="format:%s" "$r_me".."$r_other" | grep -v "^Merge" | sort -u`
338
339                 # heuristics: upstream rebase/filter-branch if more than 50% of the commits of one of the sides are in the other too
340                 r_lc_me=`$ECHO "$r_l_me" | wc -l`
341                 r_lc_other=`$ECHO "$r_l_other" | wc -l`
342                 r_lc_together=`{ $ECHO "$r_l_me"; $ECHO "$r_l_other"; } | sort -u | wc -l`
343                 r_lc_same=$(($r_lc_me + $r_lc_other - $r_lc_together))
344
345                 if [ $(( $r_lc_same * 2 )) -gt $(( $r_lc_me )) ] || [ $(( $r_lc_same * 2 )) -gt $(( $r_lc_other )) ]; then
346                         if yesno "Probable upstream rebase detected, automatically fix?" 'git log --oneline --graph --date-order --left-right "$r_other"..."$r_me"'; then
347                                 git reset --hard "$r_me"
348                                 git pull --rebase
349                                 return 1
350                         fi
351                 fi
352         fi
353
354         return 0
355 }
356
357 fix_upstream_rebase_mergeok()
358 {
359         r_me=`git rev-parse --revs-only HEAD^1 2>/dev/null || true`
360         r_other=`git rev-parse --revs-only HEAD^2 2>/dev/null || true`
361         fix_upstream_rebase
362 }
363
364 fix_upstream_rebase_mergefail()
365 {
366         r_me=`git rev-parse --revs-only HEAD 2>/dev/null || true`
367         r_other=`git rev-parse --revs-only MERGE_HEAD 2>/dev/null || true`
368         fix_upstream_rebase
369 }
370
371 fix_git_config()
372 {
373         if ! [ -f ".git/config" ]; then
374                 $ECHO "Not a git repository. Bailing out to not cause damage."
375                 exit 1
376         fi
377         verbose git config remote.origin.url "$1"
378         if [ -n "$2" ]; then
379                 verbose git config remote.origin.pushurl "$2"
380         else
381                 verbose git config --unset remote.origin.pushurl || true
382         fi
383         verbose git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
384         if testrepoflag "$d" noautocrlf; then
385                 verbose git config --unset core.autocrlf || true
386         else
387                 verbose git config core.autocrlf input
388         fi
389         if [ -z "`git config push.default || true`" ]; then
390                 verbose git config push.default current # or is tracking better?
391         fi
392         verbose git config filter.mapclean.clean "tr -d '\r' | grep '^[^/]'"
393         verbose git config filter.mapclean.smudge "cat"
394 }
395
396 setrepovars()
397 {
398         while [ $# -gt 4 ]; do
399                 shift
400         done
401         d=$1
402         url="$base$2"
403         if [ -n "$pushbase" ]; then
404                 pushurl="$pushbase$2"
405         else
406                 pushurl=
407         fi
408         branch=$3
409         f=$4
410 }
411
412 handled=true
413 case "$cmd" in
414         fix_upstream_rebase)
415                 fix_upstream_rebase_()
416                 {
417                         setrepovars "$@"
418                         enter "$d0/$d" verbose
419                         verbose fix_upstream_rebase_mergefail && verbose fix_upstream_rebase_mergeok
420                 }
421                 allrepos ifrepoenabled 0 fix_upstream_rebase_
422                 ;;
423         fix_config)
424                 fix_config_()
425                 {
426                         setrepovars "$@"
427                         if [ -f "$d0/$d/.git/config" ]; then
428                                 verbose cd "$d0/$d"
429                                 fix_git_config "$url" "$pushurl"
430                                 cd "$d0"
431                         fi
432                 }
433                 allrepos ifrepoenabled 0 fix_config_
434                 ;;
435         keygen)
436                 if [ -f ~/.ssh/id_rsa.pub ]; then
437                         msg ""
438                         msg "A key already exists and no new one will be generated. If you"
439                         msg "already have done the procedure for getting your key approved, you"
440                         msg "can skip the following paragraph and already use the repository."
441                         msg ""
442                         msg "To get access, your key has to be approved first. For that, visit"
443                         msg "$devsite_url, then log in, create a \"New Issue\" on"
444                         msg "the \"Support\" tracker in the \"Repository\" category where you"
445                         msg "apply for access and paste the following output into the issue:"
446                         msg ""
447                         msg "`cat ~/.ssh/id_rsa.pub`"
448                 elif [ -f ~/.ssh/id_dsa.pub ]; then
449                         msg ""
450                         msg "A key already exists and no new one will be generated. If you"
451                         msg "already have done the procedure for getting your key approved, you"
452                         msg "can skip the following paragraph and already use the repository."
453                         msg ""
454                         msg "To get access, your key has to be approved first. For that, visit"
455                         msg "$devsite_url, then log in, create a \"New Issue\" on"
456                         msg "the \"Support\" tracker in the \"Repository\" category where you"
457                         msg "apply for access and paste the following output into the issue:"
458                         msg ""
459                         msg "`cat ~/.ssh/id_dsa.pub`"
460                 else
461                         msg ""
462                         msg "No key has been generated yet. One will be generated now."
463                         msg "If other people are using your computer, it is recommended"
464                         msg "to specify a passphrase. Otherwise you can simply hit ENTER"
465                         msg "when asked for a passphrase."
466                         msg ""
467                         ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
468                         msg ""
469                         msg "To get access, your key has to be approved first. For that, visit"
470                         msg "$devsite_url, then log in, create a \"New Issue\" on"
471                         msg "the \"Support\" tracker in the \"Repository\" category where you"
472                         msg "apply for access and paste the following output into the issue:"
473                         msg ""
474                         msg "`cat ~/.ssh/id_rsa.pub`"
475                 fi
476                 msg ""
477                 msg "Note that you will only have write access to branches that start"
478                 msg "with your user name."
479                 msg
480                 msg "Once you have gotten access, run ./all update -p"
481                 ;;
482         update|pull)
483                 allow_pull=true
484                 need_bestmirror=false
485
486                 newprotocol=
487                 newpushprotocol=
488                 newlocation=
489
490                 case "`git config xonotic.all.mirrorselection 2>/dev/null || true`" in
491                         done)
492                                 ;;
493                         try_same)
494                                 need_bestmirror=true
495                                 ;;
496                         try_all)
497                                 newprotocol="git http"
498                                 newlocation="any"
499                                 need_bestmirror=true
500                                 ;;
501                         *)
502                                 newprotocol= # same protocol
503                                 newlocation="any"
504                                 need_bestmirror=true
505                                 ;;
506                 esac
507
508                 if $need_bestmirror; then
509                         found=false
510                         identifymirror_()
511                         {
512                                 if [ x"$base" = x"$3" ]; then
513                                         found=true
514                                 fi
515                         }
516                         allmirrors identifymirror_
517                         if ! $found; then
518                                 msg ""
519                                 msg "Current mirror not found = $base"
520                                 msg "but the last pull attempt failed."
521                                 msg ""
522                                 msg "Use ./all update -l any to switch to the best mirror."
523                                 msg ""
524                                 need_bestmirror=false
525                         fi
526                 fi
527
528                 while :; do
529                         if [ x"$1" = x"-N" ]; then
530                                 allow_pull=false
531                         elif [ x"$1" = x"-p" ]; then
532                                 newpushprotocol=ssh
533                                 need_bestmirror=true
534                         elif [ x"$1" = x"-s" ]; then
535                                 newprotocol=ssh
536                                 need_bestmirror=true
537                         elif [ x"$1" = x"-g" ]; then
538                                 newprotocol=git
539                                 need_bestmirror=true
540                         elif [ x"$1" = x"-h" ]; then
541                                 newprotocol=http
542                                 need_bestmirror=true
543                         elif [ x"$1" = x"-l" ]; then
544                                 newlocation=$2
545                                 need_bestmirror=true
546                                 shift
547                         else
548                                 break
549                         fi
550                         shift
551                 done
552                 
553                 if $need_bestmirror; then
554                         newbase=`bestmirror "$base" "$newprotocol" "$newlocation"`
555                         if [ -z "$newbase" ]; then
556                                 msg "Could not find any good mirror. Maybe try again later."
557                                 git config xonotic.all.mirrorselection try_all
558                                 exit 1
559                         fi
560                         if [ -n "$newpushprotocol" ]; then
561                                 if [ -n "$pushbase" ]; then
562                                         newpushbase=`bestmirror "$pushbase" "$newpushprotocol" "$newlocation"`
563                                 else
564                                         newpushbase=`bestmirror "$base" "$newpushprotocol" "$newlocation"`
565                                 fi
566                         else
567                                 newpushbase=$pushbase
568                         fi
569
570                         if [ x"$base" != x"$newbase" ] || [ x"$pushbase" != x"$newpushbase" ]; then
571                                 base=$newbase
572                                 pushbase=$newpushbase
573                                 seturl_()
574                                 {
575                                         setrepovars "$@"
576                                         if [ x"$d" = x"." ]; then
577                                                 fix_git_config "$url" "$pushurl"
578                                         fi
579                                 }
580                                 allrepos ifrepoenabled 0 seturl_
581                         fi
582                         git config xonotic.all.mirrorselection done
583                 fi
584
585                 "$SELF" fix_config
586
587                 pull_()
588                 {
589                         setrepovars "$@"
590                         if [ -f "$d0/$d/.git/config" ]; then
591                                 # if we have .no file, skip
592                                 if [ -f "$d0/$d.no" ]; then
593                                         msg "Repository $d disabled by a .no file, delete $d.no to enable; thus, not updated"
594                                         return
595                                 fi
596                                 if $allow_pull; then
597                                         enter "$d0/$d" verbose
598                                         r=`git symbolic-ref HEAD`
599                                         r=${r#refs/heads/}
600                                         if git config branch.$r.remote >/dev/null 2>&1; then
601                                                 o=`( cd "$d0" && git config xonotic.all.mirrorselection 2>/dev/null || true )`
602                                                 ( cd "$d0" && git config xonotic.all.mirrorselection try_same )
603                                                 if ! verbose git pull; then
604                                                         fix_upstream_rebase_mergefail || true
605                                                         check_mergeconflict "$d"
606                                                         $ECHO "Pulling failed. Press ENTER to continue, or Ctrl-C to abort."
607                                                         read -r DUMMY
608                                                 else
609                                                         ( cd "$d0" && git config xonotic.all.mirrorselection "$o" )
610                                                         fix_upstream_rebase_mergeok || true
611                                                 fi
612                                         fi
613
614                                         cd "$d00"
615                                         checkself "$cmd" "$@"
616                                         cd "$d0/$d"
617                                         verbose git remote prune origin
618                                         cd "$d0"
619                                 fi
620                         else
621                                 if [ -d "$d0/$d" ]; then
622                                         if yesno "$d0/$d is in the way, get rid of it and reclone?"; then
623                                                 verbose rm -rf "$d0/$d"
624                                         else
625                                                 echo "Note: $d0/$d will stay broken."
626                                                 return
627                                         fi
628                                 fi
629                                 o=`git config xonotic.all.mirrorselection 2>/dev/null || true`
630                                 git config xonotic.all.mirrorselection try_same
631                                 verbose git clone "$url" "$d0/$d"
632                                 git config xonotic.all.mirrorselection "$o"
633                                 enter "$d0/$d" verbose
634                                 fix_git_config "$url" "$pushurl"
635                                 if [ "$branch" != "master" ]; then
636                                         verbose git checkout --track -b "$branch" origin/"$branch"
637                                 fi
638                                 cd "$d0"
639                         fi
640                 }
641                 allrepos ifrepoenabled 0 pull_
642                 ;;
643         checkout|switch)
644                 checkoutflags=
645                 if [ x"$1" = x"-f" ]; then
646                         checkoutflags=-f
647                         shift
648                 fi
649                 remote=$1
650                 branch=$2
651                 if [ -z "$branch" ]; then
652                         case "$remote" in
653                                 origin/*)
654                                         askbranch=${remote#origin/}
655                                         remote=origin
656                                         ;;
657                                 *)
658                                         askbranch=$remote
659                                         remote=origin
660                                         ;;
661                         esac
662                 fi
663                 if [ -n "$checkoutflags" ]; then
664                         set -- -f "$@" # to make checkself work again
665                 fi
666                 exists=false
667                 checkout_()
668                 {
669                         setrepovars "$@"
670                         enter "$d0/$d" verbose
671                         b=$askbranch
672                         if [ -n "$b" ] && git rev-parse "refs/heads/$b" >/dev/null 2>&1; then
673                                 exists=true
674                                 verbose git checkout $checkoutflags "$b"
675                         elif [ -n "$b" ] && git rev-parse "refs/remotes/$remote/$b" >/dev/null 2>&1; then
676                                 exists=true
677                                 verbose git checkout $checkoutflags --track -b "$b" "$remote/$b"
678                         else
679                                 b=$branch
680                                 if git rev-parse "refs/heads/$b" >/dev/null 2>&1; then
681                                         verbose git checkout $checkoutflags "$b"
682                                 elif git rev-parse "refs/remotes/$remote/$b" >/dev/null 2>&1; then
683                                         verbose git checkout $checkoutflags --track -b "$b" "$remote/$b"
684                                 else
685                                         $ECHO "WTF? Not even branch $b doesn't exist in $d"
686                                         exit 1
687                                 fi
688                         fi
689                         cd "$d00"
690                         checkself "$cmd" "$@"
691                         cd "$d0"
692                 }
693                 allrepos ifrepoenabled 0 checkout_
694                 if ! $exists; then
695                         $ECHO "The requested branch was not found in any repository."
696                 fi
697                 exec "$SELF" branch
698                 ;;
699         branch)
700                 remote=$1
701                 askbranch=$2
702                 srcbranch=$3
703                 if [ -z "$askbranch" ]; then
704                         askbranch=$remote
705                         remote=origin
706                 fi
707                 branch_show_()
708                 {
709                         setrepovars "$@"
710                         enter "$d0/$d"
711                         r=`git symbolic-ref HEAD`
712                         r=${r#refs/heads/}
713                         dv=`visible_repo_name "$d"`
714                         $ECHO "$dv is at $r"
715                         cd "$d0"
716                 }
717                 if [ -n "$askbranch" ]; then
718                         branch_()
719                         {
720                                 setrepovars "$@"
721                                 dv=`visible_repo_name "$d"`
722                                 enter "$d0/$d" verbose
723                                 if git rev-parse "refs/heads/$askbranch" >/dev/null 2>&1; then
724                                         $ECHO "Already having this branch in $dv."
725                                 else
726                                         if yesno "Branch in $dv?"; then
727                                                 if [ -n "$srcbranch" ]; then
728                                                         b=$srcbranch
729                                                 else
730                                                         b=$branch
731                                                         verbose git fetch origin || true
732                                                 fi
733                                                 verbose git checkout -b "$askbranch" "$b"
734                                                 verbose git config "branch.$askbranch.remote" "$remote"
735                                                 verbose git config "branch.$askbranch.merge" "refs/heads/$askbranch"
736                                         fi
737                                 fi
738                                 cd "$d0"
739                         }
740                         allrepos ifrepoenabled 0 branch_
741                 fi
742                 allrepos ifrepoenabled 0 branch_show_
743                 ;;
744         push|commit)
745                 submit=$1
746                 push_()
747                 {
748                         setrepovars "$@"
749                         dv=`visible_repo_name "$d"`
750                         enter "$d0/$d" verbose
751                         r=`git symbolic-ref HEAD`
752                         r=${r#refs/heads/}
753                         diffdata=`git diff --color HEAD`
754                         if [ -n "$diffdata" ]; then
755                                 # we have uncommitted changes
756                                 if yesno "Uncommitted changes in \"$r\" in $dv. Commit?" '$ECHO "$diffdata" | less -r'; then
757                                         verbose git commit -a
758                                 fi
759                         fi
760                         rem=`git config "branch.$r.remote" || $ECHO origin`
761                         bra=`git config "branch.$r.merge" || $ECHO "$r"`
762                         upstream="$rem/${bra#refs/heads/}"
763                         if ! git rev-parse "$upstream" >/dev/null 2>&1; then
764                                 upstream="origin/$branch"
765                         fi
766                         logdata=`git log --color "$upstream".."$r"`
767                         if [ -n "$logdata" ]; then
768                                 if yesno "Push \"$r\" in $dv?" '$ECHO "$logdata" | less -r'; then
769                                         verbose git push "$rem" HEAD
770                                 fi
771                         fi
772                         if [ x"$submit" = x"-s" ]; then
773                                 case "$r" in
774                                         */*)
775                                                 verbose git push "$rem" HEAD:"${bra%%/*}/finished/${bra#*/}"
776                                                 ;;
777                                 esac
778                         fi
779                         cd "$d0"
780                 }
781                 allrepos ifrepoenabled 0 push_
782                 ;;
783         each|foreach)
784                 keep_going=false
785                 if [ x"$1" = x"-k" ]; then
786                         keep_going=true
787                         shift
788                 fi
789                 for d in $repos; do
790                         if verbose cd "$d0/$d"; then
791                                 if $keep_going; then
792                                         verbose "$@" || true
793                                 else
794                                         verbose "$@"
795                                 fi
796                                 cd "$d0"
797                         fi
798                 done
799                 ;;
800         clean)
801                 "$SELF" fix_config
802                 "$SELF" update -N
803                 force=false
804                 gotoupstream=false
805                 fetchupstream=false
806                 gotomaster=false
807                 rmuntracked=false
808                 killbranches=false
809                 # usage:
810                 #   ./all clean [-m] [-f | -fu | -fU] [-r] [-D]
811                 #   ./all clean --reclone
812                 found=false
813                 for X in "$@"; do
814                         if [ x"$X" = x"--reclone" ]; then
815                                 force=true
816                                 fetchupstream=true
817                                 gotoupstream=true
818                                 gotomaster=true
819                                 rmuntracked=true
820                                 killbranches=true
821                         elif [ x"$X" = x"-f" ]; then
822                                 force=true
823                         elif [ x"$X" = x"-u" ]; then
824                                 gotoupstream=true
825                         elif [ x"$X" = x"-U" ]; then
826                                 gotoupstream=true
827                                 fetchupstream=true
828                         elif [ x"$X" = x"-fu" ]; then
829                                 force=true
830                                 gotoupstream=true
831                         elif [ x"$X" = x"-fU" ]; then
832                                 force=true
833                                 gotoupstream=true
834                                 fetchupstream=true
835                         elif [ x"$X" = x"-m" ]; then
836                                 gotomaster=true
837                         elif [ x"$X" = x"-r" ]; then
838                                 rmuntracked=true
839                         elif [ x"$X" = x"-D" ]; then
840                                 killbranches=true
841                         elif $ECHO "$X" | grep '^-FFFF*UUUU*$' >/dev/null; then
842                                 msg ''
843                                 msg "        _____"
844                                 msg "    ,--'-\\P/\`\\  FFFFFFF"
845                                 msg " __/_    B/,-.\\  FFFFFFF"
846                                 msg " /  _\\  (//  O\\\\  FFFFFF"
847                                 msg "| (O  \`) _\\._ _)\\  FFFUU"
848                                 msg "| |___/.^d0~~\"\\  \\ UUUU"
849                                 msg "|     |\`~'     \\ |  UUUU"
850                                 msg "|     |    __,C>|| UUUU"
851                                 msg "\\    /_ ,-/,-'   |  UUUU"
852                                 msg " \\\\_ \\_>~'      /  UUUU-"
853                                 msg ''
854                         else
855                                 msg "Unknown arg: $X"
856                         fi
857                         found=true
858                 done
859                 if ! $found; then
860                         rmuntracked=true
861                 fi
862                 clean_()
863                 {
864                         setrepovars "$@"
865                         verbose cd "$d0/$d"
866                         if $gotoupstream; then
867                                 if ! $force; then
868                                         msg "Must also use -f (delete local changes) when using -u"
869                                         exit 1
870                                 fi
871                                 if $gotomaster; then
872                                         if $fetchupstream; then
873                                                 verbose git fetch origin
874                                                 verbose git remote prune origin
875                                         fi
876                                         verbose git checkout -f "$branch"
877                                         verbose git reset --hard origin/"$branch"
878                                 else
879                                         r=`git symbolic-ref HEAD`
880                                         r=${r#refs/heads/}
881                                         rem=`git config "branch.$r.remote" || $ECHO origin`
882                                         bra=`git config "branch.$r.merge" || $ECHO "$r"`
883                                         upstream="$rem/${bra#refs/heads/}"
884                                         if $fetchupstream; then
885                                                 for t in `git tag -l "xonotic-v"*`; do
886                                                         verbose git tag -d "$t"
887                                                 done
888                                                 verbose git fetch "$rem"
889                                                 verbose git remote prune "$rem"
890                                         fi
891                                         if ! git rev-parse "$upstream" >/dev/null 2>&1; then
892                                                 upstream="origin/$branch"
893                                         fi
894                                         verbose git reset --hard "$upstream"
895                                 fi
896                         elif $gotomaster; then
897                                 if $force; then
898                                         verbose git checkout -f "$branch"
899                                         verbose git reset --hard
900                                 else
901                                         verbose git checkout "$branch"
902                                 fi
903                         elif $force; then
904                                 verbose git reset --hard
905                         fi
906                         if $rmuntracked; then
907                                 case "$d" in
908                                         .)
909                                                 verbose git clean -df || true
910                                                 ;;
911                                         *)
912                                                 verbose git clean -xdf || true
913                                                 ;;
914                                 esac
915                         fi
916                         if $killbranches; then
917                                 git for-each-ref --format='%(refname)' refs/heads/ | while IFS= read -r B; do
918                                         if [ x"$B" != x"`git symbolic-ref HEAD`" ]; then
919                                                 verbose git branch -D "${B#refs/heads/}"
920                                         fi
921                                 done
922                                 git rev-parse refs/heads/master >/dev/null 2>&1 || verbose git branch --track master origin/master || true
923                                 git rev-parse "refs/heads/$branch" >/dev/null 2>&1 || verbose git branch --track "$branch" origin/"$branch" || true
924                         fi
925                         checkself "$cmd" "$@"
926                 }
927                 allrepos ifrepoenabled 0 clean_
928                 ;;
929         help)
930                 $ECHO "  $SELF branch <branch>"
931                 $ECHO "  $SELF branch <remote> <branch> [<srcbranch>]"
932                 $ECHO "  $SELF checkout|switch <branch>"
933                 $ECHO "  $SELF checkout|switch <remote>/<branch>"
934                 $ECHO "  $SELF clean [-m] [-f | -fu | -fU] [-r] [-D]"
935                 $ECHO "  $SELF clean --reclone"
936                 $ECHO "  $SELF each|foreach [-k] command..."
937                 $ECHO "  $SELF fix_upstream_rebase"
938                 $ECHO "  $SELF keygen"
939                 $ECHO "  $SELF push|commit [-s]"
940                 $ECHO "  $SELF update|pull [-N] [-s | -h [-p] | -g [-p]] [-l de|nl|default]"
941                 handled=false
942                 ;;
943         *)
944                 handled=false
945                 ;;
946 esac