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