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