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