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