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