1#!/bin/sh 2# 3# git-submodule.sh: add, init, update or list git submodules 4# 5# Copyright (c) 2007 Lars Hjemli 6 7dashless=$(basename "$0" | sed -e 's/-/ /') 8USAGE="[--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>...]" 16OPTIONS_SPEC= 17SUBDIRECTORY_OK=Yes 18. git-sh-setup 19. git-sh-i18n 20. git-parse-remote 21require_work_tree 22wt_prefix=$(git rev-parse --show-prefix) 23cd_to_toplevel 24 25# Restrict ourselves to a vanilla subset of protocols; the URLs 26# we get are under control of a remote repository, and we do not 27# want them kicking off arbitrary git-remote-* programs. 28# 29# If the user has already specified a set of allowed protocols, 30# we assume they know what they're doing and use that instead. 31:${GIT_ALLOW_PROTOCOL=file:git:http:https:ssh} 32export GIT_ALLOW_PROTOCOL 33 34command= 35branch= 36force= 37reference= 38cached= 39recursive= 40init= 41files= 42remote= 43nofetch= 44update= 45prefix= 46custom_name= 47depth= 48 49# The function takes at most 2 arguments. The first argument is the 50# URL that navigates to the submodule origin repo. When relative, this URL 51# is relative to the superproject origin URL repo. The second up_path 52# argument, if specified, is the relative path that navigates 53# from the submodule working tree to the superproject working tree. 54# 55# The output of the function is the origin URL of the submodule. 56# 57# The output will either be an absolute URL or filesystem path (if the 58# superproject origin URL is an absolute URL or filesystem path, 59# respectively) or a relative file system path (if the superproject 60# origin URL is a relative file system path). 61# 62# When the output is a relative file system path, the path is either 63# relative to the submodule working tree, if up_path is specified, or to 64# the superproject working tree otherwise. 65resolve_relative_url () 66{ 67 remote=$(get_default_remote) 68 remoteurl=$(git config "remote.$remote.url")|| 69 remoteurl=$(pwd)# the repository is its own authoritative upstream 70 url="$1" 71 remoteurl=${remoteurl%/} 72 sep=/ 73 up_path="$2" 74 75case"$remoteurl"in 76*:*|/*) 77 is_relative= 78;; 79 ./*|../*) 80 is_relative=t 81;; 82*) 83 is_relative=t 84 remoteurl="./$remoteurl" 85;; 86esac 87 88whiletest -n"$url" 89do 90case"$url"in 91 ../*) 92 url="${url#../}" 93case"$remoteurl"in 94*/*) 95 remoteurl="${remoteurl%/*}" 96;; 97*:*) 98 remoteurl="${remoteurl%:*}" 99 sep=: 100;; 101*) 102iftest -z"$is_relative"||test"."="$remoteurl" 103then 104 die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")" 105else 106 remoteurl=. 107fi 108;; 109esac 110;; 111 ./*) 112 url="${url#./}" 113;; 114*) 115break;; 116esac 117done 118 remoteurl="$remoteurl$sep${url%/}" 119echo"${is_relative:+${up_path}}${remoteurl#./}" 120} 121 122# Resolve a path to be relative to another path. This is intended for 123# converting submodule paths when git-submodule is run in a subdirectory 124# and only handles paths where the directory separator is '/'. 125# 126# The output is the first argument as a path relative to the second argument, 127# which defaults to $wt_prefix if it is omitted. 128relative_path () 129{ 130local target curdir result 131 target=$1 132 curdir=${2-$wt_prefix} 133 curdir=${curdir%/} 134 result= 135 136whiletest -n"$curdir" 137do 138case"$target"in 139"$curdir/"*) 140 target=${target#"$curdir"/} 141break 142;; 143esac 144 145 result="${result}../" 146iftest"$curdir"="${curdir%/*}" 147then 148 curdir= 149else 150 curdir="${curdir%/*}" 151fi 152done 153 154echo"$result$target" 155} 156 157die_if_unmatched () 158{ 159iftest"$1"="#unmatched" 160then 161exit1 162fi 163} 164 165# 166# Print a submodule configuration setting 167# 168# $1 = submodule name 169# $2 = option name 170# $3 = default value 171# 172# Checks in the usual git-config places first (for overrides), 173# otherwise it falls back on .gitmodules. This allows you to 174# distribute project-wide defaults in .gitmodules, while still 175# customizing individual repositories if necessary. If the option is 176# not in .gitmodules either, print a default value. 177# 178get_submodule_config () { 179 name="$1" 180 option="$2" 181 default="$3" 182 value=$(git config submodule."$name"."$option") 183iftest -z"$value" 184then 185 value=$(git config -f .gitmodules submodule."$name"."$option") 186fi 187printf'%s'"${value:-$default}" 188} 189 190isnumber() 191{ 192 n=$(($1 + 0))2>/dev/null &&test"$n"="$1" 193} 194 195# Sanitize the local git environment for use within a submodule. We 196# can't simply use clear_local_git_env since we want to preserve some 197# of the settings from GIT_CONFIG_PARAMETERS. 198sanitize_submodule_env() 199{ 200 save_config=$GIT_CONFIG_PARAMETERS 201 clear_local_git_env 202 GIT_CONFIG_PARAMETERS=$save_config 203export GIT_CONFIG_PARAMETERS 204} 205 206# 207# Add a new submodule to the working tree, .gitmodules and the index 208# 209# $@ = repo path 210# 211# optional branch is stored in global branch variable 212# 213cmd_add() 214{ 215# parse $args after "submodule ... add". 216 reference_path= 217whiletest$#-ne0 218do 219case"$1"in 220-b|--branch) 221case"$2"in'') usage ;;esac 222 branch=$2 223shift 224;; 225-f|--force) 226 force=$1 227;; 228-q|--quiet) 229 GIT_QUIET=1 230;; 231--reference) 232case"$2"in'') usage ;;esac 233 reference_path=$2 234shift 235;; 236--reference=*) 237 reference_path="${1#--reference=}" 238;; 239--name) 240case"$2"in'') usage ;;esac 241 custom_name=$2 242shift 243;; 244--depth) 245case"$2"in'') usage ;;esac 246 depth="--depth=$2" 247shift 248;; 249--depth=*) 250 depth=$1 251;; 252--) 253shift 254break 255;; 256-*) 257 usage 258;; 259*) 260break 261;; 262esac 263shift 264done 265 266iftest -n"$reference_path" 267then 268 is_absolute_path "$reference_path"|| 269 reference_path="$wt_prefix$reference_path" 270 271 reference="--reference=$reference_path" 272fi 273 274 repo=$1 275 sm_path=$2 276 277iftest -z"$sm_path";then 278 sm_path=$(printf'%s\n'"$repo"| 279sed-e's|/$||'-e's|:*/*\.git$||'-e's|.*[/:]||g') 280fi 281 282iftest -z"$repo"||test -z"$sm_path";then 283 usage 284fi 285 286 is_absolute_path "$sm_path"|| sm_path="$wt_prefix$sm_path" 287 288# assure repo is absolute or relative to parent 289case"$repo"in 290 ./*|../*) 291test -z"$wt_prefix"|| 292 die "$(gettext "Relative path can only be used from the toplevel of the working tree")" 293 294# dereference source url relative to parent's url 295 realrepo=$(resolve_relative_url "$repo")||exit 296;; 297*:*|/*) 298# absolute url 299 realrepo=$repo 300;; 301*) 302 die "$(eval_gettext "repo URL: '\$repo' must be absolute or begin with ./|../")" 303;; 304esac 305 306# normalize path: 307# multiple //; leading ./; /./; /../; trailing / 308 sm_path=$(printf'%s/\n'"$sm_path"| 309sed-e' 310 s|//*|/|g 311 s|^\(\./\)*|| 312 s|/\(\./\)*|/|g 313 :start 314 s|\([^/]*\)/\.\./|| 315 tstart 316 s|/*$|| 317 ') 318 git ls-files --error-unmatch"$sm_path"> /dev/null 2>&1&& 319 die "$(eval_gettext "'\$sm_path' already exists in the index")" 320 321iftest -z"$force"&& ! git add --dry-run --ignore-missing"$sm_path"> /dev/null 2>&1 322then 323 eval_gettextln "The following path is ignored by one of your .gitignore files: 324\$sm_path 325Use -f if you really want to add it.">&2 326exit1 327fi 328 329iftest -n"$custom_name" 330then 331 sm_name="$custom_name" 332else 333 sm_name="$sm_path" 334fi 335 336# perhaps the path exists and is already a git repo, else clone it 337iftest -e"$sm_path" 338then 339iftest -d"$sm_path"/.git ||test -f"$sm_path"/.git 340then 341 eval_gettextln "Adding existing repo at '\$sm_path' to the index" 342else 343 die "$(eval_gettext "'\$sm_path' already exists and is not a valid git repo")" 344fi 345 346else 347iftest -d".git/modules/$sm_name" 348then 349iftest -z"$force" 350then 351echo>&2"$(eval_gettext "A git directory for '\$sm_name' is found locally with remote(s):")" 352 GIT_DIR=".git/modules/$sm_name" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,"", -e s,' (fetch)',, >&2 353 echo >&2 "$(eval_gettext "If you want to reuse this local git directory instead of cloning again from")" 354 echo >&2 "$realrepo" 355 echo >&2 "$(eval_gettext "use the '--force' option. If the local git directory is not the correct repo")" 356 die "$(eval_gettext "or you are unsure what this means choose another name with the '--name' option.")" 357 else 358 echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")" 359 fi 360 fi 361 git submodule--helper clone${GIT_QUIET:+--quiet}--prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo"${reference:+"$reference"}${depth:+"$depth"}|| exit 362 ( 363 sanitize_submodule_env 364 cd "$sm_path" && 365 # ash fails to wordsplit${branch:+-b "$branch"...} 366 case "$branch" in 367 '') git checkout -f -q ;; 368 ?*) git checkout -f -q -B "$branch" "origin/$branch" ;; 369 esac 370 ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")" 371 fi 372 git config submodule."$sm_name".url "$realrepo" 373 374 git add$force"$sm_path" || 375 die "$(eval_gettext "Failed to add submodule '\$sm_path'")" 376 377 git config -f .gitmodules submodule."$sm_name".path "$sm_path" && 378 git config -f .gitmodules submodule."$sm_name".url "$repo" && 379 if test -n "$branch" 380 then 381 git config -f .gitmodules submodule."$sm_name".branch "$branch" 382 fi && 383 git add --force .gitmodules || 384 die "$(eval_gettext "Failed to register submodule '\$sm_path'")" 385} 386 387# 388# Execute an arbitrary command sequence in each checked out 389# submodule 390# 391# $@ = command to execute 392# 393cmd_foreach() 394{ 395 # parse$argsafter "submodule ... foreach". 396 while test$#-ne 0 397 do 398 case "$1" in 399 -q|--quiet) 400 GIT_QUIET=1 401 ;; 402 --recursive) 403 recursive=1 404 ;; 405 -*) 406 usage 407 ;; 408 *) 409 break 410 ;; 411 esac 412 shift 413 done 414 415 toplevel=$(pwd) 416 417 # dup stdin so that it can be restored when running the external 418 # command in the subshell (and a recursive call to this function) 419 exec 3<&0 420 421 git submodule--helper list --prefix "$wt_prefix"| 422 while read mode sha1 stage sm_path 423 do 424 die_if_unmatched "$mode" 425 if test -e "$sm_path"/.git 426 then 427 displaypath=$(relative_path "$sm_path") 428 say "$(eval_gettext "Entering '\$prefix\$displaypath'")" 429 name=$(git submodule--helper name "$sm_path") 430 ( 431 prefix="$prefix$sm_path/" 432 sanitize_submodule_env 433 cd "$sm_path" && 434 sm_path=$(relative_path "$sm_path")&& 435 # we make$pathavailable to scripts ... 436 path=$sm_path&& 437 if test$#-eq 1 438 then 439 eval "$1" 440 else 441 "$@" 442 fi && 443 if test -n "$recursive" 444 then 445 cmd_foreach "--recursive" "$@" 446 fi 447 ) <&3 3<&- || 448 die "$(eval_gettext "Stopping at '\$prefix\$displaypath'; script returned non-zero status.")" 449 fi 450 done 451} 452 453# 454# Register submodules in .git/config 455# 456# $@ = requested paths (default to all) 457# 458cmd_init() 459{ 460 # parse$argsafter "submodule ... init". 461 while test$#-ne 0 462 do 463 case "$1" in 464 -q|--quiet) 465 GIT_QUIET=1 466 ;; 467 --) 468 shift 469 break 470 ;; 471 -*) 472 usage 473 ;; 474 *) 475 break 476 ;; 477 esac 478 shift 479 done 480 481 git submodule--helper list --prefix "$wt_prefix" "$@" | 482 while read mode sha1 stage sm_path 483 do 484 die_if_unmatched "$mode" 485 name=$(git submodule--helper name "$sm_path")|| exit 486 487 displaypath=$(relative_path "$sm_path") 488 489 # Copy url setting when it is not set yet 490 if test -z "$(git config "submodule.$name.url")" 491 then 492 url=$(git config -f .gitmodules submodule."$name".url) 493 test -z "$url" && 494 die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")" 495 496 # Possibly a url relative to parent 497 case "$url" in 498 ./*|../*) 499 url=$(resolve_relative_url "$url")|| exit 500 ;; 501 esac 502 git config submodule."$name".url "$url" || 503 die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")" 504 505 say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")" 506fi 507 508# Copy "update" setting when it is not set yet 509if upd="$(git config -f .gitmodules submodule."$name".update)"&& 510test -n"$upd"&& 511test -z"$(git config submodule."$name".update)" 512then 513case"$upd"in 514 checkout | rebase | merge | none) 515;;# known modes of updating 516*) 517echo>&2"warning: unknown update mode '$upd' suggested for submodule '$name'" 518 upd=none 519;; 520esac 521 git config submodule."$name".update "$upd"|| 522 die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")" 523fi 524done 525} 526 527# 528# Unregister submodules from .git/config and remove their work tree 529# 530# $@ = requested paths (use '.' to deinit all submodules) 531# 532cmd_deinit() 533{ 534# parse $args after "submodule ... deinit". 535whiletest$#-ne0 536do 537case"$1"in 538-f|--force) 539 force=$1 540;; 541-q|--quiet) 542 GIT_QUIET=1 543;; 544--) 545shift 546break 547;; 548-*) 549 usage 550;; 551*) 552break 553;; 554esac 555shift 556done 557 558iftest$#=0 559then 560 die "$(eval_gettext "Use '.' if you really want to deinitialize all submodules")" 561fi 562 563 git submodule--helper list --prefix"$wt_prefix""$@"| 564whileread mode sha1 stage sm_path 565do 566 die_if_unmatched "$mode" 567 name=$(git submodule--helper name "$sm_path")||exit 568 569 displaypath=$(relative_path "$sm_path") 570 571# Remove the submodule work tree (unless the user already did it) 572iftest -d"$sm_path" 573then 574# Protect submodules containing a .git directory 575iftest -d"$sm_path/.git" 576then 577echo>&2"$(eval_gettext "Submodule work tree '\$displaypath' contains a .git directory")" 578 die "$(eval_gettext "(use 'rm -rf' if you really want to remove it including all of its history)")" 579 fi 580 581 if test -z "$force" 582 then 583 git rm -qn "$sm_path" || 584 die "$(eval_gettext "Submodule work tree '\$displaypath' contains local modifications; use '-f' to discard them")" 585 fi 586 rm -rf "$sm_path" && 587 say "$(eval_gettext "Cleared directory '\$displaypath'")" || 588 say "$(eval_gettext "Could not remove submodule work tree '\$displaypath'")" 589 fi 590 591 mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$displaypath'")" 592 593 # Remove the .git/config entries (unless the user already did it) 594 if test -n "$(git config --get-regexp submodule."$name\.")" 595 then 596 # Remove the whole section so we have a clean state when 597 # the user later decides to init this submodule again 598 url=$(git config submodule."$name".url) 599 git config --remove-section submodule."$name" 2>/dev/null && 600 say "$(eval_gettext "Submodule '\$name' (\$url) unregistered for path '\$displaypath'")" 601fi 602done 603} 604 605is_tip_reachable () ( 606 sanitize_submodule_env && 607cd"$1"&& 608rev=$(git rev-list -n 1 "$2" --not --all 2>/dev/null)&& 609test -z"$rev" 610) 611 612fetch_in_submodule () ( 613 sanitize_submodule_env && 614cd"$1"&& 615case"$2"in 616'') 617 git fetch ;; 618*) 619 git fetch $(get_default_remote)"$2";; 620esac 621) 622 623# 624# Update each submodule path to correct revision, using clone and checkout as needed 625# 626# $@ = requested paths (default to all) 627# 628cmd_update() 629{ 630# parse $args after "submodule ... update". 631whiletest$#-ne0 632do 633case"$1"in 634-q|--quiet) 635 GIT_QUIET=1 636;; 637-i|--init) 638 init=1 639;; 640--remote) 641 remote=1 642;; 643-N|--no-fetch) 644 nofetch=1 645;; 646-f|--force) 647 force=$1 648;; 649-r|--rebase) 650 update="rebase" 651;; 652--reference) 653case"$2"in'') usage ;;esac 654 reference="--reference=$2" 655shift 656;; 657--reference=*) 658 reference="$1" 659;; 660-m|--merge) 661 update="merge" 662;; 663--recursive) 664 recursive=1 665;; 666--checkout) 667 update="checkout" 668;; 669--depth) 670case"$2"in'') usage ;;esac 671 depth="--depth=$2" 672shift 673;; 674--depth=*) 675 depth=$1 676;; 677--) 678shift 679break 680;; 681-*) 682 usage 683;; 684*) 685break 686;; 687esac 688shift 689done 690 691iftest -n"$init" 692then 693 cmd_init "--""$@"||return 694fi 695 696 cloned_modules= 697 git submodule--helper list --prefix"$wt_prefix""$@"| { 698 err= 699whileread mode sha1 stage sm_path 700do 701 die_if_unmatched "$mode" 702iftest"$stage"= U 703then 704echo>&2"Skipping unmerged submodule$prefix$sm_path" 705continue 706fi 707 name=$(git submodule--helper name "$sm_path")||exit 708 url=$(git config submodule."$name".url) 709 branch=$(get_submodule_config "$name" branch master) 710if!test -z"$update" 711then 712 update_module=$update 713else 714 update_module=$(git config submodule."$name".update) 715iftest -z"$update_module" 716then 717 update_module="checkout" 718fi 719fi 720 721 displaypath=$(relative_path "$prefix$sm_path") 722 723iftest"$update_module"="none" 724then 725echo"Skipping submodule '$displaypath'" 726continue 727fi 728 729iftest -z"$url" 730then 731# Only mention uninitialized submodules when its 732# path have been specified 733test"$#"!="0"&& 734 say "$(eval_gettext "Submodule path '\$displaypath' not initialized 735Maybe you want to use 'update --init'?")" 736continue 737fi 738 739if!test -d"$sm_path"/.git && !test -f"$sm_path"/.git 740then 741 git submodule--helper clone ${GIT_QUIET:+--quiet}--prefix"$prefix"--path"$sm_path"--name"$name"--url"$url"${reference:+"$reference"} ${depth:+"$depth"}||exit 742 cloned_modules="$cloned_modules;$name" 743 subsha1= 744else 745 subsha1=$(sanitize_submodule_env;cd"$sm_path"&& 746 git rev-parse --verify HEAD) || 747 die "$(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")" 748fi 749 750iftest -n"$remote" 751then 752iftest -z"$nofetch" 753then 754# Fetch remote before determining tracking $sha1 755(sanitize_submodule_env;cd"$sm_path"&& git-fetch) || 756 die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")" 757fi 758 remote_name=$(sanitize_submodule_env; cd "$sm_path" && get_default_remote) 759 sha1=$(sanitize_submodule_env;cd"$sm_path"&& 760 git rev-parse --verify"${remote_name}/${branch}") || 761 die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")" 762fi 763 764iftest"$subsha1"!="$sha1"||test -n"$force" 765then 766 subforce=$force 767# If we don't already have a -f flag and the submodule has never been checked out 768iftest -z"$subsha1"&&test -z"$force" 769then 770 subforce="-f" 771fi 772 773iftest -z"$nofetch" 774then 775# Run fetch only if $sha1 isn't present or it 776# is not reachable from a ref. 777 is_tip_reachable "$sm_path""$sha1"|| 778 fetch_in_submodule "$sm_path"|| 779 die "$(eval_gettext "Unable to fetch in submodule path '\$displaypath'")" 780 781# Now we tried the usual fetch, but $sha1 may 782# not be reachable from any of the refs 783 is_tip_reachable "$sm_path""$sha1"|| 784 fetch_in_submodule "$sm_path""$sha1"|| 785 die "$(eval_gettext "Fetched in submodule path '\$displaypath', but it did not contain $sha1. Direct fetching of that commit failed.")" 786fi 787 788# Is this something we just cloned? 789case";$cloned_modules;"in 790*";$name;"*) 791# then there is no local change to integrate 792 update_module=checkout ;; 793esac 794 795 must_die_on_failure= 796case"$update_module"in 797 checkout) 798command="git checkout$subforce-q" 799 die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")" 800 say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")" 801;; 802 rebase) 803command="git rebase" 804 die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$displaypath'")" 805 say_msg="$(eval_gettext "Submodule path '\$displaypath': rebased into '\$sha1'")" 806 must_die_on_failure=yes 807;; 808 merge) 809command="git merge" 810 die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$displaypath'")" 811 say_msg="$(eval_gettext "Submodule path '\$displaypath': merged in '\$sha1'")" 812 must_die_on_failure=yes 813;; 814!*) 815command="${update_module#!}" 816 die_msg="$(eval_gettext "Execution of '\$command \$sha1' failed in submodule path '\$prefix\$sm_path'")" 817 say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': '\$command \$sha1'")" 818 must_die_on_failure=yes 819;; 820*) 821 die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")" 822esac 823 824if(sanitize_submodule_env;cd"$sm_path"&&$command"$sha1") 825then 826 say "$say_msg" 827eliftest -n"$must_die_on_failure" 828then 829 die_with_status 2"$die_msg" 830else 831 err="${err};$die_msg" 832continue 833fi 834fi 835 836iftest -n"$recursive" 837then 838( 839 prefix="$prefix$sm_path/" 840 sanitize_submodule_env 841cd"$sm_path"&& 842eval cmd_update 843) 844 res=$? 845iftest$res-gt0 846then 847 die_msg="$(eval_gettext "Failed to recurse into submodule path '\$displaypath'")" 848iftest$res-eq1 849then 850 err="${err};$die_msg" 851continue 852else 853 die_with_status $res"$die_msg" 854fi 855fi 856fi 857done 858 859iftest -n"$err" 860then 861 OIFS=$IFS 862 IFS=';' 863for e in$err 864do 865iftest -n"$e" 866then 867echo>&2"$e" 868fi 869done 870 IFS=$OIFS 871exit1 872fi 873} 874} 875 876set_name_rev () { 877 revname=$( ( 878 sanitize_submodule_env 879cd"$1"&& { 880 git describe "$2"2>/dev/null || 881 git describe --tags"$2"2>/dev/null || 882 git describe --contains"$2"2>/dev/null || 883 git describe --all --always"$2" 884} 885) ) 886test -z"$revname"|| revname=" ($revname)" 887} 888# 889# Show commit summary for submodules in index or working tree 890# 891# If '--cached' is given, show summary between index and given commit, 892# or between working tree and given commit 893# 894# $@ = [commit (default 'HEAD'),] requested paths (default all) 895# 896cmd_summary() { 897 summary_limit=-1 898 for_status= 899 diff_cmd=diff-index 900 901# parse $args after "submodule ... summary". 902whiletest$#-ne0 903do 904case"$1"in 905--cached) 906 cached="$1" 907;; 908--files) 909 files="$1" 910;; 911--for-status) 912 for_status="$1" 913;; 914-n|--summary-limit) 915 summary_limit="$2" 916 isnumber "$summary_limit"|| usage 917shift 918;; 919--summary-limit=*) 920 summary_limit="${1#--summary-limit=}" 921 isnumber "$summary_limit"|| usage 922;; 923--) 924shift 925break 926;; 927-*) 928 usage 929;; 930*) 931break 932;; 933esac 934shift 935done 936 937test$summary_limit=0&&return 938 939ifrev=$(git rev-parse -q --verify --default HEAD ${1+"$1"}) 940then 941head=$rev 942test$#=0||shift 943eliftest -z"$1"||test"$1"="HEAD" 944then 945# before the first commit: compare with an empty tree 946head=$(git hash-object -w -t tree --stdin </dev/null) 947test -z"$1"||shift 948else 949head="HEAD" 950fi 951 952if[-n"$files"] 953then 954test -n"$cached"&& 955 die "$(gettext "The --cached option cannot be used with the --files option")" 956 diff_cmd=diff-files 957head= 958fi 959 960 cd_to_toplevel 961eval"set$(git rev-parse --sq --prefix "$wt_prefix" -- "$@")" 962# Get modified modules cared by user 963 modules=$(git $diff_cmd $cached--ignore-submodules=dirty --raw$head--"$@"| 964 sane_egrep '^:([0-7]* )?160000'| 965whileread mod_src mod_dst sha1_src sha1_dst status sm_path 966do 967# Always show modules deleted or type-changed (blob<->module) 968iftest"$status"= D ||test"$status"= T 969then 970printf'%s\n'"$sm_path" 971continue 972fi 973# Respect the ignore setting for --for-status. 974iftest -n"$for_status" 975then 976 name=$(git submodule--helper name "$sm_path") 977 ignore_config=$(get_submodule_config "$name" ignore none) 978test$status!= A &&test$ignore_config= all &&continue 979fi 980# Also show added or modified modules which are checked out 981 GIT_DIR="$sm_path/.git" git-rev-parse --git-dir>/dev/null 2>&1&& 982printf'%s\n'"$sm_path" 983done 984) 985 986test -z"$modules"&&return 987 988 git $diff_cmd $cached--ignore-submodules=dirty --raw$head--$modules| 989 sane_egrep '^:([0-7]* )?160000'| 990 cut -c2-| 991whileread mod_src mod_dst sha1_src sha1_dst status name 992do 993iftest -z"$cached"&& 994test$sha1_dst=0000000000000000000000000000000000000000 995then 996case"$mod_dst"in 997160000) 998 sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD) 999;;1000100644|100755|120000)1001 sha1_dst=$(git hash-object $name)1002;;1003000000)1004;;# removed1005*)1006# unexpected type1007 eval_gettextln "unexpected mode \$mod_dst">&21008continue;;1009esac1010fi1011 missing_src=1012 missing_dst=10131014test$mod_src=160000&&1015! GIT_DIR="$name/.git" git-rev-parse -q --verify$sha1_src^0>/dev/null &&1016 missing_src=t10171018test$mod_dst=160000&&1019! GIT_DIR="$name/.git" git-rev-parse -q --verify$sha1_dst^0>/dev/null &&1020 missing_dst=t10211022 display_name=$(relative_path "$name")10231024 total_commits=1025case"$missing_src,$missing_dst"in1026 t,)1027 errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_src")"1028;;1029,t)1030 errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_dst")"1031;;1032 t,t)1033 errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commits \$sha1_src and \$sha1_dst")"1034;;1035*)1036 errmsg=1037 total_commits=$(1038iftest$mod_src=160000&&test$mod_dst=1600001039then1040 range="$sha1_src...$sha1_dst"1041eliftest$mod_src=1600001042then1043 range=$sha1_src1044else1045 range=$sha1_dst1046fi1047 GIT_DIR="$name/.git" \1048 git rev-list --first-parent$range--|wc-l1049)1050 total_commits=" ($(($total_commits + 0)))"1051;;1052esac10531054 sha1_abbr_src=$(echo $sha1_src | cut -c1-7)1055 sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)1056iftest$status= T1057then1058 blob="$(gettext "blob")"1059 submodule="$(gettext "submodule")"1060iftest$mod_dst=1600001061then1062echo"*$display_name$sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"1063else1064echo"*$display_name$sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"1065fi1066else1067echo"*$display_name$sha1_abbr_src...$sha1_abbr_dst$total_commits:"1068fi1069iftest -n"$errmsg"1070then1071# Don't give error msg for modification whose dst is not submodule1072# i.e. deleted or changed to blob1073test$mod_dst=160000&&echo"$errmsg"1074else1075iftest$mod_src=160000&&test$mod_dst=1600001076then1077 limit=1078test$summary_limit-gt0&& limit="-$summary_limit"1079 GIT_DIR="$name/.git" \1080 git log $limit--pretty='format: %m %s' \1081--first-parent$sha1_src...$sha1_dst1082eliftest$mod_dst=1600001083then1084 GIT_DIR="$name/.git" \1085 git log --pretty='format: > %s'-1$sha1_dst1086else1087 GIT_DIR="$name/.git" \1088 git log --pretty='format: < %s'-1$sha1_src1089fi1090echo1091fi1092echo1093done1094}1095#1096# List all submodules, prefixed with:1097# - submodule not initialized1098# + different revision checked out1099#1100# If --cached was specified the revision in the index will be printed1101# instead of the currently checked out revision.1102#1103# $@ = requested paths (default to all)1104#1105cmd_status()1106{1107# parse $args after "submodule ... status".1108whiletest$#-ne01109do1110case"$1"in1111-q|--quiet)1112 GIT_QUIET=11113;;1114--cached)1115 cached=11116;;1117--recursive)1118 recursive=11119;;1120--)1121shift1122break1123;;1124-*)1125 usage1126;;1127*)1128break1129;;1130esac1131shift1132done11331134 git submodule--helper list --prefix"$wt_prefix""$@"|1135whileread mode sha1 stage sm_path1136do1137 die_if_unmatched "$mode"1138 name=$(git submodule--helper name "$sm_path")||exit1139 url=$(git config submodule."$name".url)1140 displaypath=$(relative_path "$prefix$sm_path")1141iftest"$stage"= U1142then1143 say "U$sha1$displaypath"1144continue1145fi1146iftest -z"$url"||1147{1148!test -d"$sm_path"/.git &&1149!test -f"$sm_path"/.git1150}1151then1152 say "-$sha1$displaypath"1153continue;1154fi1155if git diff-files --ignore-submodules=dirty --quiet --"$sm_path"1156then1157 set_name_rev "$sm_path""$sha1"1158 say "$sha1$displaypath$revname"1159else1160iftest -z"$cached"1161then1162 sha1=$(sanitize_submodule_env; cd "$sm_path" && git rev-parse --verify HEAD)1163fi1164 set_name_rev "$sm_path""$sha1"1165 say "+$sha1$displaypath$revname"1166fi11671168iftest -n"$recursive"1169then1170(1171 prefix="$displaypath/"1172 sanitize_submodule_env1173cd"$sm_path"&&1174eval cmd_status1175) ||1176 die "$(eval_gettext "Failed to recurse into submodule path '\$sm_path'")"1177fi1178done1179}1180#1181# Sync remote urls for submodules1182# This makes the value for remote.$remote.url match the value1183# specified in .gitmodules.1184#1185cmd_sync()1186{1187whiletest$#-ne01188do1189case"$1"in1190-q|--quiet)1191 GIT_QUIET=11192shift1193;;1194--recursive)1195 recursive=11196shift1197;;1198--)1199shift1200break1201;;1202-*)1203 usage1204;;1205*)1206break1207;;1208esac1209done1210 cd_to_toplevel1211 git submodule--helper list --prefix"$wt_prefix""$@"|1212whileread mode sha1 stage sm_path1213do1214 die_if_unmatched "$mode"1215 name=$(git submodule--helper name "$sm_path")1216 url=$(git config -f .gitmodules --get submodule."$name".url)12171218# Possibly a url relative to parent1219case"$url"in1220 ./*|../*)1221# rewrite foo/bar as ../.. to find path from1222# submodule work tree to superproject work tree1223 up_path="$(printf '%s\n' "$sm_path" | sed "s/[^/][^/]*/../g")"&&1224# guarantee a trailing /1225 up_path=${up_path%/}/ &&1226# path from submodule work tree to submodule origin repo1227 sub_origin_url=$(resolve_relative_url "$url" "$up_path")&&1228# path from superproject work tree to submodule origin repo1229 super_config_url=$(resolve_relative_url "$url")||exit1230;;1231*)1232 sub_origin_url="$url"1233 super_config_url="$url"1234;;1235esac12361237if git config "submodule.$name.url">/dev/null 2>/dev/null1238then1239 displaypath=$(relative_path "$prefix$sm_path")1240 say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")"1241 git config submodule."$name".url "$super_config_url"12421243iftest -e"$sm_path"/.git1244then1245(1246 sanitize_submodule_env1247cd"$sm_path"1248 remote=$(get_default_remote)1249 git config remote."$remote".url "$sub_origin_url"12501251iftest -n"$recursive"1252then1253 prefix="$prefix$sm_path/"1254eval cmd_sync1255fi1256)1257fi1258fi1259done1260}12611262# This loop parses the command line arguments to find the1263# subcommand name to dispatch. Parsing of the subcommand specific1264# options are primarily done by the subcommand implementations.1265# Subcommand specific options such as --branch and --cached are1266# parsed here as well, for backward compatibility.12671268whiletest$#!=0&&test -z"$command"1269do1270case"$1"in1271 add | foreach | init | deinit | update | status | summary | sync)1272command=$11273;;1274-q|--quiet)1275 GIT_QUIET=11276;;1277-b|--branch)1278case"$2"in1279'')1280 usage1281;;1282esac1283 branch="$2";shift1284;;1285--cached)1286 cached="$1"1287;;1288--)1289break1290;;1291-*)1292 usage1293;;1294*)1295break1296;;1297esac1298shift1299done13001301# No command word defaults to "status"1302iftest -z"$command"1303then1304iftest$#=01305then1306command=status1307else1308 usage1309fi1310fi13111312# "-b branch" is accepted only by "add"1313iftest -n"$branch"&&test"$command"!= add1314then1315 usage1316fi13171318# "--cached" is accepted only by "status" and "summary"1319iftest -n"$cached"&&test"$command"!= status &&test"$command"!= summary1320then1321 usage1322fi13231324"cmd_$command""$@"