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