Merge branch 'js/ls-tree-error'
[git.git] / git-submodule.sh
1 #!/bin/sh
2 #
3 # git-submodules.sh: add, init, update or list git submodules
4 #
5 # Copyright (c) 2007 Lars Hjemli
6
7 dashless=$(basename "$0" | sed -e 's/-/ /')
8 USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
9    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
10    or: $dashless [--quiet] init [--] [<path>...]
11    or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
12    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
13    or: $dashless [--quiet] foreach [--recursive] <command>
14    or: $dashless [--quiet] sync [--] [<path>...]"
15 OPTIONS_SPEC=
16 . git-sh-setup
17 . git-sh-i18n
18 . git-parse-remote
19 require_work_tree
20
21 command=
22 branch=
23 force=
24 reference=
25 cached=
26 recursive=
27 init=
28 files=
29 nofetch=
30 update=
31 prefix=
32
33 # Resolve relative url by appending to parent's url
34 resolve_relative_url ()
35 {
36         remote=$(get_default_remote)
37         remoteurl=$(git config "remote.$remote.url") ||
38                 remoteurl=$(pwd) # the repository is its own authoritative upstream
39         url="$1"
40         remoteurl=${remoteurl%/}
41         sep=/
42         while test -n "$url"
43         do
44                 case "$url" in
45                 ../*)
46                         url="${url#../}"
47                         case "$remoteurl" in
48                         */*)
49                                 remoteurl="${remoteurl%/*}"
50                                 ;;
51                         *:*)
52                                 remoteurl="${remoteurl%:*}"
53                                 sep=:
54                                 ;;
55                         *)
56                                 die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
57                                 ;;
58                         esac
59                         ;;
60                 ./*)
61                         url="${url#./}"
62                         ;;
63                 *)
64                         break;;
65                 esac
66         done
67         echo "$remoteurl$sep${url%/}"
68 }
69
70 #
71 # Get submodule info for registered submodules
72 # $@ = path to limit submodule list
73 #
74 module_list()
75 {
76         git ls-files --error-unmatch --stage -- "$@" |
77         perl -e '
78         my %unmerged = ();
79         my ($null_sha1) = ("0" x 40);
80         while (<STDIN>) {
81                 chomp;
82                 my ($mode, $sha1, $stage, $path) =
83                         /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/;
84                 next unless $mode eq "160000";
85                 if ($stage ne "0") {
86                         if (!$unmerged{$path}++) {
87                                 print "$mode $null_sha1 U\t$path\n";
88                         }
89                         next;
90                 }
91                 print "$_\n";
92         }
93         '
94 }
95
96 #
97 # Map submodule path to submodule name
98 #
99 # $1 = path
100 #
101 module_name()
102 {
103         # Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
104         re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
105         name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
106                 sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
107        test -z "$name" &&
108        die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
109        echo "$name"
110 }
111
112 #
113 # Clone a submodule
114 #
115 # Prior to calling, cmd_update checks that a possibly existing
116 # path is not a git repository.
117 # Likewise, cmd_add checks that path does not exist at all,
118 # since it is the location of a new submodule.
119 #
120 module_clone()
121 {
122         path=$1
123         url=$2
124         reference="$3"
125
126         if test -n "$reference"
127         then
128                 git-clone "$reference" -n "$url" "$path"
129         else
130                 git-clone -n "$url" "$path"
131         fi ||
132         die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
133 }
134
135 #
136 # Add a new submodule to the working tree, .gitmodules and the index
137 #
138 # $@ = repo path
139 #
140 # optional branch is stored in global branch variable
141 #
142 cmd_add()
143 {
144         # parse $args after "submodule ... add".
145         while test $# -ne 0
146         do
147                 case "$1" in
148                 -b | --branch)
149                         case "$2" in '') usage ;; esac
150                         branch=$2
151                         shift
152                         ;;
153                 -f | --force)
154                         force=$1
155                         ;;
156                 -q|--quiet)
157                         GIT_QUIET=1
158                         ;;
159                 --reference)
160                         case "$2" in '') usage ;; esac
161                         reference="--reference=$2"
162                         shift
163                         ;;
164                 --reference=*)
165                         reference="$1"
166                         shift
167                         ;;
168                 --)
169                         shift
170                         break
171                         ;;
172                 -*)
173                         usage
174                         ;;
175                 *)
176                         break
177                         ;;
178                 esac
179                 shift
180         done
181
182         repo=$1
183         path=$2
184
185         if test -z "$path"; then
186                 path=$(echo "$repo" |
187                         sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
188         fi
189
190         if test -z "$repo" -o -z "$path"; then
191                 usage
192         fi
193
194         # assure repo is absolute or relative to parent
195         case "$repo" in
196         ./*|../*)
197                 # dereference source url relative to parent's url
198                 realrepo=$(resolve_relative_url "$repo") || exit
199                 ;;
200         *:*|/*)
201                 # absolute url
202                 realrepo=$repo
203                 ;;
204         *)
205                 die "$(eval_gettext "repo URL: '\$repo' must be absolute or begin with ./|../")"
206         ;;
207         esac
208
209         # normalize path:
210         # multiple //; leading ./; /./; /../; trailing /
211         path=$(printf '%s/\n' "$path" |
212                 sed -e '
213                         s|//*|/|g
214                         s|^\(\./\)*||
215                         s|/\./|/|g
216                         :start
217                         s|\([^/]*\)/\.\./||
218                         tstart
219                         s|/*$||
220                 ')
221         git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
222         die "$(eval_gettext "'\$path' already exists in the index")"
223
224         if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
225         then
226                 (
227                         eval_gettext "The following path is ignored by one of your .gitignore files:
228 \$path
229 Use -f if you really want to add it." &&
230                         echo
231                 ) >&2
232                 exit 1
233         fi
234
235         # perhaps the path exists and is already a git repo, else clone it
236         if test -e "$path"
237         then
238                 if test -d "$path"/.git -o -f "$path"/.git
239                 then
240                         eval_gettext "Adding existing repo at '\$path' to the index"; echo
241                 else
242                         die "$(eval_gettext "'\$path' already exists and is not a valid git repo")"
243                 fi
244
245         else
246
247                 module_clone "$path" "$realrepo" "$reference" || exit
248                 (
249                         clear_local_git_env
250                         cd "$path" &&
251                         # ash fails to wordsplit ${branch:+-b "$branch"...}
252                         case "$branch" in
253                         '') git checkout -f -q ;;
254                         ?*) git checkout -f -q -B "$branch" "origin/$branch" ;;
255                         esac
256                 ) || die "$(eval_gettext "Unable to checkout submodule '\$path'")"
257         fi
258         git config submodule."$path".url "$realrepo"
259
260         git add $force "$path" ||
261         die "$(eval_gettext "Failed to add submodule '\$path'")"
262
263         git config -f .gitmodules submodule."$path".path "$path" &&
264         git config -f .gitmodules submodule."$path".url "$repo" &&
265         git add --force .gitmodules ||
266         die "$(eval_gettext "Failed to register submodule '\$path'")"
267 }
268
269 #
270 # Execute an arbitrary command sequence in each checked out
271 # submodule
272 #
273 # $@ = command to execute
274 #
275 cmd_foreach()
276 {
277         # parse $args after "submodule ... foreach".
278         while test $# -ne 0
279         do
280                 case "$1" in
281                 -q|--quiet)
282                         GIT_QUIET=1
283                         ;;
284                 --recursive)
285                         recursive=1
286                         ;;
287                 -*)
288                         usage
289                         ;;
290                 *)
291                         break
292                         ;;
293                 esac
294                 shift
295         done
296
297         toplevel=$(pwd)
298
299         # dup stdin so that it can be restored when running the external
300         # command in the subshell (and a recursive call to this function)
301         exec 3<&0
302
303         module_list |
304         while read mode sha1 stage path
305         do
306                 if test -e "$path"/.git
307                 then
308                         say "$(eval_gettext "Entering '\$prefix\$path'")"
309                         name=$(module_name "$path")
310                         (
311                                 prefix="$prefix$path/"
312                                 clear_local_git_env
313                                 cd "$path" &&
314                                 eval "$@" &&
315                                 if test -n "$recursive"
316                                 then
317                                         cmd_foreach "--recursive" "$@"
318                                 fi
319                         ) <&3 3<&- ||
320                         die "$(eval_gettext "Stopping at '\$path'; script returned non-zero status.")"
321                 fi
322         done
323 }
324
325 #
326 # Register submodules in .git/config
327 #
328 # $@ = requested paths (default to all)
329 #
330 cmd_init()
331 {
332         # parse $args after "submodule ... init".
333         while test $# -ne 0
334         do
335                 case "$1" in
336                 -q|--quiet)
337                         GIT_QUIET=1
338                         ;;
339                 --)
340                         shift
341                         break
342                         ;;
343                 -*)
344                         usage
345                         ;;
346                 *)
347                         break
348                         ;;
349                 esac
350                 shift
351         done
352
353         module_list "$@" |
354         while read mode sha1 stage path
355         do
356                 # Skip already registered paths
357                 name=$(module_name "$path") || exit
358                 if test -z "$(git config "submodule.$name.url")"
359                 then
360                         url=$(git config -f .gitmodules submodule."$name".url)
361                         test -z "$url" &&
362                         die "$(eval_gettext "No url found for submodule path '\$path' in .gitmodules")"
363
364                         # Possibly a url relative to parent
365                         case "$url" in
366                         ./*|../*)
367                                 url=$(resolve_relative_url "$url") || exit
368                                 ;;
369                         esac
370                         git config submodule."$name".url "$url" ||
371                         die "$(eval_gettext "Failed to register url for submodule path '\$path'")"
372                 fi
373
374                 # Copy "update" setting when it is not set yet
375                 upd="$(git config -f .gitmodules submodule."$name".update)"
376                 test -z "$upd" ||
377                 test -n "$(git config submodule."$name".update)" ||
378                 git config submodule."$name".update "$upd" ||
379                 die "$(eval_gettext "Failed to register update mode for submodule path '\$path'")"
380
381                 say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$path'")"
382         done
383 }
384
385 #
386 # Update each submodule path to correct revision, using clone and checkout as needed
387 #
388 # $@ = requested paths (default to all)
389 #
390 cmd_update()
391 {
392         # parse $args after "submodule ... update".
393         orig_flags=
394         while test $# -ne 0
395         do
396                 case "$1" in
397                 -q|--quiet)
398                         GIT_QUIET=1
399                         ;;
400                 -i|--init)
401                         init=1
402                         ;;
403                 -N|--no-fetch)
404                         nofetch=1
405                         ;;
406                 -f|--force)
407                         force=$1
408                         ;;
409                 -r|--rebase)
410                         update="rebase"
411                         ;;
412                 --reference)
413                         case "$2" in '') usage ;; esac
414                         reference="--reference=$2"
415                         orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
416                         shift
417                         ;;
418                 --reference=*)
419                         reference="$1"
420                         ;;
421                 -m|--merge)
422                         update="merge"
423                         ;;
424                 --recursive)
425                         recursive=1
426                         ;;
427                 --)
428                         shift
429                         break
430                         ;;
431                 -*)
432                         usage
433                         ;;
434                 *)
435                         break
436                         ;;
437                 esac
438                 orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
439                 shift
440         done
441
442         if test -n "$init"
443         then
444                 cmd_init "--" "$@" || return
445         fi
446
447         cloned_modules=
448         module_list "$@" | {
449         err=
450         while read mode sha1 stage path
451         do
452                 if test "$stage" = U
453                 then
454                         echo >&2 "Skipping unmerged submodule $path"
455                         continue
456                 fi
457                 name=$(module_name "$path") || exit
458                 url=$(git config submodule."$name".url)
459                 update_module=$(git config submodule."$name".update)
460                 if test -z "$url"
461                 then
462                         # Only mention uninitialized submodules when its
463                         # path have been specified
464                         test "$#" != "0" &&
465                         say "$(eval_gettext "Submodule path '\$path' not initialized
466 Maybe you want to use 'update --init'?")"
467                         continue
468                 fi
469
470                 if ! test -d "$path"/.git -o -f "$path"/.git
471                 then
472                         module_clone "$path" "$url" "$reference"|| exit
473                         cloned_modules="$cloned_modules;$name"
474                         subsha1=
475                 else
476                         subsha1=$(clear_local_git_env; cd "$path" &&
477                                 git rev-parse --verify HEAD) ||
478                         die "$(eval_gettext "Unable to find current revision in submodule path '\$path'")"
479                 fi
480
481                 if ! test -z "$update"
482                 then
483                         update_module=$update
484                 fi
485
486                 if test "$subsha1" != "$sha1"
487                 then
488                         subforce=$force
489                         # If we don't already have a -f flag and the submodule has never been checked out
490                         if test -z "$subsha1" -a -z "$force"
491                         then
492                                 subforce="-f"
493                         fi
494
495                         if test -z "$nofetch"
496                         then
497                                 # Run fetch only if $sha1 isn't present or it
498                                 # is not reachable from a ref.
499                                 (clear_local_git_env; cd "$path" &&
500                                         ( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) &&
501                                          test -z "$rev") || git-fetch)) ||
502                                 die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
503                         fi
504
505                         # Is this something we just cloned?
506                         case ";$cloned_modules;" in
507                         *";$name;"*)
508                                 # then there is no local change to integrate
509                                 update_module= ;;
510                         esac
511
512                         must_die_on_failure=
513                         case "$update_module" in
514                         rebase)
515                                 command="git rebase"
516                                 die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
517                                 say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
518                                 must_die_on_failure=yes
519                                 ;;
520                         merge)
521                                 command="git merge"
522                                 die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
523                                 say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
524                                 must_die_on_failure=yes
525                                 ;;
526                         *)
527                                 command="git checkout $subforce -q"
528                                 die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
529                                 say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
530                                 ;;
531                         esac
532
533                         if (clear_local_git_env; cd "$path" && $command "$sha1")
534                         then
535                                 say "$say_msg"
536                         elif test -n "$must_die_on_failure"
537                         then
538                                 die_with_status 2 "$die_msg"
539                         else
540                                 err="${err};$die_msg"
541                                 continue
542                         fi
543                 fi
544
545                 if test -n "$recursive"
546                 then
547                         (clear_local_git_env; cd "$path" && eval cmd_update "$orig_flags")
548                         res=$?
549                         if test $res -gt 0
550                         then
551                                 die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")"
552                                 if test $res -eq 1
553                                 then
554                                         err="${err};$die_msg"
555                                         continue
556                                 else
557                                         die_with_status $res "$die_msg"
558                                 fi
559                         fi
560                 fi
561         done
562
563         if test -n "$err"
564         then
565                 OIFS=$IFS
566                 IFS=';'
567                 for e in $err
568                 do
569                         if test -n "$e"
570                         then
571                                 echo >&2 "$e"
572                         fi
573                 done
574                 IFS=$OIFS
575                 exit 1
576         fi
577         }
578 }
579
580 set_name_rev () {
581         revname=$( (
582                 clear_local_git_env
583                 cd "$1" && {
584                         git describe "$2" 2>/dev/null ||
585                         git describe --tags "$2" 2>/dev/null ||
586                         git describe --contains "$2" 2>/dev/null ||
587                         git describe --all --always "$2"
588                 }
589         ) )
590         test -z "$revname" || revname=" ($revname)"
591 }
592 #
593 # Show commit summary for submodules in index or working tree
594 #
595 # If '--cached' is given, show summary between index and given commit,
596 # or between working tree and given commit
597 #
598 # $@ = [commit (default 'HEAD'),] requested paths (default all)
599 #
600 cmd_summary() {
601         summary_limit=-1
602         for_status=
603         diff_cmd=diff-index
604
605         # parse $args after "submodule ... summary".
606         while test $# -ne 0
607         do
608                 case "$1" in
609                 --cached)
610                         cached="$1"
611                         ;;
612                 --files)
613                         files="$1"
614                         ;;
615                 --for-status)
616                         for_status="$1"
617                         ;;
618                 -n|--summary-limit)
619                         if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
620                         then
621                                 :
622                         else
623                                 usage
624                         fi
625                         shift
626                         ;;
627                 --)
628                         shift
629                         break
630                         ;;
631                 -*)
632                         usage
633                         ;;
634                 *)
635                         break
636                         ;;
637                 esac
638                 shift
639         done
640
641         test $summary_limit = 0 && return
642
643         if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
644         then
645                 head=$rev
646                 test $# = 0 || shift
647         elif test -z "$1" -o "$1" = "HEAD"
648         then
649                 # before the first commit: compare with an empty tree
650                 head=$(git hash-object -w -t tree --stdin </dev/null)
651                 test -z "$1" || shift
652         else
653                 head="HEAD"
654         fi
655
656         if [ -n "$files" ]
657         then
658                 test -n "$cached" &&
659                 die "$(gettext -- "--cached cannot be used with --files")"
660                 diff_cmd=diff-files
661                 head=
662         fi
663
664         cd_to_toplevel
665         # Get modified modules cared by user
666         modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
667                 sane_egrep '^:([0-7]* )?160000' |
668                 while read mod_src mod_dst sha1_src sha1_dst status name
669                 do
670                         # Always show modules deleted or type-changed (blob<->module)
671                         test $status = D -o $status = T && echo "$name" && continue
672                         # Also show added or modified modules which are checked out
673                         GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
674                         echo "$name"
675                 done
676         )
677
678         test -z "$modules" && return
679
680         git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |
681         sane_egrep '^:([0-7]* )?160000' |
682         cut -c2- |
683         while read mod_src mod_dst sha1_src sha1_dst status name
684         do
685                 if test -z "$cached" &&
686                         test $sha1_dst = 0000000000000000000000000000000000000000
687                 then
688                         case "$mod_dst" in
689                         160000)
690                                 sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
691                                 ;;
692                         100644 | 100755 | 120000)
693                                 sha1_dst=$(git hash-object $name)
694                                 ;;
695                         000000)
696                                 ;; # removed
697                         *)
698                                 # unexpected type
699                                 (
700                                         eval_gettext "unexpected mode \$mod_dst" &&
701                                         echo
702                                 ) >&2
703                                 continue ;;
704                         esac
705                 fi
706                 missing_src=
707                 missing_dst=
708
709                 test $mod_src = 160000 &&
710                 ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
711                 missing_src=t
712
713                 test $mod_dst = 160000 &&
714                 ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
715                 missing_dst=t
716
717                 total_commits=
718                 case "$missing_src,$missing_dst" in
719                 t,)
720                         errmsg="$(eval_gettext "  Warn: \$name doesn't contain commit \$sha1_src")"
721                         ;;
722                 ,t)
723                         errmsg="$(eval_gettext "  Warn: \$name doesn't contain commit \$sha1_dst")"
724                         ;;
725                 t,t)
726                         errmsg="$(eval_gettext "  Warn: \$name doesn't contain commits \$sha1_src and \$sha1_dst")"
727                         ;;
728                 *)
729                         errmsg=
730                         total_commits=$(
731                         if test $mod_src = 160000 -a $mod_dst = 160000
732                         then
733                                 range="$sha1_src...$sha1_dst"
734                         elif test $mod_src = 160000
735                         then
736                                 range=$sha1_src
737                         else
738                                 range=$sha1_dst
739                         fi
740                         GIT_DIR="$name/.git" \
741                         git rev-list --first-parent $range -- | wc -l
742                         )
743                         total_commits=" ($(($total_commits + 0)))"
744                         ;;
745                 esac
746
747                 sha1_abbr_src=$(echo $sha1_src | cut -c1-7)
748                 sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)
749                 if test $status = T
750                 then
751                         blob="$(gettext "blob")"
752                         submodule="$(gettext "submodule")"
753                         if test $mod_dst = 160000
754                         then
755                                 echo "* $name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"
756                         else
757                                 echo "* $name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"
758                         fi
759                 else
760                         echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
761                 fi
762                 if test -n "$errmsg"
763                 then
764                         # Don't give error msg for modification whose dst is not submodule
765                         # i.e. deleted or changed to blob
766                         test $mod_dst = 160000 && echo "$errmsg"
767                 else
768                         if test $mod_src = 160000 -a $mod_dst = 160000
769                         then
770                                 limit=
771                                 test $summary_limit -gt 0 && limit="-$summary_limit"
772                                 GIT_DIR="$name/.git" \
773                                 git log $limit --pretty='format:  %m %s' \
774                                 --first-parent $sha1_src...$sha1_dst
775                         elif test $mod_dst = 160000
776                         then
777                                 GIT_DIR="$name/.git" \
778                                 git log --pretty='format:  > %s' -1 $sha1_dst
779                         else
780                                 GIT_DIR="$name/.git" \
781                                 git log --pretty='format:  < %s' -1 $sha1_src
782                         fi
783                         echo
784                 fi
785                 echo
786         done |
787         if test -n "$for_status"; then
788                 if [ -n "$files" ]; then
789                         gettext "# Submodules changed but not updated:"; echo
790                 else
791                         gettext "# Submodule changes to be committed:"; echo
792                 fi
793                 echo "#"
794                 sed -e 's|^|# |' -e 's|^# $|#|'
795         else
796                 cat
797         fi
798 }
799 #
800 # List all submodules, prefixed with:
801 #  - submodule not initialized
802 #  + different revision checked out
803 #
804 # If --cached was specified the revision in the index will be printed
805 # instead of the currently checked out revision.
806 #
807 # $@ = requested paths (default to all)
808 #
809 cmd_status()
810 {
811         # parse $args after "submodule ... status".
812         orig_flags=
813         while test $# -ne 0
814         do
815                 case "$1" in
816                 -q|--quiet)
817                         GIT_QUIET=1
818                         ;;
819                 --cached)
820                         cached=1
821                         ;;
822                 --recursive)
823                         recursive=1
824                         ;;
825                 --)
826                         shift
827                         break
828                         ;;
829                 -*)
830                         usage
831                         ;;
832                 *)
833                         break
834                         ;;
835                 esac
836                 orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
837                 shift
838         done
839
840         module_list "$@" |
841         while read mode sha1 stage path
842         do
843                 name=$(module_name "$path") || exit
844                 url=$(git config submodule."$name".url)
845                 displaypath="$prefix$path"
846                 if test "$stage" = U
847                 then
848                         say "U$sha1 $displaypath"
849                         continue
850                 fi
851                 if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
852                 then
853                         say "-$sha1 $displaypath"
854                         continue;
855                 fi
856                 set_name_rev "$path" "$sha1"
857                 if git diff-files --ignore-submodules=dirty --quiet -- "$path"
858                 then
859                         say " $sha1 $displaypath$revname"
860                 else
861                         if test -z "$cached"
862                         then
863                                 sha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD)
864                                 set_name_rev "$path" "$sha1"
865                         fi
866                         say "+$sha1 $displaypath$revname"
867                 fi
868
869                 if test -n "$recursive"
870                 then
871                         (
872                                 prefix="$displaypath/"
873                                 clear_local_git_env
874                                 cd "$path" &&
875                                 eval cmd_status "$orig_args"
876                         ) ||
877                         die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
878                 fi
879         done
880 }
881 #
882 # Sync remote urls for submodules
883 # This makes the value for remote.$remote.url match the value
884 # specified in .gitmodules.
885 #
886 cmd_sync()
887 {
888         while test $# -ne 0
889         do
890                 case "$1" in
891                 -q|--quiet)
892                         GIT_QUIET=1
893                         shift
894                         ;;
895                 --)
896                         shift
897                         break
898                         ;;
899                 -*)
900                         usage
901                         ;;
902                 *)
903                         break
904                         ;;
905                 esac
906         done
907         cd_to_toplevel
908         module_list "$@" |
909         while read mode sha1 stage path
910         do
911                 name=$(module_name "$path")
912                 url=$(git config -f .gitmodules --get submodule."$name".url)
913
914                 # Possibly a url relative to parent
915                 case "$url" in
916                 ./*|../*)
917                         url=$(resolve_relative_url "$url") || exit
918                         ;;
919                 esac
920
921                 if git config "submodule.$name.url" >/dev/null 2>/dev/null
922                 then
923                         say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
924                         git config submodule."$name".url "$url"
925
926                         if test -e "$path"/.git
927                         then
928                         (
929                                 clear_local_git_env
930                                 cd "$path"
931                                 remote=$(get_default_remote)
932                                 git config remote."$remote".url "$url"
933                         )
934                         fi
935                 fi
936         done
937 }
938
939 # This loop parses the command line arguments to find the
940 # subcommand name to dispatch.  Parsing of the subcommand specific
941 # options are primarily done by the subcommand implementations.
942 # Subcommand specific options such as --branch and --cached are
943 # parsed here as well, for backward compatibility.
944
945 while test $# != 0 && test -z "$command"
946 do
947         case "$1" in
948         add | foreach | init | update | status | summary | sync)
949                 command=$1
950                 ;;
951         -q|--quiet)
952                 GIT_QUIET=1
953                 ;;
954         -b|--branch)
955                 case "$2" in
956                 '')
957                         usage
958                         ;;
959                 esac
960                 branch="$2"; shift
961                 ;;
962         --cached)
963                 cached="$1"
964                 ;;
965         --)
966                 break
967                 ;;
968         -*)
969                 usage
970                 ;;
971         *)
972                 break
973                 ;;
974         esac
975         shift
976 done
977
978 # No command word defaults to "status"
979 test -n "$command" || command=status
980
981 # "-b branch" is accepted only by "add"
982 if test -n "$branch" && test "$command" != add
983 then
984         usage
985 fi
986
987 # "--cached" is accepted only by "status" and "summary"
988 if test -n "$cached" && test "$command" != status -a "$command" != summary
989 then
990         usage
991 fi
992
993 "cmd_$command" "$@"