2.36 fast-export regression fix
[alt-git.git] / git-submodule.sh
blob87772ac89174fa7d2d47262f164c2dbc9f854ba7
1 #!/bin/sh
3 # git-submodule.sh: add, init, update or list git submodules
5 # Copyright (c) 2007 Lars Hjemli
7 dashless=$(basename "$0" | sed -e 's/-/ /')
8 USAGE="[--quiet] [--cached]
9 or: $dashless [--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
10 or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
11 or: $dashless [--quiet] init [--] [<path>...]
12 or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)
13 or: $dashless [--quiet] update [--init [--filter=<filter-spec>]] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] [--] [<path>...]
14 or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>
15 or: $dashless [--quiet] set-url [--] <path> <newurl>
16 or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
17 or: $dashless [--quiet] foreach [--recursive] <command>
18 or: $dashless [--quiet] sync [--recursive] [--] [<path>...]
19 or: $dashless [--quiet] absorbgitdirs [--] [<path>...]"
20 OPTIONS_SPEC=
21 SUBDIRECTORY_OK=Yes
22 . git-sh-setup
23 require_work_tree
24 wt_prefix=$(git rev-parse --show-prefix)
25 cd_to_toplevel
27 # Tell the rest of git that any URLs we get don't come
28 # directly from the user, so it can apply policy as appropriate.
29 GIT_PROTOCOL_FROM_USER=0
30 export GIT_PROTOCOL_FROM_USER
32 command=
33 branch=
34 force=
35 reference=
36 cached=
37 recursive=
38 init=
39 require_init=
40 files=
41 remote=
42 nofetch=
43 update=
44 prefix=
45 custom_name=
46 depth=
47 progress=
48 dissociate=
49 single_branch=
50 jobs=
51 recommend_shallow=
52 filter=
54 die_if_unmatched ()
56 if test "$1" = "#unmatched"
57 then
58 exit ${2:-1}
62 isnumber()
64 n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
67 # Sanitize the local git environment for use within a submodule. We
68 # can't simply use clear_local_git_env since we want to preserve some
69 # of the settings from GIT_CONFIG_PARAMETERS.
70 sanitize_submodule_env()
72 save_config=$GIT_CONFIG_PARAMETERS
73 clear_local_git_env
74 GIT_CONFIG_PARAMETERS=$save_config
75 export GIT_CONFIG_PARAMETERS
79 # Add a new submodule to the working tree, .gitmodules and the index
81 # $@ = repo path
83 # optional branch is stored in global branch variable
85 cmd_add()
87 # parse $args after "submodule ... add".
88 reference_path=
89 while test $# -ne 0
91 case "$1" in
92 -b | --branch)
93 case "$2" in '') usage ;; esac
94 branch=$2
95 shift
97 -f | --force)
98 force=$1
100 -q|--quiet)
101 GIT_QUIET=1
103 --progress)
104 progress=1
106 --reference)
107 case "$2" in '') usage ;; esac
108 reference_path=$2
109 shift
111 --reference=*)
112 reference_path="${1#--reference=}"
114 --dissociate)
115 dissociate=1
117 --name)
118 case "$2" in '') usage ;; esac
119 custom_name=$2
120 shift
122 --depth)
123 case "$2" in '') usage ;; esac
124 depth="--depth=$2"
125 shift
127 --depth=*)
128 depth=$1
131 shift
132 break
135 usage
138 break
140 esac
141 shift
142 done
144 if test -z "$1"
145 then
146 usage
149 git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper add ${GIT_QUIET:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@"
153 # Execute an arbitrary command sequence in each checked out
154 # submodule
156 # $@ = command to execute
158 cmd_foreach()
160 # parse $args after "submodule ... foreach".
161 while test $# -ne 0
163 case "$1" in
164 -q|--quiet)
165 GIT_QUIET=1
167 --recursive)
168 recursive=1
171 usage
174 break
176 esac
177 shift
178 done
180 git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} -- "$@"
184 # Register submodules in .git/config
186 # $@ = requested paths (default to all)
188 cmd_init()
190 # parse $args after "submodule ... init".
191 while test $# -ne 0
193 case "$1" in
194 -q|--quiet)
195 GIT_QUIET=1
198 shift
199 break
202 usage
205 break
207 esac
208 shift
209 done
211 git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper init ${GIT_QUIET:+--quiet} -- "$@"
215 # Unregister submodules from .git/config and remove their work tree
217 cmd_deinit()
219 # parse $args after "submodule ... deinit".
220 deinit_all=
221 while test $# -ne 0
223 case "$1" in
224 -f|--force)
225 force=$1
227 -q|--quiet)
228 GIT_QUIET=1
230 --all)
231 deinit_all=t
234 shift
235 break
238 usage
241 break
243 esac
244 shift
245 done
247 git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
250 # usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]
251 # Because arguments are positional, use an empty string to omit <depth>
252 # but include <sha1>.
253 fetch_in_submodule () (
254 sanitize_submodule_env &&
255 cd "$1" &&
256 if test $# -eq 3
257 then
258 echo "$3" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+"$2"}
259 else
260 git fetch ${GIT_QUIET:+--quiet} ${2:+"$2"}
265 # Update each submodule path to correct revision, using clone and checkout as needed
267 # $@ = requested paths (default to all)
269 cmd_update()
271 # parse $args after "submodule ... update".
272 while test $# -ne 0
274 case "$1" in
275 -q|--quiet)
276 GIT_QUIET=1
279 unset GIT_QUIET
281 --progress)
282 progress=1
284 -i|--init)
285 init=1
287 --require-init)
288 init=1
289 require_init=1
291 --remote)
292 remote=1
294 -N|--no-fetch)
295 nofetch=1
297 -f|--force)
298 force=$1
300 -r|--rebase)
301 update="rebase"
303 --reference)
304 case "$2" in '') usage ;; esac
305 reference="--reference=$2"
306 shift
308 --reference=*)
309 reference="$1"
311 --dissociate)
312 dissociate=1
314 -m|--merge)
315 update="merge"
317 --recursive)
318 recursive=1
320 --checkout)
321 update="checkout"
323 --recommend-shallow)
324 recommend_shallow="--recommend-shallow"
326 --no-recommend-shallow)
327 recommend_shallow="--no-recommend-shallow"
329 --depth)
330 case "$2" in '') usage ;; esac
331 depth="--depth=$2"
332 shift
334 --depth=*)
335 depth=$1
337 -j|--jobs)
338 case "$2" in '') usage ;; esac
339 jobs="--jobs=$2"
340 shift
342 --jobs=*)
343 jobs=$1
345 --single-branch)
346 single_branch="--single-branch"
348 --no-single-branch)
349 single_branch="--no-single-branch"
351 --filter)
352 case "$2" in '') usage ;; esac
353 filter="--filter=$2"
354 shift
356 --filter=*)
357 filter="$1"
360 shift
361 break
364 usage
367 break
369 esac
370 shift
371 done
373 if test -n "$filter" && test "$init" != "1"
374 then
375 usage
378 if test -n "$init"
379 then
380 cmd_init "--" "$@" || return
384 git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
385 ${progress:+"--progress"} \
386 ${wt_prefix:+--prefix "$wt_prefix"} \
387 ${prefix:+--recursive-prefix "$prefix"} \
388 ${update:+--update "$update"} \
389 ${reference:+"$reference"} \
390 ${dissociate:+"--dissociate"} \
391 ${depth:+--depth "$depth"} \
392 ${require_init:+--require-init} \
393 $single_branch \
394 $recommend_shallow \
395 $jobs \
396 $filter \
397 -- \
398 "$@" || echo "#unmatched" $?
399 } | {
400 err=
401 while read -r quickabort sha1 just_cloned sm_path
403 die_if_unmatched "$quickabort" "$sha1"
405 git submodule--helper ensure-core-worktree "$sm_path" || exit 1
407 displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
409 if test $just_cloned -eq 1
410 then
411 subsha1=
412 else
413 just_cloned=
414 subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
415 git rev-parse --verify HEAD) ||
416 die "fatal: $(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
419 if test -n "$remote"
420 then
421 branch=$(git submodule--helper remote-branch "$sm_path")
422 if test -z "$nofetch"
423 then
424 # Fetch remote before determining tracking $sha1
425 fetch_in_submodule "$sm_path" $depth ||
426 die "fatal: $(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
428 remote_name=$(sanitize_submodule_env; cd "$sm_path" && git submodule--helper print-default-remote)
429 sha1=$(sanitize_submodule_env; cd "$sm_path" &&
430 git rev-parse --verify "${remote_name}/${branch}") ||
431 die "fatal: $(eval_gettext "Unable to find current \${remote_name}/\${branch} revision in submodule path '\$sm_path'")"
434 out=$(git submodule--helper run-update-procedure \
435 ${wt_prefix:+--prefix "$wt_prefix"} \
436 ${GIT_QUIET:+--quiet} \
437 ${force:+--force} \
438 ${just_cloned:+--just-cloned} \
439 ${nofetch:+--no-fetch} \
440 ${depth:+"$depth"} \
441 ${update:+--update "$update"} \
442 ${prefix:+--recursive-prefix "$prefix"} \
443 ${sha1:+--oid "$sha1"} \
444 ${subsha1:+--suboid "$subsha1"} \
445 "--" \
446 "$sm_path")
448 # exit codes for run-update-procedure:
449 # 0: update was successful, say command output
450 # 1: update procedure failed, but should not die
451 # 2 or 128: subcommand died during execution
452 # 3: no update procedure was run
453 res="$?"
454 case $res in
456 say "$out"
459 err="${err};fatal: $out"
460 continue
462 2|128)
463 die_with_status $res "fatal: $out"
465 esac
467 if test -n "$recursive"
468 then
470 prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
471 wt_prefix=
472 sanitize_submodule_env
473 cd "$sm_path" &&
474 eval cmd_update
476 res=$?
477 if test $res -gt 0
478 then
479 die_msg="fatal: $(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
480 if test $res -ne 2
481 then
482 err="${err};$die_msg"
483 continue
484 else
485 die_with_status $res "$die_msg"
489 done
491 if test -n "$err"
492 then
493 OIFS=$IFS
494 IFS=';'
495 for e in $err
497 if test -n "$e"
498 then
499 echo >&2 "$e"
501 done
502 IFS=$OIFS
503 exit 1
509 # Configures a submodule's default branch
511 # $@ = requested path
513 cmd_set_branch() {
514 default=
515 branch=
517 while test $# -ne 0
519 case "$1" in
520 -q|--quiet)
521 # we don't do anything with this but we need to accept it
523 -d|--default)
524 default=1
526 -b|--branch)
527 case "$2" in '') usage ;; esac
528 branch=$2
529 shift
532 shift
533 break
536 usage
539 break
541 esac
542 shift
543 done
545 git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${GIT_QUIET:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@"
549 # Configures a submodule's remote url
551 # $@ = requested path, requested url
553 cmd_set_url() {
554 while test $# -ne 0
556 case "$1" in
557 -q|--quiet)
558 GIT_QUIET=1
561 shift
562 break
565 usage
568 break
570 esac
571 shift
572 done
574 git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${GIT_QUIET:+--quiet} -- "$@"
578 # Show commit summary for submodules in index or working tree
580 # If '--cached' is given, show summary between index and given commit,
581 # or between working tree and given commit
583 # $@ = [commit (default 'HEAD'),] requested paths (default all)
585 cmd_summary() {
586 summary_limit=-1
587 for_status=
588 diff_cmd=diff-index
590 # parse $args after "submodule ... summary".
591 while test $# -ne 0
593 case "$1" in
594 --cached)
595 cached="$1"
597 --files)
598 files="$1"
600 --for-status)
601 for_status="$1"
603 -n|--summary-limit)
604 summary_limit="$2"
605 isnumber "$summary_limit" || usage
606 shift
608 --summary-limit=*)
609 summary_limit="${1#--summary-limit=}"
610 isnumber "$summary_limit" || usage
613 shift
614 break
617 usage
620 break
622 esac
623 shift
624 done
626 git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@"
629 # List all submodules, prefixed with:
630 # - submodule not initialized
631 # + different revision checked out
633 # If --cached was specified the revision in the index will be printed
634 # instead of the currently checked out revision.
636 # $@ = requested paths (default to all)
638 cmd_status()
640 # parse $args after "submodule ... status".
641 while test $# -ne 0
643 case "$1" in
644 -q|--quiet)
645 GIT_QUIET=1
647 --cached)
648 cached=1
650 --recursive)
651 recursive=1
654 shift
655 break
658 usage
661 break
663 esac
664 shift
665 done
667 git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@"
670 # Sync remote urls for submodules
671 # This makes the value for remote.$remote.url match the value
672 # specified in .gitmodules.
674 cmd_sync()
676 while test $# -ne 0
678 case "$1" in
679 -q|--quiet)
680 GIT_QUIET=1
681 shift
683 --recursive)
684 recursive=1
685 shift
688 shift
689 break
692 usage
695 break
697 esac
698 done
700 git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} -- "$@"
703 cmd_absorbgitdirs()
705 git submodule--helper absorb-git-dirs --prefix "$wt_prefix" "$@"
708 # This loop parses the command line arguments to find the
709 # subcommand name to dispatch. Parsing of the subcommand specific
710 # options are primarily done by the subcommand implementations.
711 # Subcommand specific options such as --branch and --cached are
712 # parsed here as well, for backward compatibility.
714 while test $# != 0 && test -z "$command"
716 case "$1" in
717 add | foreach | init | deinit | update | set-branch | set-url | status | summary | sync | absorbgitdirs)
718 command=$1
720 -q|--quiet)
721 GIT_QUIET=1
723 -b|--branch)
724 case "$2" in
726 usage
728 esac
729 branch="$2"; shift
731 --cached)
732 cached="$1"
735 break
738 usage
741 break
743 esac
744 shift
745 done
747 # No command word defaults to "status"
748 if test -z "$command"
749 then
750 if test $# = 0
751 then
752 command=status
753 else
754 usage
758 # "-b branch" is accepted only by "add" and "set-branch"
759 if test -n "$branch" && (test "$command" != add || test "$command" != set-branch)
760 then
761 usage
764 # "--cached" is accepted only by "status" and "summary"
765 if test -n "$cached" && test "$command" != status && test "$command" != summary
766 then
767 usage
770 "cmd_$(echo $command | sed -e s/-/_/g)" "$@"