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