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