git-submodule.shon commit submodule: print graph output next to submodule log (0f33a06)
   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 -n "$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" || say "$(eval_gettext "Could not remove submodule work tree '\$sm_path'")"
 613                fi
 614
 615                mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$sm_path'")"
 616
 617                # Remove the .git/config entries (unless the user already did it)
 618                if test -n "$(git config --get-regexp submodule."$name\.")"
 619                then
 620                        # Remove the whole section so we have a clean state when
 621                        # the user later decides to init this submodule again
 622                        url=$(git config submodule."$name".url)
 623                        git config --remove-section submodule."$name" 2>/dev/null &&
 624                        say "$(eval_gettext "Submodule '\$name' (\$url) unregistered for path '\$sm_path'")"
 625                fi
 626        done
 627}
 628
 629#
 630# Update each submodule path to correct revision, using clone and checkout as needed
 631#
 632# $@ = requested paths (default to all)
 633#
 634cmd_update()
 635{
 636        # parse $args after "submodule ... update".
 637        orig_flags=
 638        while test $# -ne 0
 639        do
 640                case "$1" in
 641                -q|--quiet)
 642                        GIT_QUIET=1
 643                        ;;
 644                -i|--init)
 645                        init=1
 646                        ;;
 647                --remote)
 648                        remote=1
 649                        ;;
 650                -N|--no-fetch)
 651                        nofetch=1
 652                        ;;
 653                -f|--force)
 654                        force=$1
 655                        ;;
 656                -r|--rebase)
 657                        update="rebase"
 658                        ;;
 659                --reference)
 660                        case "$2" in '') usage ;; esac
 661                        reference="--reference=$2"
 662                        orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
 663                        shift
 664                        ;;
 665                --reference=*)
 666                        reference="$1"
 667                        ;;
 668                -m|--merge)
 669                        update="merge"
 670                        ;;
 671                --recursive)
 672                        recursive=1
 673                        ;;
 674                --checkout)
 675                        update="checkout"
 676                        ;;
 677                --)
 678                        shift
 679                        break
 680                        ;;
 681                -*)
 682                        usage
 683                        ;;
 684                *)
 685                        break
 686                        ;;
 687                esac
 688                orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
 689                shift
 690        done
 691
 692        if test -n "$init"
 693        then
 694                cmd_init "--" "$@" || return
 695        fi
 696
 697        cloned_modules=
 698        module_list "$@" | {
 699        err=
 700        while read mode sha1 stage sm_path
 701        do
 702                die_if_unmatched "$mode"
 703                if test "$stage" = U
 704                then
 705                        echo >&2 "Skipping unmerged submodule $prefix$sm_path"
 706                        continue
 707                fi
 708                name=$(module_name "$sm_path") || exit
 709                url=$(git config submodule."$name".url)
 710                branch=$(get_submodule_config "$name" branch master)
 711                if ! test -z "$update"
 712                then
 713                        update_module=$update
 714                else
 715                        update_module=$(git config submodule."$name".update)
 716                fi
 717
 718                if test "$update_module" = "none"
 719                then
 720                        echo "Skipping submodule '$prefix$sm_path'"
 721                        continue
 722                fi
 723
 724                if test -z "$url"
 725                then
 726                        # Only mention uninitialized submodules when its
 727                        # path have been specified
 728                        test "$#" != "0" &&
 729                        say "$(eval_gettext "Submodule path '\$prefix\$sm_path' not initialized
 730Maybe you want to use 'update --init'?")"
 731                        continue
 732                fi
 733
 734                if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
 735                then
 736                        module_clone "$sm_path" "$name" "$url" "$reference" || exit
 737                        cloned_modules="$cloned_modules;$name"
 738                        subsha1=
 739                else
 740                        subsha1=$(clear_local_git_env; cd "$sm_path" &&
 741                                git rev-parse --verify HEAD) ||
 742                        die "$(eval_gettext "Unable to find current revision in submodule path '\$prefix\$sm_path'")"
 743                fi
 744
 745                if test -n "$remote"
 746                then
 747                        if test -z "$nofetch"
 748                        then
 749                                # Fetch remote before determining tracking $sha1
 750                                (clear_local_git_env; cd "$sm_path" && git-fetch) ||
 751                                die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
 752                        fi
 753                        remote_name=$(clear_local_git_env; cd "$sm_path" && get_default_remote)
 754                        sha1=$(clear_local_git_env; cd "$sm_path" &&
 755                                git rev-parse --verify "${remote_name}/${branch}") ||
 756                        die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
 757                fi
 758
 759                if test "$subsha1" != "$sha1" -o -n "$force"
 760                then
 761                        subforce=$force
 762                        # If we don't already have a -f flag and the submodule has never been checked out
 763                        if test -z "$subsha1" -a -z "$force"
 764                        then
 765                                subforce="-f"
 766                        fi
 767
 768                        if test -z "$nofetch"
 769                        then
 770                                # Run fetch only if $sha1 isn't present or it
 771                                # is not reachable from a ref.
 772                                (clear_local_git_env; cd "$sm_path" &&
 773                                        ( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) &&
 774                                         test -z "$rev") || git-fetch)) ||
 775                                die "$(eval_gettext "Unable to fetch in submodule path '\$prefix\$sm_path'")"
 776                        fi
 777
 778                        # Is this something we just cloned?
 779                        case ";$cloned_modules;" in
 780                        *";$name;"*)
 781                                # then there is no local change to integrate
 782                                update_module= ;;
 783                        esac
 784
 785                        must_die_on_failure=
 786                        case "$update_module" in
 787                        rebase)
 788                                command="git rebase"
 789                                die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$prefix\$sm_path'")"
 790                                say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': rebased into '\$sha1'")"
 791                                must_die_on_failure=yes
 792                                ;;
 793                        merge)
 794                                command="git merge"
 795                                die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$prefix\$sm_path'")"
 796                                say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': merged in '\$sha1'")"
 797                                must_die_on_failure=yes
 798                                ;;
 799                        *)
 800                                command="git checkout $subforce -q"
 801                                die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$prefix\$sm_path'")"
 802                                say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': checked out '\$sha1'")"
 803                                ;;
 804                        esac
 805
 806                        if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
 807                        then
 808                                say "$say_msg"
 809                        elif test -n "$must_die_on_failure"
 810                        then
 811                                die_with_status 2 "$die_msg"
 812                        else
 813                                err="${err};$die_msg"
 814                                continue
 815                        fi
 816                fi
 817
 818                if test -n "$recursive"
 819                then
 820                        (
 821                                prefix="$prefix$sm_path/"
 822                                clear_local_git_env
 823                                cd "$sm_path" &&
 824                                eval cmd_update "$orig_flags"
 825                        )
 826                        res=$?
 827                        if test $res -gt 0
 828                        then
 829                                die_msg="$(eval_gettext "Failed to recurse into submodule path '\$prefix\$sm_path'")"
 830                                if test $res -eq 1
 831                                then
 832                                        err="${err};$die_msg"
 833                                        continue
 834                                else
 835                                        die_with_status $res "$die_msg"
 836                                fi
 837                        fi
 838                fi
 839        done
 840
 841        if test -n "$err"
 842        then
 843                OIFS=$IFS
 844                IFS=';'
 845                for e in $err
 846                do
 847                        if test -n "$e"
 848                        then
 849                                echo >&2 "$e"
 850                        fi
 851                done
 852                IFS=$OIFS
 853                exit 1
 854        fi
 855        }
 856}
 857
 858set_name_rev () {
 859        revname=$( (
 860                clear_local_git_env
 861                cd "$1" && {
 862                        git describe "$2" 2>/dev/null ||
 863                        git describe --tags "$2" 2>/dev/null ||
 864                        git describe --contains "$2" 2>/dev/null ||
 865                        git describe --all --always "$2"
 866                }
 867        ) )
 868        test -z "$revname" || revname=" ($revname)"
 869}
 870#
 871# Show commit summary for submodules in index or working tree
 872#
 873# If '--cached' is given, show summary between index and given commit,
 874# or between working tree and given commit
 875#
 876# $@ = [commit (default 'HEAD'),] requested paths (default all)
 877#
 878cmd_summary() {
 879        summary_limit=-1
 880        for_status=
 881        diff_cmd=diff-index
 882
 883        # parse $args after "submodule ... summary".
 884        while test $# -ne 0
 885        do
 886                case "$1" in
 887                --cached)
 888                        cached="$1"
 889                        ;;
 890                --files)
 891                        files="$1"
 892                        ;;
 893                --for-status)
 894                        for_status="$1"
 895                        ;;
 896                -n|--summary-limit)
 897                        summary_limit="$2"
 898                        isnumber "$summary_limit" || usage
 899                        shift
 900                        ;;
 901                --summary-limit=*)
 902                        summary_limit="${1#--summary-limit=}"
 903                        isnumber "$summary_limit" || usage
 904                        ;;
 905                --)
 906                        shift
 907                        break
 908                        ;;
 909                -*)
 910                        usage
 911                        ;;
 912                *)
 913                        break
 914                        ;;
 915                esac
 916                shift
 917        done
 918
 919        test $summary_limit = 0 && return
 920
 921        if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
 922        then
 923                head=$rev
 924                test $# = 0 || shift
 925        elif test -z "$1" -o "$1" = "HEAD"
 926        then
 927                # before the first commit: compare with an empty tree
 928                head=$(git hash-object -w -t tree --stdin </dev/null)
 929                test -z "$1" || shift
 930        else
 931                head="HEAD"
 932        fi
 933
 934        if [ -n "$files" ]
 935        then
 936                test -n "$cached" &&
 937                die "$(gettext "The --cached option cannot be used with the --files option")"
 938                diff_cmd=diff-files
 939                head=
 940        fi
 941
 942        cd_to_toplevel
 943        # Get modified modules cared by user
 944        modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
 945                sane_egrep '^:([0-7]* )?160000' |
 946                while read mod_src mod_dst sha1_src sha1_dst status name
 947                do
 948                        # Always show modules deleted or type-changed (blob<->module)
 949                        test $status = D -o $status = T && echo "$name" && continue
 950                        # Also show added or modified modules which are checked out
 951                        GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
 952                        echo "$name"
 953                done
 954        )
 955
 956        test -z "$modules" && return
 957
 958        git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |
 959        sane_egrep '^:([0-7]* )?160000' |
 960        cut -c2- |
 961        while read mod_src mod_dst sha1_src sha1_dst status name
 962        do
 963                if test -z "$cached" &&
 964                        test $sha1_dst = 0000000000000000000000000000000000000000
 965                then
 966                        case "$mod_dst" in
 967                        160000)
 968                                sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
 969                                ;;
 970                        100644 | 100755 | 120000)
 971                                sha1_dst=$(git hash-object $name)
 972                                ;;
 973                        000000)
 974                                ;; # removed
 975                        *)
 976                                # unexpected type
 977                                eval_gettextln "unexpected mode \$mod_dst" >&2
 978                                continue ;;
 979                        esac
 980                fi
 981                missing_src=
 982                missing_dst=
 983
 984                test $mod_src = 160000 &&
 985                ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
 986                missing_src=t
 987
 988                test $mod_dst = 160000 &&
 989                ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
 990                missing_dst=t
 991
 992                total_commits=
 993                case "$missing_src,$missing_dst" in
 994                t,)
 995                        errmsg="$(eval_gettext "  Warn: \$name doesn't contain commit \$sha1_src")"
 996                        ;;
 997                ,t)
 998                        errmsg="$(eval_gettext "  Warn: \$name doesn't contain commit \$sha1_dst")"
 999                        ;;
