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