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