]>
Commit | Line | Data |
---|---|---|
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] [--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 | |
26 | ||
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 | |
31 | ||
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= | |
53 | ||
54 | die_if_unmatched () | |
55 | { | |
56 | if test "$1" = "#unmatched" | |
57 | then | |
58 | exit ${2:-1} | |
59 | fi | |
60 | } | |
61 | ||
62 | isnumber() | |
63 | { | |
64 | n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1" | |
65 | } | |
66 | ||
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() | |
71 | { | |
72 | save_config=$GIT_CONFIG_PARAMETERS | |
73 | clear_local_git_env | |
74 | GIT_CONFIG_PARAMETERS=$save_config | |
75 | export GIT_CONFIG_PARAMETERS | |
76 | } | |
77 | ||
78 | # | |
79 | # Add a new submodule to the working tree, .gitmodules and the index | |
80 | # | |
81 | # $@ = repo path | |
82 | # | |
83 | # optional branch is stored in global branch variable | |
84 | # | |
85 | cmd_add() | |
86 | { | |
87 | # parse $args after "submodule ... add". | |
88 | reference_path= | |
89 | while test $# -ne 0 | |
90 | do | |
91 | case "$1" in | |
92 | -b | --branch) | |
93 | case "$2" in '') usage ;; esac | |
94 | branch=$2 | |
95 | shift | |
96 | ;; | |
97 | -f | --force) | |
98 | force=$1 | |
99 | ;; | |
100 | -q|--quiet) | |
101 | GIT_QUIET=1 | |
102 | ;; | |
103 | --progress) | |
104 | progress=1 | |
105 | ;; | |
106 | --reference) | |
107 | case "$2" in '') usage ;; esac | |
108 | reference_path=$2 | |
109 | shift | |
110 | ;; | |
111 | --reference=*) | |
112 | reference_path="${1#--reference=}" | |
113 | ;; | |
114 | --dissociate) | |
115 | dissociate=1 | |
116 | ;; | |
117 | --name) | |
118 | case "$2" in '') usage ;; esac | |
119 | custom_name=$2 | |
120 | shift | |
121 | ;; | |
122 | --depth) | |
123 | case "$2" in '') usage ;; esac | |
124 | depth="--depth=$2" | |
125 | shift | |
126 | ;; | |
127 | --depth=*) | |
128 | depth=$1 | |
129 | ;; | |
130 | --) | |
131 | shift | |
132 | break | |
133 | ;; | |
134 | -*) | |
135 | usage | |
136 | ;; | |
137 | *) | |
138 | break | |
139 | ;; | |
140 | esac | |
141 | shift | |
142 | done | |
143 | ||
144 | if test -z "$1" | |
145 | then | |
146 | usage | |
147 | fi | |
148 | ||
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"} -- "$@" | |
150 | } | |
151 | ||
152 | # | |
153 | # Execute an arbitrary command sequence in each checked out | |
154 | # submodule | |
155 | # | |
156 | # $@ = command to execute | |
157 | # | |
158 | cmd_foreach() | |
159 | { | |
160 | # parse $args after "submodule ... foreach". | |
161 | while test $# -ne 0 | |
162 | do | |
163 | case "$1" in | |
164 | -q|--quiet) | |
165 | GIT_QUIET=1 | |
166 | ;; | |
167 | --recursive) | |
168 | recursive=1 | |
169 | ;; | |
170 | -*) | |
171 | usage | |
172 | ;; | |
173 | *) | |
174 | break | |
175 | ;; | |
176 | esac | |
177 | shift | |
178 | done | |
179 | ||
180 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} -- "$@" | |
181 | } | |
182 | ||
183 | # | |
184 | # Register submodules in .git/config | |
185 | # | |
186 | # $@ = requested paths (default to all) | |
187 | # | |
188 | cmd_init() | |
189 | { | |
190 | # parse $args after "submodule ... init". | |
191 | while test $# -ne 0 | |
192 | do | |
193 | case "$1" in | |
194 | -q|--quiet) | |
195 | GIT_QUIET=1 | |
196 | ;; | |
197 | --) | |
198 | shift | |
199 | break | |
200 | ;; | |
201 | -*) | |
202 | usage | |
203 | ;; | |
204 | *) | |
205 | break | |
206 | ;; | |
207 | esac | |
208 | shift | |
209 | done | |
210 | ||
211 | git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper init ${GIT_QUIET:+--quiet} -- "$@" | |
212 | } | |
213 | ||
214 | # | |
215 | # Unregister submodules from .git/config and remove their work tree | |
216 | # | |
217 | cmd_deinit() | |
218 | { | |
219 | # parse $args after "submodule ... deinit". | |
220 | deinit_all= | |
221 | while test $# -ne 0 | |
222 | do | |
223 | case "$1" in | |
224 | -f|--force) | |
225 | force=$1 | |
226 | ;; | |
227 | -q|--quiet) | |
228 | GIT_QUIET=1 | |
229 | ;; | |
230 | --all) | |
231 | deinit_all=t | |
232 | ;; | |
233 | --) | |
234 | shift | |
235 | break | |
236 | ;; | |
237 | -*) | |
238 | usage | |
239 | ;; | |
240 | *) | |
241 | break | |
242 | ;; | |
243 | esac | |
244 | shift | |
245 | done | |
246 | ||
247 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@" | |
248 | } | |
249 | ||
250 | # | |
251 | # Update each submodule path to correct revision, using clone and checkout as needed | |
252 | # | |
253 | # $@ = requested paths (default to all) | |
254 | # | |
255 | cmd_update() | |
256 | { | |
257 | # parse $args after "submodule ... update". | |
258 | while test $# -ne 0 | |
259 | do | |
260 | case "$1" in | |
261 | -q|--quiet) | |
262 | GIT_QUIET=1 | |
263 | ;; | |
264 | -v) | |
265 | unset GIT_QUIET | |
266 | ;; | |
267 | --progress) | |
268 | progress=1 | |
269 | ;; | |
270 | -i|--init) | |
271 | init=1 | |
272 | ;; | |
273 | --require-init) | |
274 | init=1 | |
275 | require_init=1 | |
276 | ;; | |
277 | --remote) | |
278 | remote=1 | |
279 | ;; | |
280 | -N|--no-fetch) | |
281 | nofetch=1 | |
282 | ;; | |
283 | -f|--force) | |
284 | force=$1 | |
285 | ;; | |
286 | -r|--rebase) | |
287 | update="rebase" | |
288 | ;; | |
289 | --reference) | |
290 | case "$2" in '') usage ;; esac | |
291 | reference="--reference=$2" | |
292 | shift | |
293 | ;; | |
294 | --reference=*) | |
295 | reference="$1" | |
296 | ;; | |
297 | --dissociate) | |
298 | dissociate=1 | |
299 | ;; | |
300 | -m|--merge) | |
301 | update="merge" | |
302 | ;; | |
303 | --recursive) | |
304 | recursive=1 | |
305 | ;; | |
306 | --checkout) | |
307 | update="checkout" | |
308 | ;; | |
309 | --recommend-shallow) | |
310 | recommend_shallow="--recommend-shallow" | |
311 | ;; | |
312 | --no-recommend-shallow) | |
313 | recommend_shallow="--no-recommend-shallow" | |
314 | ;; | |
315 | --depth) | |
316 | case "$2" in '') usage ;; esac | |
317 | depth="--depth=$2" | |
318 | shift | |
319 | ;; | |
320 | --depth=*) | |
321 | depth=$1 | |
322 | ;; | |
323 | -j|--jobs) | |
324 | case "$2" in '') usage ;; esac | |
325 | jobs="--jobs=$2" | |
326 | shift | |
327 | ;; | |
328 | --jobs=*) | |
329 | jobs=$1 | |
330 | ;; | |
331 | --single-branch) | |
332 | single_branch="--single-branch" | |
333 | ;; | |
334 | --no-single-branch) | |
335 | single_branch="--no-single-branch" | |
336 | ;; | |
337 | --filter) | |
338 | case "$2" in '') usage ;; esac | |
339 | filter="--filter=$2" | |
340 | shift | |
341 | ;; | |
342 | --filter=*) | |
343 | filter="$1" | |
344 | ;; | |
345 | --) | |
346 | shift | |
347 | break | |
348 | ;; | |
349 | -*) | |
350 | usage | |
351 | ;; | |
352 | *) | |
353 | break | |
354 | ;; | |
355 | esac | |
356 | shift | |
357 | done | |
358 | ||
359 | { | |
360 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \ | |
361 | ${GIT_QUIET:+--quiet} \ | |
362 | ${progress:+"--progress"} \ | |
363 | ${init:+--init} \ | |
364 | ${wt_prefix:+--prefix "$wt_prefix"} \ | |
365 | ${prefix:+--recursive-prefix "$prefix"} \ | |
366 | ${update:+--update "$update"} \ | |
367 | ${reference:+"$reference"} \ | |
368 | ${dissociate:+"--dissociate"} \ | |
369 | ${depth:+--depth "$depth"} \ | |
370 | ${require_init:+--require-init} \ | |
371 | $single_branch \ | |
372 | $recommend_shallow \ | |
373 | $jobs \ | |
374 | $filter \ | |
375 | -- \ | |
376 | "$@" || echo "#unmatched" $? | |
377 | } | { | |
378 | err= | |
379 | while read -r quickabort sha1 just_cloned sm_path | |
380 | do | |
381 | die_if_unmatched "$quickabort" "$sha1" | |
382 | ||
383 | displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix") | |
384 | ||
385 | if test $just_cloned -eq 0 | |
386 | then | |
387 | just_cloned= | |
388 | fi | |
389 | ||
390 | out=$(git submodule--helper run-update-procedure \ | |
391 | ${wt_prefix:+--prefix "$wt_prefix"} \ | |
392 | ${GIT_QUIET:+--quiet} \ | |
393 | ${force:+--force} \ | |
394 | ${just_cloned:+--just-cloned} \ | |
395 | ${nofetch:+--no-fetch} \ | |
396 | ${depth:+"$depth"} \ | |
397 | ${update:+--update "$update"} \ | |
398 | ${prefix:+--recursive-prefix "$prefix"} \ | |
399 | ${sha1:+--oid "$sha1"} \ | |
400 | ${remote:+--remote} \ | |
401 | "--" \ | |
402 | "$sm_path") | |
403 | ||
404 | # exit codes for run-update-procedure: | |
405 | # 0: update was successful, say command output | |
406 | # 1: update procedure failed, but should not die | |
407 | # 2 or 128: subcommand died during execution | |
408 | # 3: no update procedure was run | |
409 | res="$?" | |
410 | case $res in | |
411 | 0) | |
412 | say "$out" | |
413 | ;; | |
414 | 1) | |
415 | err="${err};fatal: $out" | |
416 | continue | |
417 | ;; | |
418 | 2|128) | |
419 | die_with_status $res "fatal: $out" | |
420 | ;; | |
421 | esac | |
422 | ||
423 | if test -n "$recursive" | |
424 | then | |
425 | ( | |
426 | prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix") | |
427 | wt_prefix= | |
428 | sanitize_submodule_env | |
429 | cd "$sm_path" && | |
430 | eval cmd_update | |
431 | ) | |
432 | res=$? | |
433 | if test $res -gt 0 | |
434 | then | |
435 | die_msg="fatal: $(eval_gettext "Failed to recurse into submodule path '\$displaypath'")" | |
436 | if test $res -ne 2 | |
437 | then | |
438 | err="${err};$die_msg" | |
439 | continue | |
440 | else | |
441 | die_with_status $res "$die_msg" | |
442 | fi | |
443 | fi | |
444 | fi | |
445 | done | |
446 | ||
447 | if test -n "$err" | |
448 | then | |
449 | OIFS=$IFS | |
450 | IFS=';' | |
451 | for e in $err | |
452 | do | |
453 | if test -n "$e" | |
454 | then | |
455 | echo >&2 "$e" | |
456 | fi | |
457 | done | |
458 | IFS=$OIFS | |
459 | exit 1 | |
460 | fi | |
461 | } | |
462 | } | |
463 | ||
464 | # | |
465 | # Configures a submodule's default branch | |
466 | # | |
467 | # $@ = requested path | |
468 | # | |
469 | cmd_set_branch() { | |
470 | default= | |
471 | branch= | |
472 | ||
473 | while test $# -ne 0 | |
474 | do | |
475 | case "$1" in | |
476 | -q|--quiet) | |
477 | # we don't do anything with this but we need to accept it | |
478 | ;; | |
479 | -d|--default) | |
480 | default=1 | |
481 | ;; | |
482 | -b|--branch) | |
483 | case "$2" in '') usage ;; esac | |
484 | branch=$2 | |
485 | shift | |
486 | ;; | |
487 | --) | |
488 | shift | |
489 | break | |
490 | ;; | |
491 | -*) | |
492 | usage | |
493 | ;; | |
494 | *) | |
495 | break | |
496 | ;; | |
497 | esac | |
498 | shift | |
499 | done | |
500 | ||
501 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${GIT_QUIET:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@" | |
502 | } | |
503 | ||
504 | # | |
505 | # Configures a submodule's remote url | |
506 | # | |
507 | # $@ = requested path, requested url | |
508 | # | |
509 | cmd_set_url() { | |
510 | while test $# -ne 0 | |
511 | do | |
512 | case "$1" in | |
513 | -q|--quiet) | |
514 | GIT_QUIET=1 | |
515 | ;; | |
516 | --) | |
517 | shift | |
518 | break | |
519 | ;; | |
520 | -*) | |
521 | usage | |
522 | ;; | |
523 | *) | |
524 | break | |
525 | ;; | |
526 | esac | |
527 | shift | |
528 | done | |
529 | ||
530 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${GIT_QUIET:+--quiet} -- "$@" | |
531 | } | |
532 | ||
533 | # | |
534 | # Show commit summary for submodules in index or working tree | |
535 | # | |
536 | # If '--cached' is given, show summary between index and given commit, | |
537 | # or between working tree and given commit | |
538 | # | |
539 | # $@ = [commit (default 'HEAD'),] requested paths (default all) | |
540 | # | |
541 | cmd_summary() { | |
542 | summary_limit=-1 | |
543 | for_status= | |
544 | diff_cmd=diff-index | |
545 | ||
546 | # parse $args after "submodule ... summary". | |
547 | while test $# -ne 0 | |
548 | do | |
549 | case "$1" in | |
550 | --cached) | |
551 | cached="$1" | |
552 | ;; | |
553 | --files) | |
554 | files="$1" | |
555 | ;; | |
556 | --for-status) | |
557 | for_status="$1" | |
558 | ;; | |
559 | -n|--summary-limit) | |
560 | summary_limit="$2" | |
561 | isnumber "$summary_limit" || usage | |
562 | shift | |
563 | ;; | |
564 | --summary-limit=*) | |
565 | summary_limit="${1#--summary-limit=}" | |
566 | isnumber "$summary_limit" || usage | |
567 | ;; | |
568 | --) | |
569 | shift | |
570 | break | |
571 | ;; | |
572 | -*) | |
573 | usage | |
574 | ;; | |
575 | *) | |
576 | break | |
577 | ;; | |
578 | esac | |
579 | shift | |
580 | done | |
581 | ||
582 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@" | |
583 | } | |
584 | # | |
585 | # List all submodules, prefixed with: | |
586 | # - submodule not initialized | |
587 | # + different revision checked out | |
588 | # | |
589 | # If --cached was specified the revision in the index will be printed | |
590 | # instead of the currently checked out revision. | |
591 | # | |
592 | # $@ = requested paths (default to all) | |
593 | # | |
594 | cmd_status() | |
595 | { | |
596 | # parse $args after "submodule ... status". | |
597 | while test $# -ne 0 | |
598 | do | |
599 | case "$1" in | |
600 | -q|--quiet) | |
601 | GIT_QUIET=1 | |
602 | ;; | |
603 | --cached) | |
604 | cached=1 | |
605 | ;; | |
606 | --recursive) | |
607 | recursive=1 | |
608 | ;; | |
609 | --) | |
610 | shift | |
611 | break | |
612 | ;; | |
613 | -*) | |
614 | usage | |
615 | ;; | |
616 | *) | |
617 | break | |
618 | ;; | |
619 | esac | |
620 | shift | |
621 | done | |
622 | ||
623 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@" | |
624 | } | |
625 | # | |
626 | # Sync remote urls for submodules | |
627 | # This makes the value for remote.$remote.url match the value | |
628 | # specified in .gitmodules. | |
629 | # | |
630 | cmd_sync() | |
631 | { | |
632 | while test $# -ne 0 | |
633 | do | |
634 | case "$1" in | |
635 | -q|--quiet) | |
636 | GIT_QUIET=1 | |
637 | shift | |
638 | ;; | |
639 | --recursive) | |
640 | recursive=1 | |
641 | shift | |
642 | ;; | |
643 | --) | |
644 | shift | |
645 | break | |
646 | ;; | |
647 | -*) | |
648 | usage | |
649 | ;; | |
650 | *) | |
651 | break | |
652 | ;; | |
653 | esac | |
654 | done | |
655 | ||
656 | git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} -- "$@" | |
657 | } | |
658 | ||
659 | cmd_absorbgitdirs() | |
660 | { | |
661 | git submodule--helper absorb-git-dirs --prefix "$wt_prefix" "$@" | |
662 | } | |
663 | ||
664 | # This loop parses the command line arguments to find the | |
665 | # subcommand name to dispatch. Parsing of the subcommand specific | |
666 | # options are primarily done by the subcommand implementations. | |
667 | # Subcommand specific options such as --branch and --cached are | |
668 | # parsed here as well, for backward compatibility. | |
669 | ||
670 | while test $# != 0 && test -z "$command" | |
671 | do | |
672 | case "$1" in | |
673 | add | foreach | init | deinit | update | set-branch | set-url | status | summary | sync | absorbgitdirs) | |
674 | command=$1 | |
675 | ;; | |
676 | -q|--quiet) | |
677 | GIT_QUIET=1 | |
678 | ;; | |
679 | -b|--branch) | |
680 | case "$2" in | |
681 | '') | |
682 | usage | |
683 | ;; | |
684 | esac | |
685 | branch="$2"; shift | |
686 | ;; | |
687 | --cached) | |
688 | cached="$1" | |
689 | ;; | |
690 | --) | |
691 | break | |
692 | ;; | |
693 | -*) | |
694 | usage | |
695 | ;; | |
696 | *) | |
697 | break | |
698 | ;; | |
699 | esac | |
700 | shift | |
701 | done | |
702 | ||
703 | # No command word defaults to "status" | |
704 | if test -z "$command" | |
705 | then | |
706 | if test $# = 0 | |
707 | then | |
708 | command=status | |
709 | else | |
710 | usage | |
711 | fi | |
712 | fi | |
713 | ||
714 | # "-b branch" is accepted only by "add" and "set-branch" | |
715 | if test -n "$branch" && (test "$command" != add || test "$command" != set-branch) | |
716 | then | |
717 | usage | |
718 | fi | |
719 | ||
720 | # "--cached" is accepted only by "status" and "summary" | |
721 | if test -n "$cached" && test "$command" != status && test "$command" != summary | |
722 | then | |
723 | usage | |
724 | fi | |
725 | ||
726 | "cmd_$(echo $command | sed -e s/-/_/g)" "$@" |