f7d7f51c37889b6d29239e794e444d0c1bcfa241
   1#!/bin/sh
   2#
   3# git-submodules.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] [--reference <repository>] [--] <repository> [<path>]
   9   or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
  10   or: $dashless [--quiet] init [--] [<path>...]
  11   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
  12   or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
  13   or: $dashless [--quiet] foreach [--recursive] <command>
  14   or: $dashless [--quiet] sync [--] [<path>...]"
  15OPTIONS_SPEC=
  16. git-sh-setup
  17. git-sh-i18n
  18. git-parse-remote
  19require_work_tree
  20
  21command=
  22branch=
  23force=
  24reference=
  25cached=
  26recursive=
  27init=
  28files=
  29nofetch=
  30update=
  31prefix=
  32
  33# Resolve relative url by appending to parent's url
  34resolve_relative_url ()
  35{
  36        remote=$(get_default_remote)
  37        remoteurl=$(git config "remote.$remote.url") ||
  38                die "$(eval_gettext "remote (\$remote) does not have a url defined in .git/config")"
  39        url="$1"
  40        remoteurl=${remoteurl%/}
  41        sep=/
  42        while test -n "$url"
  43        do
  44                case "$url" in
  45                ../*)
  46                        url="${url#../}"
  47                        case "$remoteurl" in
  48                        */*)
  49                                remoteurl="${remoteurl%/*}"
  50                                ;;
  51                        *:*)
  52                                remoteurl="${remoteurl%:*}"
  53                                sep=:
  54                                ;;
  55                        *)
  56                                die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
  57                                ;;
  58                        esac
  59                        ;;
  60                ./*)
  61                        url="${url#./}"
  62                        ;;
  63                *)
  64                        break;;
  65                esac
  66        done
  67        echo "$remoteurl$sep${url%/}"
  68}
  69
  70#
  71# Get submodule info for registered submodules
  72# $@ = path to limit submodule list
  73#
  74module_list()
  75{
  76        git ls-files --error-unmatch --stage -- "$@" |
  77        perl -e '
  78        my %unmerged = ();
  79        my ($null_sha1) = ("0" x 40);
  80        while (<STDIN>) {
  81                chomp;
  82                my ($mode, $sha1, $stage, $path) =
  83                        /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/;
  84                next unless $mode eq "160000";
  85                if ($stage ne "0") {
  86                        if (!$unmerged{$path}++) {
  87                                print "$mode $null_sha1 U\t$path\n";
  88                        }
  89                        next;
  90                }
  91                print "$_\n";
  92        }
  93        '
  94}
  95
  96#
  97# Map submodule path to submodule name
  98#
  99# $1 = path
 100#
 101module_name()
 102{
 103        # Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
 104        re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
 105        name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
 106                sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
 107       test -z "$name" &&
 108       die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
 109       echo "$name"
 110}
 111
 112#
 113# Clone a submodule
 114#
 115# Prior to calling, cmd_update checks that a possibly existing
 116# path is not a git repository.
 117# Likewise, cmd_add checks that path does not exist at all,
 118# since it is the location of a new submodule.
 119#
 120module_clone()
 121{
 122        path=$1
 123        url=$2
 124        reference="$3"
 125
 126        if test -n "$reference"
 127        then
 128                git-clone "$reference" -n "$url" "$path"
 129        else
 130                git-clone -n "$url" "$path"
 131        fi ||
 132        die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
 133}
 134
 135#
 136# Add a new submodule to the working tree, .gitmodules and the index
 137#
 138# $@ = repo path
 139#
 140# optional branch is stored in global branch variable
 141#
 142cmd_add()
 143{
 144        # parse $args after "submodule ... add".
 145        while test $# -ne 0
 146        do
 147                case "$1" in
 148                -b | --branch)
 149                        case "$2" in '') usage ;; esac
 150                        branch=$2
 151                        shift
 152                        ;;
 153                -f | --force)
 154                        force=$1
 155                        ;;
 156                -q|--quiet)
 157                        GIT_QUIET=1
 158                        ;;
 159                --reference)
 160                        case "$2" in '') usage ;; esac
 161                        reference="--reference=$2"
 162                        shift
 163                        ;;
 164                --reference=*)
 165                        reference="$1"
 166                        shift
 167                        ;;
 168                --)
 169                        shift
 170                        break
 171                        ;;
 172                -*)
 173                        usage
 174                        ;;
 175                *)
 176                        break
 177                        ;;
 178                esac
 179                shift
 180        done
 181
 182        repo=$1
 183        path=$2
 184
 185        if test -z "$path"; then
 186                path=$(echo "$repo" |
 187                        sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
 188        fi
 189
 190        if test -z "$repo" -o -z "$path"; then
 191                usage
 192        fi
 193
 194        # assure repo is absolute or relative to parent
 195        case "$repo" in
 196        ./*|../*)
 197                # dereference source url relative to parent's url
 198                realrepo=$(resolve_relative_url "$repo") || exit
 199                ;;
 200        *:*|/*)
 201                # absolute url
 202                realrepo=$repo
 203                ;;
 204        *)
 205                die "$(eval_gettext "repo URL: '\$repo' must be absolute or begin with ./|../")"
 206        ;;
 207        esac
 208
 209        # normalize path:
 210        # multiple //; leading ./; /./; /../; trailing /
 211        path=$(printf '%s/\n' "$path" |
 212                sed -e '
 213                        s|//*|/|g
 214                        s|^\(\./\)*||
 215                        s|/\./|/|g
 216                        :start
 217                        s|\([^/]*\)/\.\./||
 218                        tstart
 219                        s|/*$||
 220                ')
 221        git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
 222        die "$(eval_gettext "'\$path' already exists in the index")"
 223
 224        if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
 225        then
 226                echo >&2 "The following path is ignored by one of your .gitignore files:" &&
 227                echo >&2 $path &&
 228                echo >&2 "Use -f if you really want to add it."
 229                exit 1
 230        fi
 231
 232        # perhaps the path exists and is already a git repo, else clone it
 233        if test -e "$path"
 234        then
 235                if test -d "$path"/.git -o -f "$path"/.git
 236                then
 237                        eval_gettext "Adding existing repo at '\$path' to the index"; echo
 238                else
 239                        die "$(eval_gettext "'\$path' already exists and is not a valid git repo")"
 240                fi
 241
 242                case "$repo" in
 243                ./*|../*)
 244                        url=$(resolve_relative_url "$repo") || exit
 245                    ;;
 246                *)
 247                        url="$repo"
 248                        ;;
 249                esac
 250                git config submodule."$path".url "$url"
 251        else
 252
 253                module_clone "$path" "$realrepo" "$reference" || exit
 254                (
 255                        clear_local_git_env
 256                        cd "$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 '\$path'")"
 263        fi
 264
 265        git add $force "$path" ||
 266        die "$(eval_gettext "Failed to add submodule '\$path'")"
 267
 268        git config -f .gitmodules submodule."$path".path "$path" &&
 269        git config -f .gitmodules submodule."$path".url "$repo" &&
 270        git add --force .gitmodules ||
 271        die "$(eval_gettext "Failed to register submodule '\$path'")"
 272}
 273
 274#
 275# Execute an arbitrary command sequence in each checked out
 276# submodule
 277#
 278# $@ = command to execute
 279#
 280cmd_foreach()
 281{
 282        # parse $args after "submodule ... foreach".
 283        while test $# -ne 0
 284        do
 285                case "$1" in
 286                -q|--quiet)
 287                        GIT_QUIET=1
 288                        ;;
 289                --recursive)
 290                        recursive=1
 291                        ;;
 292                -*)
 293                        usage
 294                        ;;
 295                *)
 296                        break
 297                        ;;
 298                esac
 299                shift
 300        done
 301
 302        toplevel=$(pwd)
 303
 304        module_list |
 305        while read mode sha1 stage path
 306        do
 307                if test -e "$path"/.git
 308                then
 309                        say "$(eval_gettext "Entering '\$prefix\$path'")"
 310                        name=$(module_name "$path")
 311                        (
 312                                prefix="$prefix$path/"
 313                                clear_local_git_env
 314                                cd "$path" &&
 315                                eval "$@" &&
 316                                if test -n "$recursive"
 317                                then
 318                                        cmd_foreach "--recursive" "$@"
 319                                fi
 320                        ) ||
 321                        die "$(eval_gettext "Stopping at '\$path'; script returned non-zero status.")"
 322                fi
 323        done
 324}
 325
 326#
 327# Register submodules in .git/config
 328#
 329# $@ = requested paths (default to all)
 330#
 331cmd_init()
 332{
 333        # parse $args after "submodule ... init".
 334        while test $# -ne 0
 335        do
 336                case "$1" in
 337                -q|--quiet)
 338                        GIT_QUIET=1
 339                        ;;
 340                --)
 341                        shift
 342                        break
 343                        ;;
 344                -*)
 345                        usage
 346                        ;;
 347                *)
 348                        break
 349                        ;;
 350                esac
 351                shift
 352        done
 353
 354        module_list "$@" |
 355        while read mode sha1 stage path
 356        do
 357                # Skip already registered paths
 358                name=$(module_name "$path") || exit
 359                url=$(git config submodule."$name".url)
 360                test -z "$url" || continue
 361
 362                url=$(git config -f .gitmodules submodule."$name".url)
 363                test -z "$url" &&
 364                die "$(eval_gettext "No url found for submodule path '\$path' in .gitmodules")"
 365
 366                # Possibly a url relative to parent
 367                case "$url" in
 368                ./*|../*)
 369                        url=$(resolve_relative_url "$url") || exit
 370                        ;;
 371                esac
 372
 373                git config submodule."$name".url "$url" ||
 374                die "$(eval_gettext "Failed to register url for submodule path '\$path'")"
 375
 376                upd="$(git config -f .gitmodules submodule."$name".update)"
 377                test -z "$upd" ||
 378                git config submodule."$name".update "$upd" ||
 379                die "$(eval_gettext "Failed to register update mode for submodule path '\$path'")"
 380
 381                say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$path'")"
 382        done
 383}
 384
 385#
 386# Update each submodule path to correct revision, using clone and checkout as needed
 387#
 388# $@ = requested paths (default to all)
 389#
 390cmd_update()
 391{
 392        # parse $args after "submodule ... update".
 393        orig_flags=
 394        while test $# -ne 0
 395        do
 396                case "$1" in
 397                -q|--quiet)
 398                        GIT_QUIET=1
 399                        ;;
 400                -i|--init)
 401                        init=1
 402                        ;;
 403                -N|--no-fetch)
 404                        nofetch=1
 405                        ;;
 406                -f|--force)
 407                        force=$1
 408                        ;;
 409                -r|--rebase)
 410                        update="rebase"
 411                        ;;
 412                --reference)
 413                        case "$2" in '') usage ;; esac
 414                        reference="--reference=$2"
 415                        orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
 416                        shift
 417                        ;;
 418                --reference=*)
 419                        reference="$1"
 420                        ;;
 421                -m|--merge)
 422                        update="merge"
 423                        ;;
 424                --recursive)
 425                        recursive=1
 426                        ;;
 427                --)
 428                        shift
 429                        break
 430                        ;;
 431                -*)
 432                        usage
 433                        ;;
 434                *)
 435                        break
 436                        ;;
 437                esac
 438                orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
 439                shift
 440        done
 441
 442        if test -n "$init"
 443        then
 444                cmd_init "--" "$@" || return
 445        fi
 446
 447        cloned_modules=
 448        module_list "$@" |
 449        while read mode sha1 stage path
 450        do
 451                if test "$stage" = U
 452                then
 453                        echo >&2 "Skipping unmerged submodule $path"
 454                        continue
 455                fi
 456                name=$(module_name "$path") || exit
 457                url=$(git config submodule."$name".url)
 458                update_module=$(git config submodule."$name".update)
 459                if test -z "$url"
 460                then
 461                        # Only mention uninitialized submodules when its
 462                        # path have been specified
 463                        test "$#" != "0" &&
 464                        say "Submodule path '$path' not initialized" &&
 465                        say "Maybe you want to use 'update --init'?"
 466                        continue
 467                fi
 468
 469                if ! test -d "$path"/.git -o -f "$path"/.git
 470                then
 471                        module_clone "$path" "$url" "$reference"|| exit
 472                        cloned_modules="$cloned_modules;$name"
 473                        subsha1=
 474                else
 475                        subsha1=$(clear_local_git_env; cd "$path" &&
 476                                git rev-parse --verify HEAD) ||
 477                        die "$(eval_gettext "Unable to find current revision in submodule path '\$path'")"
 478                fi
 479
 480                if ! test -z "$update"
 481                then
 482                        update_module=$update
 483                fi
 484
 485                if test "$subsha1" != "$sha1"
 486                then
 487                        subforce=$force
 488                        # If we don't already have a -f flag and the submodule has never been checked out
 489                        if test -z "$subsha1" -a -z "$force"
 490                        then
 491                                subforce="-f"
 492                        fi
 493
 494                        if test -z "$nofetch"
 495                        then
 496                                # Run fetch only if $sha1 isn't present or it
 497                                # is not reachable from a ref.
 498                                (clear_local_git_env; cd "$path" &&
 499                                        ((rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) &&
 500                                         test -z "$rev") || git-fetch)) ||
 501                                die "$(eval_gettext "Unable to fetch in submodule path '\$path'")"
 502                        fi
 503
 504                        # Is this something we just cloned?
 505                        case ";$cloned_modules;" in
 506                        *";$name;"*)
 507                                # then there is no local change to integrate
 508                                update_module= ;;
 509                        esac
 510
 511                        case "$update_module" in
 512                        rebase)
 513                                command="git rebase"
 514                                die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")"
 515                                say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")"
 516                                ;;
 517                        merge)
 518                                command="git merge"
 519                                die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")"
 520                                say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")"
 521                                ;;
 522                        *)
 523                                command="git checkout $subforce -q"
 524                                die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")"
 525                                say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")"
 526                                ;;
 527                        esac
 528
 529                        (clear_local_git_env; cd "$path" && $command "$sha1") || die $die_msg
 530                        say $say_msg
 531                fi
 532
 533                if test -n "$recursive"
 534                then
 535                        (clear_local_git_env; cd "$path" && eval cmd_update "$orig_flags") ||
 536                        die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
 537                fi
 538        done
 539}
 540
 541set_name_rev () {
 542        revname=$( (
 543                clear_local_git_env
 544                cd "$1" && {
 545                        git describe "$2" 2>/dev/null ||
 546                        git describe --tags "$2" 2>/dev/null ||
 547                        git describe --contains "$2" 2>/dev/null ||
 548                        git describe --all --always "$2"
 549                }
 550        ) )
 551        test -z "$revname" || revname=" ($revname)"
 552}
 553#
 554# Show commit summary for submodules in index or working tree
 555#
 556# If '--cached' is given, show summary between index and given commit,
 557# or between working tree and given commit
 558#
 559# $@ = [commit (default 'HEAD'),] requested paths (default all)
 560#
 561cmd_summary() {
 562        summary_limit=-1
 563        for_status=
 564        diff_cmd=diff-index
 565
 566        # parse $args after "submodule ... summary".
 567        while test $# -ne 0
 568        do
 569                case "$1" in
 570                --cached)
 571                        cached="$1"
 572                        ;;
 573                --files)
 574                        files="$1"
 575                        ;;
 576                --for-status)
 577                        for_status="$1"
 578                        ;;
 579                -n|--summary-limit)
 580                        if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
 581                        then
 582                                :
 583                        else
 584                                usage
 585                        fi
 586                        shift
 587                        ;;
 588                --)
 589                        shift
 590                        break
 591                        ;;
 592                -*)
 593                        usage
 594                        ;;
 595                *)
 596                        break
 597                        ;;
 598                esac
 599                shift
 600        done
 601
 602        test $summary_limit = 0 && return
 603
 604        if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
 605        then
 606                head=$rev
 607                test $# = 0 || shift
 608        elif test -z "$1" -o "$1" = "HEAD"
 609        then
 610                # before the first commit: compare with an empty tree
 611                head=$(git hash-object -w -t tree --stdin </dev/null)
 612                test -z "$1" || shift
 613        else
 614                head="HEAD"
 615        fi
 616
 617        if [ -n "$files" ]
 618        then
 619                test -n "$cached" &&
 620                die "$(gettext -- "--cached cannot be used with --files")"
 621                diff_cmd=diff-files
 622                head=
 623        fi
 624
 625        cd_to_toplevel
 626        # Get modified modules cared by user
 627        modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
 628                sane_egrep '^:([0-7]* )?160000' |
 629                while read mod_src mod_dst sha1_src sha1_dst status name
 630                do
 631                        # Always show modules deleted or type-changed (blob<->module)
 632                        test $status = D -o $status = T && echo "$name" && continue
 633                        # Also show added or modified modules which are checked out
 634                        GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
 635                        echo "$name"
 636                done
 637        )
 638
 639        test -z "$modules" && return
 640
 641        git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |
 642        sane_egrep '^:([0-7]* )?160000' |
 643        cut -c2- |
 644        while read mod_src mod_dst sha1_src sha1_dst status name
 645        do
 646                if test -z "$cached" &&
 647                        test $sha1_dst = 0000000000000000000000000000000000000000
 648                then
 649                        case "$mod_dst" in
 650                        160000)
 651                                sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
 652                                ;;
 653                        100644 | 100755 | 120000)
 654                                sha1_dst=$(git hash-object $name)
 655                                ;;
 656                        000000)
 657                                ;; # removed
 658                        *)
 659                                # unexpected type
 660                                (
 661                                        eval_gettext "unexpected mode \$mod_dst" &&
 662                                        echo
 663                                ) >&2
 664                                continue ;;
 665                        esac
 666                fi
 667                missing_src=
 668                missing_dst=
 669
 670                test $mod_src = 160000 &&
 671                ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
 672                missing_src=t
 673
 674                test $mod_dst = 160000 &&
 675                ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
 676                missing_dst=t
 677
 678                total_commits=
 679                case "$missing_src,$missing_dst" in
 680                t,)
 681                        errmsg="$(eval_gettext "  Warn: \$name doesn't contain commit \$sha1_src")"
 682                        ;;
 683                ,t)
 684                        errmsg="$(eval_gettext "  Warn: \$name doesn't contain commit \$sha1_dst")"
 685                        ;;
 686                t,t)
 687                        errmsg="$(eval_gettext "  Warn: \$name doesn't contain commits \$sha1_src and \$sha1_dst")"
 688                        ;;
 689                *)
 690                        errmsg=
 691                        total_commits=$(
 692                        if test $mod_src = 160000 -a $mod_dst = 160000
 693                        then
 694                                range="$sha1_src...$sha1_dst"
 695                        elif test $mod_src = 160000
 696                        then
 697                                range=$sha1_src
 698                        else
 699                                range=$sha1_dst
 700                        fi
 701                        GIT_DIR="$name/.git" \
 702                        git rev-list --first-parent $range -- | wc -l
 703                        )
 704                        total_commits=" ($(($total_commits + 0)))"
 705                        ;;
 706                esac
 707
 708                sha1_abbr_src=$(echo $sha1_src | cut -c1-7)
 709                sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)
 710                if test $status = T
 711                then
 712                        if test $mod_dst = 160000
 713                        then
 714                                echo "* $name $sha1_abbr_src(blob)->$sha1_abbr_dst(submodule)$total_commits:"
 715                        else
 716                                echo "* $name $sha1_abbr_src(submodule)->$sha1_abbr_dst(blob)$total_commits:"
 717                        fi
 718                else
 719                        echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
 720                fi
 721                if test -n "$errmsg"
 722                then
 723                        # Don't give error msg for modification whose dst is not submodule
 724                        # i.e. deleted or changed to blob
 725                        test $mod_dst = 160000 && echo "$errmsg"
 726                else
 727                        if test $mod_src = 160000 -a $mod_dst = 160000
 728                        then
 729                                limit=
 730                                test $summary_limit -gt 0 && limit="-$summary_limit"
 731                                GIT_DIR="$name/.git" \
 732                                git log $limit --pretty='format:  %m %s' \
 733                                --first-parent $sha1_src...$sha1_dst
 734                        elif test $mod_dst = 160000
 735                        then
 736                                GIT_DIR="$name/.git" \
 737                                git log --pretty='format:  > %s' -1 $sha1_dst
 738                        else
 739                                GIT_DIR="$name/.git" \
 740                                git log --pretty='format:  < %s' -1 $sha1_src
 741                        fi
 742                        echo
 743                fi
 744                echo
 745        done |
 746        if test -n "$for_status"; then
 747                if [ -n "$files" ]; then
 748                        gettext "# Submodules changed but not updated:"; echo
 749                else
 750                        gettext "# Submodule changes to be committed:"; echo
 751                fi
 752                echo "#"
 753                sed -e 's|^|# |' -e 's|^# $|#|'
 754        else
 755                cat
 756        fi
 757}
 758#
 759# List all submodules, prefixed with:
 760#  - submodule not initialized
 761#  + different revision checked out
 762#
 763# If --cached was specified the revision in the index will be printed
 764# instead of the currently checked out revision.
 765#
 766# $@ = requested paths (default to all)
 767#
 768cmd_status()
 769{
 770        # parse $args after "submodule ... status".
 771        orig_flags=
 772        while test $# -ne 0
 773        do
 774                case "$1" in
 775                -q|--quiet)
 776                        GIT_QUIET=1
 777                        ;;
 778                --cached)
 779                        cached=1
 780                        ;;
 781                --recursive)
 782                        recursive=1
 783                        ;;
 784                --)
 785                        shift
 786                        break
 787                        ;;
 788                -*)
 789                        usage
 790                        ;;
 791                *)
 792                        break
 793                        ;;
 794                esac
 795                orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
 796                shift
 797        done
 798
 799        module_list "$@" |
 800        while read mode sha1 stage path
 801        do
 802                name=$(module_name "$path") || exit
 803                url=$(git config submodule."$name".url)
 804                displaypath="$prefix$path"
 805                if test "$stage" = U
 806                then
 807                        say "U$sha1 $displaypath"
 808                        continue
 809                fi
 810                if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
 811                then
 812                        say "-$sha1 $displaypath"
 813                        continue;
 814                fi
 815                set_name_rev "$path" "$sha1"
 816                if git diff-files --ignore-submodules=dirty --quiet -- "$path"
 817                then
 818                        say " $sha1 $displaypath$revname"
 819                else
 820                        if test -z "$cached"
 821                        then
 822                                sha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD)
 823                                set_name_rev "$path" "$sha1"
 824                        fi
 825                        say "+$sha1 $displaypath$revname"
 826                fi
 827
 828                if test -n "$recursive"
 829                then
 830                        (
 831                                prefix="$displaypath/"
 832                                clear_local_git_env
 833                                cd "$path" &&
 834                                eval cmd_status "$orig_args"
 835                        ) ||
 836                        die "$(eval_gettext "Failed to recurse into submodule path '\$path'")"
 837                fi
 838        done
 839}
 840#
 841# Sync remote urls for submodules
 842# This makes the value for remote.$remote.url match the value
 843# specified in .gitmodules.
 844#
 845cmd_sync()
 846{
 847        while test $# -ne 0
 848        do
 849                case "$1" in
 850                -q|--quiet)
 851                        GIT_QUIET=1
 852                        shift
 853                        ;;
 854                --)
 855                        shift
 856                        break
 857                        ;;
 858                -*)
 859                        usage
 860                        ;;
 861                *)
 862                        break
 863                        ;;
 864                esac
 865        done
 866        cd_to_toplevel
 867        module_list "$@" |
 868        while read mode sha1 stage path
 869        do
 870                name=$(module_name "$path")
 871                url=$(git config -f .gitmodules --get submodule."$name".url)
 872
 873                # Possibly a url relative to parent
 874                case "$url" in
 875                ./*|../*)
 876                        url=$(resolve_relative_url "$url") || exit
 877                        ;;
 878                esac
 879
 880                say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
 881                git config submodule."$name".url "$url"
 882
 883                if test -e "$path"/.git
 884                then
 885                (
 886                        clear_local_git_env
 887                        cd "$path"
 888                        remote=$(get_default_remote)
 889                        git config remote."$remote".url "$url"
 890                )
 891                fi
 892        done
 893}
 894
 895# This loop parses the command line arguments to find the
 896# subcommand name to dispatch.  Parsing of the subcommand specific
 897# options are primarily done by the subcommand implementations.
 898# Subcommand specific options such as --branch and --cached are
 899# parsed here as well, for backward compatibility.
 900
 901while test $# != 0 && test -z "$command"
 902do
 903        case "$1" in
 904        add | foreach | init | update | status | summary | sync)
 905                command=$1
 906                ;;
 907        -q|--quiet)
 908                GIT_QUIET=1
 909                ;;
 910        -b|--branch)
 911                case "$2" in
 912                '')
 913                        usage
 914                        ;;
 915                esac
 916                branch="$2"; shift
 917                ;;
 918        --cached)
 919                cached="$1"
 920                ;;
 921        --)
 922                break
 923                ;;
 924        -*)
 925                usage
 926                ;;
 927        *)
 928                break
 929                ;;
 930        esac
 931        shift
 932done
 933
 934# No command word defaults to "status"
 935test -n "$command" || command=status
 936
 937# "-b branch" is accepted only by "add"
 938if test -n "$branch" && test "$command" != add
 939then
 940        usage
 941fi
 942
 943# "--cached" is accepted only by "status" and "summary"
 944if test -n "$cached" && test "$command" != status -a "$command" != summary
 945then
 946        usage
 947fi
 948
 949"cmd_$command" "$@"