1000                t,t)
1001                        errmsg="$(eval_gettext "  Warn: \$name doesn't contain commits \$sha1_src and \$sha1_dst")"
1002                        ;;
1003                *)
1004                        errmsg=
1005                        total_commits=$(
1006                        if test $mod_src = 160000 -a $mod_dst = 160000
1007                        then
1008                                range="$sha1_src...$sha1_dst"
1009                        elif test $mod_src = 160000
1010                        then
1011                                range=$sha1_src
1012                        else
1013                                range=$sha1_dst
1014                        fi
1015                        GIT_DIR="$name/.git" \
1016                        git rev-list --first-parent $range -- | wc -l
1017                        )
1018                        total_commits=" ($(($total_commits + 0)))"
1019                        ;;
1020                esac
1021
1022                sha1_abbr_src=$(echo $sha1_src | cut -c1-7)
1023                sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)
1024                if test $status = T
1025                then
1026                        blob="$(gettext "blob")"
1027                        submodule="$(gettext "submodule")"
1028                        if test $mod_dst = 160000
1029                        then
1030                                echo "* $name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"
1031                        else
1032                                echo "* $name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"
1033                        fi
1034                else
1035                        echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
1036                fi
1037                if test -n "$errmsg"
1038                then
1039                        # Don't give error msg for modification whose dst is not submodule
1040                        # i.e. deleted or changed to blob
1041                        test $mod_dst = 160000 && echo "$errmsg"
1042                else
1043                        if test $mod_src = 160000 -a $mod_dst = 160000
1044                        then
1045                                limit=
1046                                test $summary_limit -gt 0 && limit="-$summary_limit"
1047                                GIT_DIR="$name/.git" \
1048                                git log $limit --pretty='format:  %m %s' \
1049                                --first-parent $sha1_src...$sha1_dst
1050                        elif test $mod_dst = 160000
1051                        then
1052                                GIT_DIR="$name/.git" \
1053                                git log --pretty='format:  > %s' -1 $sha1_dst
1054                        else
1055                                GIT_DIR="$name/.git" \
1056                                git log --pretty='format:  < %s' -1 $sha1_src
1057                        fi
1058                        echo
1059                fi
1060                echo
1061        done |
1062        if test -n "$for_status"; then
1063                if [ -n "$files" ]; then
1064                        gettextln "Submodules changed but not updated:" | git stripspace -c
1065                else
1066                        gettextln "Submodule changes to be committed:" | git stripspace -c
1067                fi
1068                printf "\n" | git stripspace -c
1069                git stripspace -c
1070        else
1071                cat
1072        fi
1073}
1074#
1075# List all submodules, prefixed with:
1076#  - submodule not initialized
1077#  + different revision checked out
1078#
1079# If --cached was specified the revision in the index will be printed
1080# instead of the currently checked out revision.
1081#
1082# $@ = requested paths (default to all)
1083#
1084cmd_status()
1085{
1086        # parse $args after "submodule ... status".
1087        while test $# -ne 0
1088        do
1089                case "$1" in
1090                -q|--quiet)
1091                        GIT_QUIET=1
1092                        ;;
1093                --cached)
1094                        cached=1
1095                        ;;
1096                --recursive)
1097                        recursive=1
1098                        ;;
1099                --)
1100                        shift
1101                        break
1102                        ;;
1103                -*)
1104                        usage
1105                        ;;
1106                *)
1107                        break
1108                        ;;
1109                esac
1110                shift
1111        done
1112
1113        module_list "$@" |
1114        while read mode sha1 stage sm_path
1115        do
1116                die_if_unmatched "$mode"
1117                name=$(module_name "$sm_path") || exit
1118                url=$(git config submodule."$name".url)
1119                displaypath="$prefix$sm_path"
1120                if test "$stage" = U
1121                then
1122                        say "U$sha1 $displaypath"
1123                        continue
1124                fi
1125                if test -z "$url" || ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
1126                then
1127                        say "-$sha1 $displaypath"
1128                        continue;
1129                fi
1130                set_name_rev "$sm_path" "$sha1"
1131                if git diff-files --ignore-submodules=dirty --quiet -- "$sm_path"
1132                then
1133                        say " $sha1 $displaypath$revname"
1134                else
1135                        if test -z "$cached"
1136                        then
1137                                sha1=$(clear_local_git_env; cd "$sm_path" && git rev-parse --verify HEAD)
1138                                set_name_rev "$sm_path" "$sha1"
1139                        fi
1140                        say "+$sha1 $displaypath$revname"
1141                fi
1142
1143                if test -n "$recursive"
1144                then
1145                        (
1146                                prefix="$displaypath/"
1147                                clear_local_git_env
1148                                cd "$sm_path" &&
1149                                eval cmd_status
1150                        ) ||
1151                        die "$(eval_gettext "Failed to recurse into submodule path '\$sm_path'")"
1152                fi
1153        done
1154}
1155#
1156# Sync remote urls for submodules
1157# This makes the value for remote.$remote.url match the value
1158# specified in .gitmodules.
1159#
1160cmd_sync()
1161{
1162        while test $# -ne 0
1163        do
1164                case "$1" in
1165                -q|--quiet)
1166                        GIT_QUIET=1
1167                        shift
1168                        ;;
1169                --recursive)
1170                        recursive=1
1171                        shift
1172                        ;;
1173                --)
1174                        shift
1175                        break
1176                        ;;
1177                -*)
1178                        usage
1179                        ;;
1180                *)
1181                        break
1182                        ;;
1183                esac
1184        done
1185        cd_to_toplevel
1186        module_list "$@" |
1187        while read mode sha1 stage sm_path
1188        do
1189                die_if_unmatched "$mode"
1190                name=$(module_name "$sm_path")
1191                url=$(git config -f .gitmodules --get submodule."$name".url)
1192
1193                # Possibly a url relative to parent
1194                case "$url" in
1195                ./*|../*)
1196                        # rewrite foo/bar as ../.. to find path from
1197                        # submodule work tree to superproject work tree
1198                        up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" &&
1199                        # guarantee a trailing /
1200                        up_path=${up_path%/}/ &&
1201                        # path from submodule work tree to submodule origin repo
1202                        sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
1203                        # path from superproject work tree to submodule origin repo
1204                        super_config_url=$(resolve_relative_url "$url") || exit
1205                        ;;
1206                *)
1207                        sub_origin_url="$url"
1208                        super_config_url="$url"
1209                        ;;
1210                esac
1211
1212                if git config "submodule.$name.url" >/dev/null 2>/dev/null
1213                then
1214                        say "$(eval_gettext "Synchronizing submodule url for '\$prefix\$sm_path'")"
1215                        git config submodule."$name".url "$super_config_url"
1216
1217                        if test -e "$sm_path"/.git
1218                        then
1219                        (
1220                                clear_local_git_env
1221                                cd "$sm_path"
1222                                remote=$(get_default_remote)
1223                                git config remote."$remote".url "$sub_origin_url"
1224
1225                                if test -n "$recursive"
1226                                then
1227                                        prefix="$prefix$sm_path/"
1228                                        eval cmd_sync
1229                                fi
1230                        )
1231                        fi
1232                fi
1233        done
1234}
1235
1236# This loop parses the command line arguments to find the
1237# subcommand name to dispatch.  Parsing of the subcommand specific
1238# options are primarily done by the subcommand implementations.
1239# Subcommand specific options such as --branch and --cached are
1240# parsed here as well, for backward compatibility.
1241
1242while test $# != 0 && test -z "$command"
1243do
1244        case "$1" in
1245        add | foreach | init | deinit | update | status | summary | sync)
1246                command=$1
1247                ;;
1248        -q|--quiet)
1249                GIT_QUIET=1
1250                ;;
1251        -b|--branch)
1252                case "$2" in
1253                '')
1254                        usage
1255                        ;;
1256                esac
1257                branch="$2"; shift
1258                ;;
1259        --cached)
1260                cached="$1"
1261                ;;
1262        --)
1263                break
1264                ;;
1265        -*)
1266                usage
1267                ;;
1268        *)
1269                break
1270                ;;
1271        esac
1272        shift
1273done
1274
1275# No command word defaults to "status"
1276if test -z "$command"
1277then
1278    if test $# = 0
1279    then
1280        command=status
1281    else
1282        usage
1283    fi
1284fi
1285
1286# "-b branch" is accepted only by "add"
1287if test -n "$branch" && test "$command" != add
1288then
1289        usage
1290fi
1291
1292# "--cached" is accepted only by "status" and "summary"
1293if test -n "$cached" && test "$command" != status -a "$command" != summary
1294then
1295        usage
1296fi
1297
1298"cmd_$command" "$@"