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