submodule: fix sync handling of some relative superproject origin URLs

When the origin URL of the superproject is itself relative, git submodule sync configures the remote.origin.url configuration property of the submodule with a path that is relative to the work tree of the superproject rather than the work tree of the submodule. To fix this an 'up_path' that navigates from the work tree of the submodule to the work tree of the superproject needs to be prepended to the URL otherwise calculated. Correct handling of superproject origin URLs like foo, ./foo and ./foo/bar is left to a subsequent patch since an additional change is required to handle these cases. The documentation of resolve_relative_url() is expanded to give a more thorough description of the function's objective. Signed-off-by: Jon Seymour <jon.seymour@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jon Seymour committed Jun 6, 2012 at 21:57 UTC 967b2c66738fe6b168ead0c3106ac47fb9ae22c7
2 files changed +47 -9
git-submodule.sh
+43 -5
@@ -30,7 +30,22 @@ nofetch=
30 update=
31 prefix=
32
33 -# Resolve relative url by appending to parent's url
33 +# The function takes at most 2 arguments. The first argument is the
34 +# URL that navigates to the submodule origin repo. When relative, this URL
35 +# is relative to the superproject origin URL repo. The second up_path
36 +# argument, if specified, is the relative path that navigates
37 +# from the submodule working tree to the superproject working tree.
38 +#
39 +# The output of the function is the origin URL of the submodule.
40 +#
41 +# The output will either be an absolute URL or filesystem path (if the
42 +# superproject origin URL is an absolute URL or filesystem path,
43 +# respectively) or a relative file system path (if the superproject
44 +# origin URL is a relative file system path).
45 +#
46 +# When the output is a relative file system path, the path is either
47 +# relative to the submodule working tree, if up_path is specified, or to
48 +# the superproject working tree otherwise.
49 resolve_relative_url ()
50 {
51 remote=$(get_default_remote)
@@ -39,6 +54,17 @@ resolve_relative_url ()
54 url="$1"
55 remoteurl=${remoteurl%/}
56 sep=/
57 + up_path="$2"
58 +
59 + case "$remoteurl" in
60 + *:*|/*)
61 + is_relative=
62 + ;;
63 + *)
64 + is_relative=t
65 + ;;
66 + esac
67 +
68 while test -n "$url"
69 do
70 case "$url" in
@@ -64,7 +90,7 @@ resolve_relative_url ()
90 break;;
91 esac
92 done
67 - echo "$remoteurl$sep${url%/}"
93 + echo "${is_relative:+${up_path}}$remoteurl$sep${url%/}"
94 }
95
96 #
@@ -964,14 +990,26 @@ cmd_sync()
990 # Possibly a url relative to parent
991 case "$url" in
992 ./*|../*)
967 - url=$(resolve_relative_url "$url") || exit
993 + # rewrite foo/bar as ../.. to find path from
994 + # submodule work tree to superproject work tree
995 + up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" &&
996 + # guarantee a trailing /
997 + up_path=${up_path%/}/ &&
998 + # path from submodule work tree to submodule origin repo
999 + sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
1000 + # path from superproject work tree to submodule origin repo
1001 + super_config_url=$(resolve_relative_url "$url") || exit
1002 + ;;
1003 + *)
1004 + sub_origin_url="$url"
1005 + super_config_url="$url"
1006 ;;
1007 esac
1008
1009 if git config "submodule.$name.url" >/dev/null 2>/dev/null
1010 then
1011 say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
974 - git config submodule."$name".url "$url"
1012 + git config submodule."$name".url "$super_config_url"
1013
1014 if test -e "$sm_path"/.git
1015 then
@@ -979,7 +1017,7 @@ cmd_sync()
1017 clear_local_git_env
1018 cd "$sm_path"
1019 remote=$(get_default_remote)
982 - git config remote."$remote".url "$url"
1020 + git config remote."$remote".url "$sub_origin_url"
1021 )
1022 fi
1023 fi
t/t7403-submodule-sync.sh
+4 -4
@@ -99,7 +99,7 @@ test_expect_failure '"git submodule sync" handles origin URL of the form foo' '
99 )
100 '
101
102 -test_expect_failure '"git submodule sync" handles origin URL of the form foo/bar' '
102 +test_expect_success '"git submodule sync" handles origin URL of the form foo/bar' '
103 (cd relative-clone &&
104 git remote set-url origin foo/bar &&
105 git submodule sync &&
@@ -132,7 +132,7 @@ test_expect_failure '"git submodule sync" handles origin URL of the form ./foo/b
132 )
133 '
134
135 -test_expect_failure '"git submodule sync" handles origin URL of the form ../foo' '
135 +test_expect_success '"git submodule sync" handles origin URL of the form ../foo' '
136 (cd relative-clone &&
137 git remote set-url origin ../foo &&
138 git submodule sync &&
@@ -143,7 +143,7 @@ test_expect_failure '"git submodule sync" handles origin URL of the form ../foo'
143 )
144 '
145
146 -test_expect_failure '"git submodule sync" handles origin URL of the form ../foo/bar' '
146 +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar' '
147 (cd relative-clone &&
148 git remote set-url origin ../foo/bar &&
149 git submodule sync &&
@@ -154,7 +154,7 @@ test_expect_failure '"git submodule sync" handles origin URL of the form ../foo/
154 )
155 '
156
157 -test_expect_failure '"git submodule sync" handles origin URL of the form ../foo/bar with deeply nested submodule' '
157 +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar with deeply nested submodule' '
158 (cd relative-clone &&
159 git remote set-url origin ../foo/bar &&
160 mkdir -p a/b/c &&