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