Merge branch 'hv/submodule-path-unmatch'
authorJunio C Hamano <gitster@pobox.com>
Wed, 29 Aug 2012 21:50:15 +0000 (14:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 29 Aug 2012 21:50:15 +0000 (14:50 -0700)
* hv/submodule-path-unmatch:
Let submodule command exit with error status if path does not exist

1  2 
git-submodule.sh
t/t7400-submodule-basic.sh
diff --combined git-submodule.sh
index aac575e74f833c9bce28b779733b28a7611246b2,dd3ae0e1a0f52118933a64a49f85652e87a0fb3e..08405249edfedba744a36e9e653320b0948b2746
@@@ -30,22 -30,7 +30,22 @@@ nofetch
  update=
  prefix=
  
 -# Resolve relative url by appending to parent's url
 +# The function takes at most 2 arguments. The first argument is the
 +# URL that navigates to the submodule origin repo. When relative, this URL
 +# is relative to the superproject origin URL repo. The second up_path
 +# argument, if specified, is the relative path that navigates
 +# from the submodule working tree to the superproject working tree.
 +#
 +# The output of the function is the origin URL of the submodule.
 +#
 +# The output will either be an absolute URL or filesystem path (if the
 +# superproject origin URL is an absolute URL or filesystem path,
 +# respectively) or a relative file system path (if the superproject
 +# origin URL is a relative file system path).
 +#
 +# When the output is a relative file system path, the path is either
 +# relative to the submodule working tree, if up_path is specified, or to
 +# the superproject working tree otherwise.
  resolve_relative_url ()
  {
        remote=$(get_default_remote)
        url="$1"
        remoteurl=${remoteurl%/}
        sep=/
 +      up_path="$2"
 +
 +      case "$remoteurl" in
 +      *:*|/*)
 +              is_relative=
 +              ;;
 +      ./*|../*)
 +              is_relative=t
 +              ;;
 +      *)
 +              is_relative=t
 +              remoteurl="./$remoteurl"
 +              ;;
 +      esac
 +
        while test -n "$url"
        do
                case "$url" in
                                sep=:
                                ;;
                        *)
 -                              die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
 +                              if test -z "$is_relative" || test "." = "$remoteurl"
 +                              then
 +                                      die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
 +                              else
 +                                      remoteurl=.
 +                              fi
                                ;;
                        esac
                        ;;
@@@ -99,8 -64,7 +99,8 @@@
                        break;;
                esac
        done
 -      echo "$remoteurl$sep${url%/}"
 +      remoteurl="$remoteurl$sep${url%/}"
 +      echo "${is_relative:+${up_path}}${remoteurl#./}"
  }
  
  #
  #
  module_list()
  {
-       git ls-files --error-unmatch --stage -- "$@" |
+       (
+               git ls-files --error-unmatch --stage -- "$@" ||
+               echo "unmatched pathspec exists"
+       ) |
        perl -e '
        my %unmerged = ();
        my ($null_sha1) = ("0" x 40);
+       my @out = ();
+       my $unmatched = 0;
        while (<STDIN>) {
+               if (/^unmatched pathspec/) {
+                       $unmatched = 1;
+                       next;
+               }
                chomp;
                my ($mode, $sha1, $stage, $path) =
                        /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/;
                next unless $mode eq "160000";
                if ($stage ne "0") {
                        if (!$unmerged{$path}++) {
-                               print "$mode $null_sha1 U\t$path\n";
+                               push @out, "$mode $null_sha1 U\t$path\n";
                        }
                        next;
                }
-               print "$_\n";
+               push @out, "$_\n";
+       }
+       if ($unmatched) {
+               print "#unmatched\n";
+       } else {
+               print for (@out);
        }
        '
  }
  
+ die_if_unmatched ()
+ {
+       if test "$1" = "#unmatched"
+       then
+               exit 1
+       fi
+ }
  #
  # Map submodule path to submodule name
  #
@@@ -181,11 -167,8 +203,11 @@@ module_clone(
                rm -f "$gitdir/index"
        else
                mkdir -p "$gitdir_base"
 -              git clone $quiet -n ${reference:+"$reference"} \
 -                      --separate-git-dir "$gitdir" "$url" "$sm_path" ||
 +              (
 +                      clear_local_git_env
 +                      git clone $quiet -n ${reference:+"$reference"} \
 +                              --separate-git-dir "$gitdir" "$url" "$sm_path"
 +              ) ||
                die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")"
        fi
  
@@@ -385,6 -368,7 +407,7 @@@ cmd_foreach(
        module_list |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test -e "$sm_path"/.git
                then
                        say "$(eval_gettext "Entering '\$prefix\$sm_path'")"
@@@ -437,6 -421,7 +460,7 @@@ cmd_init(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
  
                # Copy url setting when it is not set yet
@@@ -537,6 -522,7 +561,7 @@@ cmd_update(
        err=
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test "$stage" = U
                then
                        echo >&2 "Skipping unmerged submodule $sm_path"
@@@ -751,7 -737,7 +776,7 @@@ cmd_summary() 
        if [ -n "$files" ]
        then
                test -n "$cached" &&
 -              die "$(gettext -- "--cached cannot be used with --files")"
 +              die "$(gettext "The --cached option cannot be used with the --files option")"
                diff_cmd=diff-files
                head=
        fi
@@@ -932,6 -918,7 +957,7 @@@ cmd_status(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
                displaypath="$prefix$sm_path"
@@@ -1000,32 -987,21 +1026,33 @@@ cmd_sync(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path")
                url=$(git config -f .gitmodules --get submodule."$name".url)
  
                # Possibly a url relative to parent
                case "$url" in
                ./*|../*)
 -                      url=$(resolve_relative_url "$url") || exit
 +                      # rewrite foo/bar as ../.. to find path from
 +                      # submodule work tree to superproject work tree
 +                      up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" &&
 +                      # guarantee a trailing /
 +                      up_path=${up_path%/}/ &&
 +                      # path from submodule work tree to submodule origin repo
 +                      sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
 +                      # path from superproject work tree to submodule origin repo
 +                      super_config_url=$(resolve_relative_url "$url") || exit
 +                      ;;
 +              *)
 +                      sub_origin_url="$url"
 +                      super_config_url="$url"
                        ;;
                esac
  
                if git config "submodule.$name.url" >/dev/null 2>/dev/null
                then
                        say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
 -                      git config submodule."$name".url "$url"
 +                      git config submodule."$name".url "$super_config_url"
  
                        if test -e "$sm_path"/.git
                        then
                                clear_local_git_env
                                cd "$sm_path"
                                remote=$(get_default_remote)
 -                              git config remote."$remote".url "$url"
 +                              git config remote."$remote".url "$sub_origin_url"
                        )
                        fi
                fi
index c73bec9551eb27dab25aad69c83ae7ce9f9b11a8,0278f48396e0d22d434b421b2f74cf05244a17a3..56a81cd7486716897cc4f08196d0815a62461ffd
@@@ -258,6 -258,27 +258,27 @@@ test_expect_success 'init should regist
        test_cmp expect url
  '
  
+ test_failure_with_unknown_submodule () {
+       test_must_fail git submodule $1 no-such-submodule 2>output.err &&
+       grep "^error: .*no-such-submodule" output.err
+ }
+ test_expect_success 'init should fail with unknown submodule' '
+       test_failure_with_unknown_submodule init
+ '
+ test_expect_success 'update should fail with unknown submodule' '
+       test_failure_with_unknown_submodule update
+ '
+ test_expect_success 'status should fail with unknown submodule' '
+       test_failure_with_unknown_submodule status
+ '
+ test_expect_success 'sync should fail with unknown submodule' '
+       test_failure_with_unknown_submodule sync
+ '
  test_expect_success 'update should fail when path is used by a file' '
        echo hello >expect &&
  
@@@ -418,10 -439,7 +439,7 @@@ test_expect_success 'moving to a commi
  '
  
  test_expect_success 'submodule <invalid-path> warns' '
-       git submodule no-such-submodule 2> output.err &&
-       grep "^error: .*no-such-submodule" output.err
+       test_failure_with_unknown_submodule
  '
  
  test_expect_success 'add submodules without specifying an explicit path' '
@@@ -483,72 -501,21 +501,72 @@@ test_expect_success 'set up for relativ
                git add sub &&
                git config -f .gitmodules submodule.sub.path sub &&
                git config -f .gitmodules submodule.sub.url ../subrepo &&
 -              cp .git/config pristine-.git-config
 +              cp .git/config pristine-.git-config &&
 +              cp .gitmodules pristine-.gitmodules
        )
  '
  
 -test_expect_success 'relative path works with URL' '
 +test_expect_success '../subrepo works with URL - ssh://hostname/repo' '
        (
                cd reltest &&
                cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
                git config remote.origin.url ssh://hostname/repo &&
                git submodule init &&
                test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
        )
  '
  
 -test_expect_success 'relative path works with user@host:path' '
 +test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ssh://hostname:22/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo
 +      )
 +'
 +
 +# About the choice of the path in the next test:
 +# - double-slash side-steps path mangling issues on Windows
 +# - it is still an absolute local path
 +# - there cannot be a server with a blank in its name just in case the
 +#   path is used erroneously to access a //server/share style path
 +test_expect_success '../subrepo path works with local path - //somewhere else/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url "//somewhere else/repo" &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = "//somewhere else/subrepo"
 +      )
 +'
 +
 +test_expect_success '../subrepo works with file URL - file:///tmp/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url file:///tmp/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = file:///tmp/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url helper:://hostname/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = helper:://hostname/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with scp-style URL - user@host:repo' '
        (
                cd reltest &&
                cp pristine-.git-config .git/config &&
        )
  '
  
 +test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url user@host:path/to/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = user@host:path/to/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - foo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url foo &&
 +              # actual: fails with an error
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - foo/bar' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url foo/bar &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = foo/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ./foo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ./foo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ./foo/bar' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ./foo/bar &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = foo/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ../foo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ../foo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = ../subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ../foo/bar' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ../foo/bar &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = ../foo/subrepo
 +      )
 +'
 +
 +test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              mkdir -p a/b/c &&
 +              (cd a/b/c; git init) &&
 +              git config remote.origin.url ../foo/bar.git &&
 +              git submodule add ../bar/a/b/c ./a/b/c &&
 +              git submodule init &&
 +              test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c
 +      )
 +'
 +
  test_expect_success 'moving the superproject does not break submodules' '
        (
                cd addtest &&