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