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