git-submodule.shon commit git submodule foreach: Add --recursive to recurse into nested submodules (15fc56a)
   1#!/bin/sh
   2#
   3# git-submodules.sh: add, init, update or list git submodules
   4#
   5# Copyright (c) 2007 Lars Hjemli
   6
   7dashless=$(basename "$0" | sed -e 's/-/ /')
   8USAGE="[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path>
   9   or: $dashless [--quiet] status [--cached] [--] [<path>...]
  10   or: $dashless [--quiet] init [--] [<path>...]
  11   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--] [<path>...]
  12   or: $dashless [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...]
  13   or: $dashless [--quiet] foreach [--recursive] <command>
  14   or: $dashless [--quiet] sync [--] [<path>...]"
  15OPTIONS_SPEC=
  16. git-sh-setup
  17. git-parse-remote
  18require_work_tree
  19
  20command=
  21branch=
  22reference=
  23cached=
  24nofetch=
  25update=
  26prefix=
  27
  28# Resolve relative url by appending to parent's url
  29resolve_relative_url ()
  30{
  31        remote=$(get_default_remote)
  32        remoteurl=$(git config "remote.$remote.url") ||
  33                die "remote ($remote) does not have a url defined in .git/config"
  34        url="$1"
  35        remoteurl=${remoteurl%/}
  36        while test -n "$url"
  37        do
  38                case "$url" in
  39                ../*)
  40                        url="${url#../}"
  41                        remoteurl="${remoteurl%/*}"
  42                        ;;
  43                ./*)
  44                        url="${url#./}"
  45                        ;;
  46                *)
  47                        break;;
  48                esac
  49        done
  50        echo "$remoteurl/${url%/}"
  51}
  52
  53#
  54# Get submodule info for registered submodules
  55# $@ = path to limit submodule list
  56#
  57module_list()
  58{
  59        git ls-files --error-unmatch --stage -- "$@" | grep '^160000 '
  60}
  61
  62#
  63# Map submodule path to submodule name
  64#
  65# $1 = path
  66#
  67module_name()
  68{
  69        # Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
  70        re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
  71        name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
  72                sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
  73       test -z "$name" &&
  74       die "No submodule mapping found in .gitmodules for path '$path'"
  75       echo "$name"
  76}
  77
  78#
  79# Clone a submodule
  80#
  81# Prior to calling, cmd_update checks that a possibly existing
  82# path is not a git repository.
  83# Likewise, cmd_add checks that path does not exist at all,
  84# since it is the location of a new submodule.
  85#
  86module_clone()
  87{
  88        path=$1
  89        url=$2
  90        reference="$3"
  91
  92        # If there already is a directory at the submodule path,
  93        # expect it to be empty (since that is the default checkout
  94        # action) and try to remove it.
  95        # Note: if $path is a symlink to a directory the test will
  96        # succeed but the rmdir will fail. We might want to fix this.
  97        if test -d "$path"
  98        then
  99                rmdir "$path" 2>/dev/null ||
 100                die "Directory '$path' exist, but is neither empty nor a git repository"
 101        fi
 102
 103        test -e "$path" &&
 104        die "A file already exist at path '$path'"
 105
 106        if test -n "$reference"
 107        then
 108                git-clone "$reference" -n "$url" "$path"
 109        else
 110                git-clone -n "$url" "$path"
 111        fi ||
 112        die "Clone of '$url' into submodule path '$path' failed"
 113}
 114
 115#
 116# Add a new submodule to the working tree, .gitmodules and the index
 117#
 118# $@ = repo path
 119#
 120# optional branch is stored in global branch variable
 121#
 122cmd_add()
 123{
 124        # parse $args after "submodule ... add".
 125        while test $# -ne 0
 126        do
 127                case "$1" in
 128                -b | --branch)
 129                        case "$2" in '') usage ;; esac
 130                        branch=$2
 131                        shift
 132                        ;;
 133                -q|--quiet)
 134                        GIT_QUIET=1
 135                        ;;
 136                --reference)
 137                        case "$2" in '') usage ;; esac
 138                        reference="--reference=$2"
 139                        shift
 140                        ;;
 141                --reference=*)
 142                        reference="$1"
 143                        shift
 144                        ;;
 145                --)
 146                        shift
 147                        break
 148                        ;;
 149                -*)
 150                        usage
 151                        ;;
 152                *)
 153                        break
 154                        ;;
 155                esac
 156                shift
 157        done
 158
 159        repo=$1
 160        path=$2
 161
 162        if test -z "$repo" -o -z "$path"; then
 163                usage
 164        fi
 165
 166        # assure repo is absolute or relative to parent
 167        case "$repo" in
 168        ./*|../*)
 169                # dereference source url relative to parent's url
 170                realrepo=$(resolve_relative_url "$repo") || exit
 171                ;;
 172        *:*|/*)
 173                # absolute url
 174                realrepo=$repo
 175                ;;
 176        *)
 177                die "repo URL: '$repo' must be absolute or begin with ./|../"
 178        ;;
 179        esac
 180
 181        # normalize path:
 182        # multiple //; leading ./; /./; /../; trailing /
 183        path=$(printf '%s/\n' "$path" |
 184                sed -e '
 185                        s|//*|/|g
 186                        s|^\(\./\)*||
 187                        s|/\./|/|g
 188                        :start
 189                        s|\([^/]*\)/\.\./||
 190                        tstart
 191                        s|/*$||
 192                ')
 193        git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
 194        die "'$path' already exists in the index"
 195
 196        # perhaps the path exists and is already a git repo, else clone it
 197        if test -e "$path"
 198        then
 199                if test -d "$path"/.git -o -f "$path"/.git
 200                then
 201                        echo "Adding existing repo at '$path' to the index"
 202                else
 203                        die "'$path' already exists and is not a valid git repo"
 204                fi
 205
 206                case "$repo" in
 207                ./*|../*)
 208                        url=$(resolve_relative_url "$repo") || exit
 209                    ;;
 210                *)
 211                        url="$repo"
 212                        ;;
 213                esac
 214                git config submodule."$path".url "$url"
 215        else
 216
 217                module_clone "$path" "$realrepo" "$reference" || exit
 218                (
 219                        unset GIT_DIR
 220                        cd "$path" &&
 221                        # ash fails to wordsplit ${branch:+-b "$branch"...}
 222                        case "$branch" in
 223                        '') git checkout -f -q ;;
 224                        ?*) git checkout -f -q -b "$branch" "origin/$branch" ;;
 225                        esac
 226                ) || die "Unable to checkout submodule '$path'"
 227        fi
 228
 229        git add "$path" ||
 230        die "Failed to add submodule '$path'"
 231
 232        git config -f .gitmodules submodule."$path".path "$path" &&
 233        git config -f .gitmodules submodule."$path".url "$repo" &&
 234        git add .gitmodules ||
 235        die "Failed to register submodule '$path'"
 236}
 237
 238#
 239# Execute an arbitrary command sequence in each checked out
 240# submodule
 241#
 242# $@ = command to execute
 243#
 244cmd_foreach()
 245{
 246        # parse $args after "submodule ... foreach".
 247        while test $# -ne 0
 248        do
 249                case "$1" in
 250                -q|--quiet)
 251                        GIT_QUIET=1
 252                        ;;
 253                --recursive)
 254                        recursive=1
 255                        ;;
 256                -*)
 257                        usage
 258                        ;;
 259                *)
 260                        break
 261                        ;;
 262                esac
 263                shift
 264        done
 265
 266        module_list |
 267        while read mode sha1 stage path
 268        do
 269                if test -e "$path"/.git
 270                then
 271                        say "Entering '$prefix$path'"
 272                        name=$(module_name "$path")
 273                        (
 274                                prefix="$prefix$path/"
 275                                unset GIT_DIR
 276                                cd "$path" &&
 277                                eval "$@" &&
 278                                if test -n "$recursive"
 279                                then
 280                                        cmd_foreach "--recursive" "$@"
 281                                fi
 282                        ) ||
 283                        die "Stopping at '$path'; script returned non-zero status."
 284                fi
 285        done
 286}
 287
 288#
 289# Register submodules in .git/config
 290#
 291# $@ = requested paths (default to all)
 292#
 293cmd_init()
 294{
 295        # parse $args after "submodule ... init".
 296        while test $# -ne 0
 297        do
 298                case "$1" in
 299                -q|--quiet)
 300                        GIT_QUIET=1
 301                        ;;
 302                --)
 303                        shift
 304                        break
 305                        ;;
 306                -*)
 307                        usage
 308                        ;;
 309                *)
 310                        break
 311                        ;;
 312                esac
 313                shift
 314        done
 315
 316        module_list "$@" |
 317        while read mode sha1 stage path
 318        do
 319                # Skip already registered paths
 320                name=$(module_name "$path") || exit
 321                url=$(git config submodule."$name".url)
 322                test -z "$url" || continue
 323
 324                url=$(git config -f .gitmodules submodule."$name".url)
 325                test -z "$url" &&
 326                die "No url found for submodule path '$path' in .gitmodules"
 327
 328                # Possibly a url relative to parent
 329                case "$url" in
 330                ./*|../*)
 331                        url=$(resolve_relative_url "$url") || exit
 332                        ;;
 333                esac
 334
 335                git config submodule."$name".url "$url" ||
 336                die "Failed to register url for submodule path '$path'"
 337
 338                upd="$(git config -f .gitmodules submodule."$name".update)"
 339                test -z "$upd" ||
 340                git config submodule."$name".update "$upd" ||
 341                die "Failed to register update mode for submodule path '$path'"
 342
 343                say "Submodule '$name' ($url) registered for path '$path'"
 344        done
 345}
 346
 347#
 348# Update each submodule path to correct revision, using clone and checkout as needed
 349#
 350# $@ = requested paths (default to all)
 351#
 352cmd_update()
 353{
 354        # parse $args after "submodule ... update".
 355        while test $# -ne 0
 356        do
 357                case "$1" in
 358                -q|--quiet)
 359                        shift
 360                        GIT_QUIET=1
 361                        ;;
 362                -i|--init)
 363                        init=1
 364                        shift
 365                        ;;
 366                -N|--no-fetch)
 367                        shift
 368                        nofetch=1
 369                        ;;
 370                -r|--rebase)
 371                        shift
 372                        update="rebase"
 373                        ;;
 374                --reference)
 375                        case "$2" in '') usage ;; esac
 376                        reference="--reference=$2"
 377                        shift 2
 378                        ;;
 379                --reference=*)
 380                        reference="$1"
 381                        shift
 382                        ;;
 383                -m|--merge)
 384                        shift
 385                        update="merge"
 386                        ;;
 387                --)
 388                        shift
 389                        break
 390                        ;;
 391                -*)
 392                        usage
 393                        ;;
 394                *)
 395                        break
 396                        ;;
 397                esac
 398        done
 399
 400        if test -n "$init"
 401        then
 402                cmd_init "--" "$@" || return
 403        fi
 404
 405        module_list "$@" |
 406        while read mode sha1 stage path
 407        do
 408                name=$(module_name "$path") || exit
 409                url=$(git config submodule."$name".url)
 410                update_module=$(git config submodule."$name".update)
 411                if test -z "$url"
 412                then
 413                        # Only mention uninitialized submodules when its
 414                        # path have been specified
 415                        test "$#" != "0" &&
 416                        say "Submodule path '$path' not initialized" &&
 417                        say "Maybe you want to use 'update --init'?"
 418                        continue
 419                fi
 420
 421                if ! test -d "$path"/.git -o -f "$path"/.git
 422                then
 423                        module_clone "$path" "$url" "$reference"|| exit
 424                        subsha1=
 425                else
 426                        subsha1=$(unset GIT_DIR; cd "$path" &&
 427                                git rev-parse --verify HEAD) ||
 428                        die "Unable to find current revision in submodule path '$path'"
 429                fi
 430
 431                if ! test -z "$update"
 432                then
 433                        update_module=$update
 434                fi
 435
 436                if test "$subsha1" != "$sha1"
 437                then
 438                        force=
 439                        if test -z "$subsha1"
 440                        then
 441                                force="-f"
 442                        fi
 443
 444                        if test -z "$nofetch"
 445                        then
 446                                (unset GIT_DIR; cd "$path" &&
 447                                        git-fetch) ||
 448                                die "Unable to fetch in submodule path '$path'"
 449                        fi
 450
 451                        case "$update_module" in
 452                        rebase)
 453                                command="git rebase"
 454                                action="rebase"
 455                                msg="rebased onto"
 456                                ;;
 457                        merge)
 458                                command="git merge"
 459                                action="merge"
 460                                msg="merged in"
 461                                ;;
 462                        *)
 463                                command="git checkout $force -q"
 464                                action="checkout"
 465                                msg="checked out"
 466                                ;;
 467                        esac
 468
 469                        (unset GIT_DIR; cd "$path" && $command "$sha1") ||
 470                        die "Unable to $action '$sha1' in submodule path '$path'"
 471                        say "Submodule path '$path': $msg '$sha1'"
 472                fi
 473        done
 474}
 475
 476set_name_rev () {
 477        revname=$( (
 478                unset GIT_DIR
 479                cd "$1" && {
 480                        git describe "$2" 2>/dev/null ||
 481                        git describe --tags "$2" 2>/dev/null ||
 482                        git describe --contains "$2" 2>/dev/null ||
 483                        git describe --all --always "$2"
 484                }
 485        ) )
 486        test -z "$revname" || revname=" ($revname)"
 487}
 488#
 489# Show commit summary for submodules in index or working tree
 490#
 491# If '--cached' is given, show summary between index and given commit,
 492# or between working tree and given commit
 493#
 494# $@ = [commit (default 'HEAD'),] requested paths (default all)
 495#
 496cmd_summary() {
 497        summary_limit=-1
 498        for_status=
 499
 500        # parse $args after "submodule ... summary".
 501        while test $# -ne 0
 502        do
 503                case "$1" in
 504                --cached)
 505                        cached="$1"
 506                        ;;
 507                --for-status)
 508                        for_status="$1"
 509                        ;;
 510                -n|--summary-limit)
 511                        if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
 512                        then
 513                                :
 514                        else
 515                                usage
 516                        fi
 517                        shift
 518                        ;;
 519                --)
 520                        shift
 521                        break
 522                        ;;
 523                -*)
 524                        usage
 525                        ;;
 526                *)
 527                        break
 528                        ;;
 529                esac
 530                shift
 531        done
 532
 533        test $summary_limit = 0 && return
 534
 535        if rev=$(git rev-parse -q --verify "$1^0")
 536        then
 537                head=$rev
 538                shift
 539        else
 540                head=HEAD
 541        fi
 542
 543        cd_to_toplevel
 544        # Get modified modules cared by user
 545        modules=$(git diff-index $cached --raw $head -- "$@" |
 546                egrep '^:([0-7]* )?160000' |
 547                while read mod_src mod_dst sha1_src sha1_dst status name
 548                do
 549                        # Always show modules deleted or type-changed (blob<->module)
 550                        test $status = D -o $status = T && echo "$name" && continue
 551                        # Also show added or modified modules which are checked out
 552                        GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
 553                        echo "$name"
 554                done
 555        )
 556
 557        test -z "$modules" && return
 558
 559        git diff-index $cached --raw $head -- $modules |
 560        egrep '^:([0-7]* )?160000' |
 561        cut -c2- |
 562        while read mod_src mod_dst sha1_src sha1_dst status name
 563        do
 564                if test -z "$cached" &&
 565                        test $sha1_dst = 0000000000000000000000000000000000000000
 566                then
 567                        case "$mod_dst" in
 568                        160000)
 569                                sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
 570                                ;;
 571                        100644 | 100755 | 120000)
 572                                sha1_dst=$(git hash-object $name)
 573                                ;;
 574                        000000)
 575                                ;; # removed
 576                        *)
 577                                # unexpected type
 578                                echo >&2 "unexpected mode $mod_dst"
 579                                continue ;;
 580                        esac
 581                fi
 582                missing_src=
 583                missing_dst=
 584
 585                test $mod_src = 160000 &&
 586                ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
 587                missing_src=t
 588
 589                test $mod_dst = 160000 &&
 590                ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
 591                missing_dst=t
 592
 593                total_commits=
 594                case "$missing_src,$missing_dst" in
 595                t,)
 596                        errmsg="  Warn: $name doesn't contain commit $sha1_src"
 597                        ;;
 598                ,t)
 599                        errmsg="  Warn: $name doesn't contain commit $sha1_dst"
 600                        ;;
 601                t,t)
 602                        errmsg="  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
 603                        ;;
 604                *)
 605                        errmsg=
 606                        total_commits=$(
 607                        if test $mod_src = 160000 -a $mod_dst = 160000
 608                        then
 609                                range="$sha1_src...$sha1_dst"
 610                        elif test $mod_src = 160000
 611                        then
 612                                range=$sha1_src
 613                        else
 614                                range=$sha1_dst
 615                        fi
 616                        GIT_DIR="$name/.git" \
 617                        git log --pretty=oneline --first-parent $range | wc -l
 618                        )
 619                        total_commits=" ($(($total_commits + 0)))"
 620                        ;;
 621                esac
 622
 623                sha1_abbr_src=$(echo $sha1_src | cut -c1-7)
 624                sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)
 625                if test $status = T
 626                then
 627                        if test $mod_dst = 160000
 628                        then
 629                                echo "* $name $sha1_abbr_src(blob)->$sha1_abbr_dst(submodule)$total_commits:"
 630                        else
 631                                echo "* $name $sha1_abbr_src(submodule)->$sha1_abbr_dst(blob)$total_commits:"
 632                        fi
 633                else
 634                        echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
 635                fi
 636                if test -n "$errmsg"
 637                then
 638                        # Don't give error msg for modification whose dst is not submodule
 639                        # i.e. deleted or changed to blob
 640                        test $mod_dst = 160000 && echo "$errmsg"
 641                else
 642                        if test $mod_src = 160000 -a $mod_dst = 160000
 643                        then
 644                                limit=
 645                                test $summary_limit -gt 0 && limit="-$summary_limit"
 646                                GIT_DIR="$name/.git" \
 647                                git log $limit --pretty='format:  %m %s' \
 648                                --first-parent $sha1_src...$sha1_dst
 649                        elif test $mod_dst = 160000
 650                        then
 651                                GIT_DIR="$name/.git" \
 652                                git log --pretty='format:  > %s' -1 $sha1_dst
 653                        else
 654                                GIT_DIR="$name/.git" \
 655                                git log --pretty='format:  < %s' -1 $sha1_src
 656                        fi
 657                        echo
 658                fi
 659                echo
 660        done |
 661        if test -n "$for_status"; then
 662                echo "# Modified submodules:"
 663                echo "#"
 664                sed -e 's|^|# |' -e 's|^# $|#|'
 665        else
 666                cat
 667        fi
 668}
 669#
 670# List all submodules, prefixed with:
 671#  - submodule not initialized
 672#  + different revision checked out
 673#
 674# If --cached was specified the revision in the index will be printed
 675# instead of the currently checked out revision.
 676#
 677# $@ = requested paths (default to all)
 678#
 679cmd_status()
 680{
 681        # parse $args after "submodule ... status".
 682        while test $# -ne 0
 683        do
 684                case "$1" in
 685                -q|--quiet)
 686                        GIT_QUIET=1
 687                        ;;
 688                --cached)
 689                        cached=1
 690                        ;;
 691                --)
 692                        shift
 693                        break
 694                        ;;
 695                -*)
 696                        usage
 697                        ;;
 698                *)
 699                        break
 700                        ;;
 701                esac
 702                shift
 703        done
 704
 705        module_list "$@" |
 706        while read mode sha1 stage path
 707        do
 708                name=$(module_name "$path") || exit
 709                url=$(git config submodule."$name".url)
 710                if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
 711                then
 712                        say "-$sha1 $path"
 713                        continue;
 714                fi
 715                set_name_rev "$path" "$sha1"
 716                if git diff-files --quiet -- "$path"
 717                then
 718                        say " $sha1 $path$revname"
 719                else
 720                        if test -z "$cached"
 721                        then
 722                                sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
 723                                set_name_rev "$path" "$sha1"
 724                        fi
 725                        say "+$sha1 $path$revname"
 726                fi
 727        done
 728}
 729#
 730# Sync remote urls for submodules
 731# This makes the value for remote.$remote.url match the value
 732# specified in .gitmodules.
 733#
 734cmd_sync()
 735{
 736        while test $# -ne 0
 737        do
 738                case "$1" in
 739                -q|--quiet)
 740                        GIT_QUIET=1
 741                        shift
 742                        ;;
 743                --)
 744                        shift
 745                        break
 746                        ;;
 747                -*)
 748                        usage
 749                        ;;
 750                *)
 751                        break
 752                        ;;
 753                esac
 754        done
 755        cd_to_toplevel
 756        module_list "$@" |
 757        while read mode sha1 stage path
 758        do
 759                name=$(module_name "$path")
 760                url=$(git config -f .gitmodules --get submodule."$name".url)
 761
 762                # Possibly a url relative to parent
 763                case "$url" in
 764                ./*|../*)
 765                        url=$(resolve_relative_url "$url") || exit
 766                        ;;
 767                esac
 768
 769                if test -e "$path"/.git
 770                then
 771                (
 772                        unset GIT_DIR
 773                        cd "$path"
 774                        remote=$(get_default_remote)
 775                        say "Synchronizing submodule url for '$name'"
 776                        git config remote."$remote".url "$url"
 777                )
 778                fi
 779        done
 780}
 781
 782# This loop parses the command line arguments to find the
 783# subcommand name to dispatch.  Parsing of the subcommand specific
 784# options are primarily done by the subcommand implementations.
 785# Subcommand specific options such as --branch and --cached are
 786# parsed here as well, for backward compatibility.
 787
 788while test $# != 0 && test -z "$command"
 789do
 790        case "$1" in
 791        add | foreach | init | update | status | summary | sync)
 792                command=$1
 793                ;;
 794        -q|--quiet)
 795                GIT_QUIET=1
 796                ;;
 797        -b|--branch)
 798                case "$2" in
 799                '')
 800                        usage
 801                        ;;
 802                esac
 803                branch="$2"; shift
 804                ;;
 805        --cached)
 806                cached="$1"
 807                ;;
 808        --)
 809                break
 810                ;;
 811        -*)
 812                usage
 813                ;;
 814        *)
 815                break
 816                ;;
 817        esac
 818        shift
 819done
 820
 821# No command word defaults to "status"
 822test -n "$command" || command=status
 823
 824# "-b branch" is accepted only by "add"
 825if test -n "$branch" && test "$command" != add
 826then
 827        usage
 828fi
 829
 830# "--cached" is accepted only by "status" and "summary"
 831if test -n "$cached" && test "$command" != status -a "$command" != summary
 832then
 833        usage
 834fi
 835
 836"cmd_$command" "$@"