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