git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v5 2/2] submodule: fix handling of relative superproject origin URLs

From
Jon Seymour <jon.seymour@gmail.com>
Date
May 24, 2012, 03:40 UTC
Message-ID
<CAH3AnrpweAah9GojN2QodTx6qW2rHE4wadxbc23zrwj=uPCP-A@mail.gmail.com>
In-Reply-To
<1337830657-16400-3-git-send-email-jon.seymour@gmail.com>
On Thu, May 24, 2012 at 1:37 PM, Jon Seymour <jon.seymour@gmail.com> wrote:
Show 189 quoted lines
> When the origin URL of the superproject is itself relative, an operation
> such as git submodule add, init or sync may result in either the
> submodule.{name}.url configuration property of the superproject
> referring to the incorrect location or remote.origin.url configuration
> property of the submodule referring to the incorrect location or both
> these conditions. In some cases, git submodule fails to update
> the configuration and fails with an error condition.
>
> The issue arises in these cases because the origin URL of
> the superproject needs to be prepended with a prefix that navigates
> from the submodule to the superproject so that when the submodule
> URL is concatenated the resulting URL is relative to the working tree
> of the submodule.
>
> This change fixes handling for relative superproject origin URLs
> for 6 cases:
>  foo
>  foo/bar
>  ./foo
>  ./foo/bar
>  ../foo
>  ../foo/bar
>
> In each case, the configuration properties in the superproject's
> configuration and the submodule's configuration refer to the
> correct, relative, location of the submodule's origin repo. In all cases,
> the configured paths are relative to the working trees of the
> repositories containing the configuration.
>
> Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
> ---
>  git-submodule.sh           | 57 +++++++++++++++++++++++++++++++++++++++++-----
>  t/t7400-submodule-basic.sh |  6 ++---
>  t/t7403-submodule-sync.sh  | 18 +++++----------
>  3 files changed, 59 insertions(+), 22 deletions(-)
>
> diff --git a/git-submodule.sh b/git-submodule.sh
> index 64a70d6..738eba3 100755
> --- a/git-submodule.sh
> +++ b/git-submodule.sh
> @@ -30,13 +30,35 @@ nofetch=
>  update=
>  prefix=
>
> -# Resolve relative url by appending to parent's url
> +# Resolve relative url by appending the submodule url
> +# to the superproject's origin URL
> +#
> +# If the origin URL is itself a relative URL prepend
> +# an additional prefix, if present, that represents
> +# the relative path from the submodule's working tree
> +# to the superprojects' working tree.
> +#
> +# This behaviour is required to ensure that the origin URL
> +# of a submodule, when relative, is relative to the
> +# submodule's work tree and not to the superproject's work tree.
> +#
>  resolve_relative_url ()
>  {
>        remote=$(get_default_remote)
>        remoteurl=$(git config "remote.$remote.url") ||
>                remoteurl=$(pwd) # the repository is its own authoritative upstream
>        url="$1"
> +       up_path="$2"
> +
> +       #
> +       # ensure all relative paths begin with ./ to enable
> +       # selection relative branch of subsequent case "$remoteurl"
> +       # statement.
> +       #
> +       # rewrites foo/bar to ./foo/bar but leaves /foo, :foo ./foo
> +       # and ../foo untouched.
> +       #
> +       remoteurl=$(echo "$remoteurl" | sed "s|^[^/:\\.][^:]*\$|./&|")
>        remoteurl=${remoteurl%/}
>        sep=/
>        while test -n "$url"
> @@ -45,6 +67,16 @@ resolve_relative_url ()
>                ../*)
>                        url="${url#../}"
>                        case "$remoteurl" in
> +                       .*/*)
> +                               # remove last part
> +                               remoteurl="${remoteurl%/*}"
> +                               # remove redundant leading ./
> +                               remoteurl="${remoteurl#./}"
> +                               # prefix path from submodule work tree to superproject work tree
> +                               remoteurl="${up_path}${remoteurl}"
> +                               # remove trailing /.
> +                               remoteurl="${remoteurl%/.}"
> +                               ;;
>                        */*)
>                                remoteurl="${remoteurl%/*}"
>                                ;;
> @@ -959,19 +991,32 @@ cmd_sync()
>        while read mode sha1 stage sm_path
>        do
>                name=$(module_name "$sm_path")
> -               url=$(git config -f .gitmodules --get submodule."$name".url)
> +               # path from superproject origin repo to submodule origin repo
> +               module_url=$(git config -f .gitmodules --get submodule."$name".url)
>
>                # Possibly a url relative to parent
> -               case "$url" in
> +               case "$module_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 "$module_url" "$up_path") &&
> +                       # path from superproject work tree to submodule origin repo
> +                       super_config_url=$(resolve_relative_url "$module_url") || exit
> +                       ;;
> +               *)
> +                       sub_origin_url="$module_url"
> +                       super_config_url="$module_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
> @@ -979,7 +1024,7 @@ cmd_sync()
>                                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
> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
> index 08b8d2f..f2f907f 100755
> --- a/t/t7400-submodule-basic.sh
> +++ b/t/t7400-submodule-basic.sh
> @@ -507,12 +507,11 @@ test_expect_success 'relative path works with user@host:path' '
>        )
>  '
>
> -test_expect_failure 'relative path works with foo' '
> +test_expect_success 'relative path works with foo' '
>        (
>                cd reltest &&
>                cp pristine-.git-config .git/config &&
>                git config remote.origin.url foo &&
> -               # actual: fails with an error
>                git submodule init &&
>                test "$(git config submodule.sub.url)" = ./subrepo
>        )
> @@ -538,13 +537,12 @@ test_expect_success 'relative path works with ./foo' '
>        )
>  '
>
> -test_expect_failure 'relative path works with ./foo/bar' '
> +test_expect_success 'relative path works with ./foo/bar' '
>        (
>                cd reltest &&
>                cp pristine-.git-config .git/config &&
>                git config remote.origin.url ./foo/bar &&
>                git submodule init &&
> -               #actual: ./foo/subrepo
>                test "$(git config submodule.sub.url)" = foo/subrepo
>        )
>  '
> diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
> index 9fa4e58..9526f8d 100755
> --- a/t/t7403-submodule-sync.sh
> +++ b/t/t7403-submodule-sync.sh
> @@ -88,72 +88,66 @@ test_expect_success '"git submodule sync" should not vivify uninteresting submod
>        )
>  '
>
> -test_expect_failure '"git submodule sync" handles origin URL of the form foo' '
> +test_expect_success '"git submodule sync" handles origin URL of the form foo' '
>        (cd relative-clone &&
>         git remote set-url origin foo
>         git submodule sync &&
>        (cd submodule &&
> -        #actual fails with: "cannot strip off url foo
>         git config remote.origin.url &&

Sorry, it appears I left some debug output in the tests. Will roll this into a v6 with any updates you suggest.

Regards,
jon.
Previous: Jon SeymourNext: Phil Hord
Message 4 of 7 in “series: submodule: fix handling of relative superproject origin URLs”
  1. 0/2 series: submodule: fix handling of relative superproject origin URLsJon Seymour, May 24, 2012
  2. 1/2 submodule: document failures handling relative superproject origin URLsJon Seymour, May 24, 2012
  3. 2/2 submodule: fix handling of relative superproject origin URLsJon Seymour, May 24, 2012
  4. Jon SeymourMay 24, 2012
  5. Phil HordMay 24, 2012
  6. Jon SeymourMay 24, 2012
  7. Jon SeymourMay 24, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.