[PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-04-15 Thread Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves.  As these other commands are written in C
already, we'd need the init functionality in C, too.  The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.

To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.

Signed-off-by: Stefan Beller 
Signed-off-by: Junio C Hamano 
---
 builtin/submodule--helper.c | 209 +++-
 git-submodule.sh|  81 +
 t/t0060-path-utils.sh   |  46 ++
 3 files changed, 258 insertions(+), 78 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 864dd18..46946b0 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,211 @@
 #include "submodule-config.h"
 #include "string-list.h"
 #include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+   char *dest = NULL, *ret;
+   unsigned char sha1[20];
+   struct strbuf sb = STRBUF_INIT;
+   const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+
+   if (!refname)
+   die(_("No such ref: %s"), "HEAD");
+
+   /* detached HEAD */
+   if (!strcmp(refname, "HEAD"))
+   return xstrdup("origin");
+
+   if (!skip_prefix(refname, "refs/heads/", ))
+   die(_("Expecting a full ref name, got %s"), refname);
+
+   strbuf_addf(, "branch.%s.remote", refname);
+   if (git_config_get_string(sb.buf, ))
+   ret = xstrdup("origin");
+   else
+   ret = dest;
+
+   strbuf_release();
+   return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+   return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+   return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+   char *rfind = find_last_dir_sep(*remoteurl);
+   if (rfind) {
+   *rfind = '\0';
+   return 0;
+   }
+
+   rfind = strrchr(*remoteurl, ':');
+   if (rfind) {
+   *rfind = '\0';
+   return 1;
+   }
+
+   if (is_relative || !strcmp(".", *remoteurl))
+   die(_("cannot strip one component off url '%s'"),
+   *remoteurl);
+
+   free(*remoteurl);
+   *remoteurl = xstrdup(".");
+   return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url  url  outcome  expectation
+ * http://a.com/b  ../c http://a.com/c   as is
+ * http://a.com/b  ../../c  http://c error out
+ * http://a.com/b  ../../../c   http:/c  error out
+ * http://a.com/b  ../../../../chttp:c   error out
+ * http://a.com/b  ../../../../../c.:c   error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+   const char *url,
+   const char *up_path)
+{
+   int is_relative = 0;
+   int colonsep = 0;
+   char *out;
+   char *remoteurl = xstrdup(remote_url);
+   struct strbuf sb = STRBUF_INIT;
+   size_t len = strlen(remoteurl);
+
+   if (is_dir_sep(remoteurl[len]))
+   remoteurl[len] = '\0';
+
+   if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+   is_relative = 0;
+   else {
+   is_relative = 1;
+   /*
+* Prepend a './' to ensure all relative
+* 

Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-04-14 Thread Stefan Beller
On Thu, Apr 14, 2016 at 12:35 PM, Johannes Sixt  wrote:
> Am 14.04.2016 um 20:18 schrieb Stefan Beller:
>> @@ -298,4 +305,40 @@ test_git_path GIT_COMMON_DIR=bar config 
>>   bar/config
>>   test_git_path GIT_COMMON_DIR=bar packed-refs  bar/packed-refs
>>   test_git_path GIT_COMMON_DIR=bar shallow  bar/shallow
>>
>> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
>> +test_submodule_relative_url "../" "../foo/bar" "../submodule" 
>> "../../foo/submodule"
>> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" 
>> "../../foo/submodule"
>> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "../" "./foo/bar" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" 
>> "../../../../foo/sub/a/b/c"
>> +test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
>> +test_submodule_relative_url "../" "foo/bar" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
>> +
>> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" 
>> "../foo/sub/a/b/c"
>> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" 
>> "foo/submodule"
>> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
>> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" 
>> "//somewhere else/subrepo"
>> +test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" 
>> "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
>> +test_submodule_relative_url "(null)" "$PWD/super_update_r2" 
>> "../subsuper_update_r" "$PWD/subsuper_update_r"
>> +test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
>> +test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
>> +test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
>> +test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
>> +test_submodule_relative_url "(null)" "$PWD/." "../submodule" 
>> "$PWD/submodule"
>> +test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" 
>> "$PWD/submodule"
>> +test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" 
>> "$PWD/home2/../bundle1"
>> +test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." 
>> "$PWD/submodule_update_repo/."
>> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" 
>> "file:///tmp/subrepo"
>> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" 
>> "foo/submodule"
>> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
>> +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" 
>> "helper:://hostname/subrepo"
>> +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" 
>> "ssh://hostname/subrepo"
>> +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" 
>> "ssh://hostname:22/subrepo"
>> +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" 
>> "user@host:path/to/subrepo"
>> +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" 
>> "user@host:subrepo"
>> +
>>   test_done
>>
>
> I am very sorry that I am chiming in again so late. I forgot to mention
> that this requires a fixup on Windows as below. I won't mind to submit
> the fixup as a follow-on patch, but you could also squash it in if yet
> another round is required.

Thanks a lot for testing a patch on Windows!
I'll pick this up in a resend.


>
> diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
> index 579c1fa..1d19fbb 100755
> --- a/t/t0060-path-utils.sh
> +++ b/t/t0060-path-utils.sh
> @@ -293,13 +293,16 @@ test_git_path GIT_COMMON_DIR=bar config 
>   bar/config
>  test_git_path GIT_COMMON_DIR=bar packed-refs  bar/packed-refs
>  test_git_path GIT_COMMON_DIR=bar shallow  bar/shallow
>
> +# In the tests below, the distinction between $PWD and $(pwd) is important:
> +# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).
> +
>  test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
>  test_submodule_relative_url "../" "../foo/bar" "../submodule" 
> "../../foo/submodule"
>  test_submodule_relative_url "../" "../foo/submodule" "../submodule" 
> "../../foo/submodule"
>  test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
>  test_submodule_relative_url "../" "./foo/bar" "../submodule" 
> "../foo/submodule"
>  test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" 
> "../../../../foo/sub/a/b/c"
> -test_submodule_relative_url "../" "$PWD/addtest" 

Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-04-14 Thread Johannes Sixt
Am 14.04.2016 um 20:18 schrieb Stefan Beller:
> @@ -298,4 +305,40 @@ test_git_path GIT_COMMON_DIR=bar config  
>  bar/config
>   test_git_path GIT_COMMON_DIR=bar packed-refs  bar/packed-refs
>   test_git_path GIT_COMMON_DIR=bar shallow  bar/shallow
>   
> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
> +test_submodule_relative_url "../" "../foo/bar" "../submodule" 
> "../../foo/submodule"
> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" 
> "../../foo/submodule"
> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
> +test_submodule_relative_url "../" "./foo/bar" "../submodule" 
> "../foo/submodule"
> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" 
> "../../../../foo/sub/a/b/c"
> +test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
> +test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
> +
> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" 
> "../foo/sub/a/b/c"
> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" 
> "../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" 
> "../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" 
> "foo/submodule"
> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" 
> "//somewhere else/subrepo"
> +test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" 
> "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
> +test_submodule_relative_url "(null)" "$PWD/super_update_r2" 
> "../subsuper_update_r" "$PWD/subsuper_update_r"
> +test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
> +test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
> +test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
> +test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
> +test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
> +test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" 
> "$PWD/submodule"
> +test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" 
> "$PWD/home2/../bundle1"
> +test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." 
> "$PWD/submodule_update_repo/."
> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" 
> "file:///tmp/subrepo"
> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
> +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" 
> "helper:://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" 
> "ssh://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" 
> "ssh://hostname:22/subrepo"
> +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" 
> "user@host:path/to/subrepo"
> +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" 
> "user@host:subrepo"
> +
>   test_done
> 

I am very sorry that I am chiming in again so late. I forgot to mention
that this requires a fixup on Windows as below. I won't mind to submit
the fixup as a follow-on patch, but you could also squash it in if yet
another round is required.

diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 579c1fa..1d19fbb 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -293,13 +293,16 @@ test_git_path GIT_COMMON_DIR=bar config   
bar/config
 test_git_path GIT_COMMON_DIR=bar packed-refs  bar/packed-refs
 test_git_path GIT_COMMON_DIR=bar shallow  bar/shallow
 
+# In the tests below, the distinction between $PWD and $(pwd) is important:
+# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).
+
 test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
 test_submodule_relative_url "../" "../foo/bar" "../submodule" 
"../../foo/submodule"
 test_submodule_relative_url "../" "../foo/submodule" "../submodule" 
"../../foo/submodule"
 test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
 test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
 test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" 
"../../../../foo/sub/a/b/c"
-test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$(pwd)/repo"
 test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
 test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
 
@@ -310,16 +313,16 @@ 

[PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-04-14 Thread Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves.  As these other commands are written in C
already, we'd need the init functionality in C, too.  The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.

To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.

Signed-off-by: Stefan Beller 
Signed-off-by: Junio C Hamano 
---
 builtin/submodule--helper.c | 209 +++-
 git-submodule.sh|  81 +
 t/t0060-path-utils.sh   |  43 +
 3 files changed, 255 insertions(+), 78 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 864dd18..46946b0 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,211 @@
 #include "submodule-config.h"
 #include "string-list.h"
 #include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+   char *dest = NULL, *ret;
+   unsigned char sha1[20];
+   struct strbuf sb = STRBUF_INIT;
+   const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+
+   if (!refname)
+   die(_("No such ref: %s"), "HEAD");
+
+   /* detached HEAD */
+   if (!strcmp(refname, "HEAD"))
+   return xstrdup("origin");
+
+   if (!skip_prefix(refname, "refs/heads/", ))
+   die(_("Expecting a full ref name, got %s"), refname);
+
+   strbuf_addf(, "branch.%s.remote", refname);
+   if (git_config_get_string(sb.buf, ))
+   ret = xstrdup("origin");
+   else
+   ret = dest;
+
+   strbuf_release();
+   return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+   return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+   return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+   char *rfind = find_last_dir_sep(*remoteurl);
+   if (rfind) {
+   *rfind = '\0';
+   return 0;
+   }
+
+   rfind = strrchr(*remoteurl, ':');
+   if (rfind) {
+   *rfind = '\0';
+   return 1;
+   }
+
+   if (is_relative || !strcmp(".", *remoteurl))
+   die(_("cannot strip one component off url '%s'"),
+   *remoteurl);
+
+   free(*remoteurl);
+   *remoteurl = xstrdup(".");
+   return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url  url  outcome  expectation
+ * http://a.com/b  ../c http://a.com/c   as is
+ * http://a.com/b  ../../c  http://c error out
+ * http://a.com/b  ../../../c   http:/c  error out
+ * http://a.com/b  ../../../../chttp:c   error out
+ * http://a.com/b  ../../../../../c.:c   error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+   const char *url,
+   const char *up_path)
+{
+   int is_relative = 0;
+   int colonsep = 0;
+   char *out;
+   char *remoteurl = xstrdup(remote_url);
+   struct strbuf sb = STRBUF_INIT;
+   size_t len = strlen(remoteurl);
+
+   if (is_dir_sep(remoteurl[len]))
+   remoteurl[len] = '\0';
+
+   if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+   is_relative = 0;
+   else {
+   is_relative = 1;
+   /*
+* Prepend a './' to ensure all relative
+* 

[PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-04-12 Thread Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves.  As these other commands are written in C
already, we'd need the init functionality in C, too.  The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.

To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.

Signed-off-by: Stefan Beller 
Signed-off-by: Junio C Hamano 
---
 builtin/submodule--helper.c | 209 +++-
 git-submodule.sh|  81 +
 t/t0060-path-utils.sh   |  43 +
 3 files changed, 255 insertions(+), 78 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a484945..2ab3662 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,211 @@
 #include "submodule-config.h"
 #include "string-list.h"
 #include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+   char *dest = NULL, *ret;
+   unsigned char sha1[20];
+   struct strbuf sb = STRBUF_INIT;
+   const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+
+   if (!refname)
+   die(_("No such ref: %s"), "HEAD");
+
+   /* detached HEAD */
+   if (!strcmp(refname, "HEAD"))
+   return xstrdup("origin");
+
+   if (!skip_prefix(refname, "refs/heads/", ))
+   die(_("Expecting a full ref name, got %s"), refname);
+
+   strbuf_addf(, "branch.%s.remote", refname);
+   if (git_config_get_string(sb.buf, ))
+   ret = xstrdup("origin");
+   else
+   ret = dest;
+
+   strbuf_release();
+   return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+   return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+   return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+   char *rfind = find_last_dir_sep(*remoteurl);
+   if (rfind) {
+   *rfind = '\0';
+   return 0;
+   }
+
+   rfind = strrchr(*remoteurl, ':');
+   if (rfind) {
+   *rfind = '\0';
+   return 1;
+   }
+
+   if (is_relative || !strcmp(".", *remoteurl))
+   die(_("cannot strip one component off url '%s'"),
+   *remoteurl);
+
+   free(*remoteurl);
+   *remoteurl = xstrdup(".");
+   return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url  url  outcome  expectation
+ * http://a.com/b  ../c http://a.com/c   as is
+ * http://a.com/b  ../../c  http://c error out
+ * http://a.com/b  ../../../c   http:/c  error out
+ * http://a.com/b  ../../../../chttp:c   error out
+ * http://a.com/b  ../../../../../c.:c   error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+   const char *url,
+   const char *up_path)
+{
+   int is_relative = 0;
+   int colonsep = 0;
+   char *out;
+   char *remoteurl = xstrdup(remote_url);
+   struct strbuf sb = STRBUF_INIT;
+   size_t len = strlen(remoteurl);
+
+   if (is_dir_sep(remoteurl[len]))
+   remoteurl[len] = '\0';
+
+   if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+   is_relative = 0;
+   else {
+   is_relative = 1;
+   /*
+* Prepend a './' to ensure all relative
+* 

[PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-03-14 Thread Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves.  As these other commands are written in C
already, we'd need the init functionality in C, too.  The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.

To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.

Signed-off-by: Stefan Beller 
Signed-off-by: Junio C Hamano 
---
 builtin/submodule--helper.c | 210 +++-
 git-submodule.sh|  81 +
 t/t0060-path-utils.sh   |  43 +
 3 files changed, 256 insertions(+), 78 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a484945..bc7cf87 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,212 @@
 #include "submodule-config.h"
 #include "string-list.h"
 #include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+   char *dest = NULL, *ret;
+   unsigned char sha1[20];
+   int flag = 0;
+   struct strbuf sb = STRBUF_INIT;
+   const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, );
+
+   if (!refname)
+   die(_("No such ref: %s"), "HEAD");
+
+   /* detached HEAD */
+   if (!strcmp(refname, "HEAD"))
+   return xstrdup("origin");
+
+   if (!skip_prefix(refname, "refs/heads/", ))
+   die(_("Expecting a full ref name, got %s"), refname);
+
+   strbuf_addf(, "branch.%s.remote", refname);
+   if (git_config_get_string(sb.buf, ))
+   ret = xstrdup("origin");
+   else
+   ret = dest;
+
+   strbuf_release();
+   return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+   return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+   return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+   char *rfind = find_last_dir_sep(*remoteurl);
+   if (rfind) {
+   *rfind = '\0';
+   return 0;
+   }
+
+   rfind = strrchr(*remoteurl, ':');
+   if (rfind) {
+   *rfind = '\0';
+   return 1;
+   }
+
+   if (is_relative || !strcmp(".", *remoteurl))
+   die(_("cannot strip one component off url '%s'"),
+   *remoteurl);
+
+   free(*remoteurl);
+   *remoteurl = xstrdup(".");
+   return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url  url  outcome  expectation
+ * http://a.com/b  ../c http://a.com/c   as is
+ * http://a.com/b  ../../c  http://c error out
+ * http://a.com/b  ../../../c   http:/c  error out
+ * http://a.com/b  ../../../../chttp:c   error out
+ * http://a.com/b  ../../../../../c.:c   error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+   const char *url,
+   const char *up_path)
+{
+   int is_relative = 0;
+   int colonsep = 0;
+   char *out;
+   char *remoteurl = xstrdup(remote_url);
+   struct strbuf sb = STRBUF_INIT;
+   size_t len = strlen(remoteurl);
+
+   if (is_dir_sep(remoteurl[len]))
+   remoteurl[len] = '\0';
+
+   if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+   is_relative = 0;
+   else {
+   is_relative = 1;
+   /*
+* Prepend a './' to ensure all relative
+  

Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-03-02 Thread Stefan Beller
On Wed, Mar 2, 2016 at 9:21 AM, Johannes Sixt  wrote:
> Am 13.02.2016 um 00:39 schrieb Stefan Beller:
>> @@ -289,4 +296,39 @@ test_git_path GIT_COMMON_DIR=bar config 
>>   bar/config
>>   test_git_path GIT_COMMON_DIR=bar packed-refs  bar/packed-refs
>>   test_git_path GIT_COMMON_DIR=bar shallow  bar/shallow
>>
>> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" 
>> "../foo/sub/a/b/c"
>> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" 
>> "../../../../foo/sub/a/b/c"
>> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "../" "../foo/bar" "../submodule" 
>> "../../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" 
>> "../../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
>> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" 
>> "foo/submodule"
>> +test_submodule_relative_url "../" "./foo/bar" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
>> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" 
>> "//somewhere else/subrepo"
>> +test_submodule_relative_url "(null)" "/u//trash 
>> directory.t7406-submodule-update/subsuper_update_r" 
>> "../subsubsuper_update_r" "/u//trash 
>> directory.t7406-submodule-update/subsubsuper_update_r"
>> +test_submodule_relative_url "(null)" "/u//trash 
>> directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" 
>> "/u//trash directory.t7406-submodule-update/subsuper_update_r"
>> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." 
>> "/u/trash directory.t3600-rm/."
>> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." 
>> "/u/trash directory.t3600-rm/."
>> +test_submodule_relative_url "(null)" "/u/trash 
>> directory.t7400-submodule-basic/addtest" "../repo" "/u/trash 
>> directory.t7400-submodule-basic/repo"
>> +test_submodule_relative_url "../" "/u/trash 
>> directory.t7400-submodule-basic/addtest" "../repo" "/u/trash 
>> directory.t7400-submodule-basic/repo"
>> +test_submodule_relative_url "(null)" "/u/trash 
>> directory.t7400-submodule-basic" "./å äö" "/u/trash 
>> directory.t7400-submodule-basic/å äö"
>> +test_submodule_relative_url "(null)" "/u/trash 
>> directory.t7403-submodule-sync/." "../submodule" "/u/trash 
>> directory.t7403-submodule-sync/submodule"
>> +test_submodule_relative_url "(null)" "/u/trash 
>> directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash 
>> directory.t7407-submodule-foreach/submodule"
>> +test_submodule_relative_url "(null)" "/u/trash 
>> directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" 
>> "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
>> +test_submodule_relative_url "(null)" "/u/trash 
>> directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash 
>> directory.t7613-merge-submodule/submodule_update_repo/."
>
> The tests with absolute paths all fail on Windows. The reason is that
> git.exe sees mangled paths and 'git submodule--helper
> resolve-relative-url-test' produces mangled paths (that begins with a
> drive letter), whereas the test script expects POSIX paths. The pattern
> I currently use to fix this is
>
> test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"
>
> (In our test scripts, $PWD is a POSIX style path and $(pwd) is a
> Windows style path).
>
> With this change, the penultimate case above still fails because the
> 'home2/..' gets lost somewhere in the actual output, which I still have
> to debug.
>
> The two cases beginning with '/u//' cannot be tested on Windows.
> Are they important? Are the doubled slashes intentional?

The way I got the test cases is by inserting a debug printf into the
shell script
and then running the test suite (as that ought to work correct and
cover everything).

And the double slash is intentional, somewhere in the test suite we have a case
where that occurs. It may be a calling error?

Thanks for looking into this on the Windows side :)

Thanks,
Stefan

>
>> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" 
>> "file:///tmp/subrepo"
>> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" 
>> "foo/submodule"
>> +test_submodule_relative_url "../" "foo/bar" "../submodule" 
>> "../foo/submodule"
>> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
>> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "(null)" "helper:://hostname/repo" 

Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-03-02 Thread Johannes Sixt
Am 13.02.2016 um 00:39 schrieb Stefan Beller:
> @@ -289,4 +296,39 @@ test_git_path GIT_COMMON_DIR=bar config  
>  bar/config
>   test_git_path GIT_COMMON_DIR=bar packed-refs  bar/packed-refs
>   test_git_path GIT_COMMON_DIR=bar shallow  bar/shallow
>   
> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" 
> "../foo/sub/a/b/c"
> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" 
> "../../../../foo/sub/a/b/c"
> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" 
> "../foo/submodule"
> +test_submodule_relative_url "../" "../foo/bar" "../submodule" 
> "../../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" 
> "../foo/submodule"
> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" 
> "../../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" 
> "foo/submodule"
> +test_submodule_relative_url "../" "./foo/bar" "../submodule" 
> "../foo/submodule"
> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" 
> "//somewhere else/subrepo"
> +test_submodule_relative_url "(null)" "/u//trash 
> directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" 
> "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
> +test_submodule_relative_url "(null)" "/u//trash 
> directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" 
> "/u//trash directory.t7406-submodule-update/subsuper_update_r"
> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." 
> "/u/trash directory.t3600-rm/."
> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." 
> "/u/trash directory.t3600-rm/."
> +test_submodule_relative_url "(null)" "/u/trash 
> directory.t7400-submodule-basic/addtest" "../repo" "/u/trash 
> directory.t7400-submodule-basic/repo"
> +test_submodule_relative_url "../" "/u/trash 
> directory.t7400-submodule-basic/addtest" "../repo" "/u/trash 
> directory.t7400-submodule-basic/repo"
> +test_submodule_relative_url "(null)" "/u/trash 
> directory.t7400-submodule-basic" "./å äö" "/u/trash 
> directory.t7400-submodule-basic/å äö"
> +test_submodule_relative_url "(null)" "/u/trash 
> directory.t7403-submodule-sync/." "../submodule" "/u/trash 
> directory.t7403-submodule-sync/submodule"
> +test_submodule_relative_url "(null)" "/u/trash 
> directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash 
> directory.t7407-submodule-foreach/submodule"
> +test_submodule_relative_url "(null)" "/u/trash 
> directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" 
> "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
> +test_submodule_relative_url "(null)" "/u/trash 
> directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash 
> directory.t7613-merge-submodule/submodule_update_repo/."

The tests with absolute paths all fail on Windows. The reason is that
git.exe sees mangled paths and 'git submodule--helper
resolve-relative-url-test' produces mangled paths (that begins with a
drive letter), whereas the test script expects POSIX paths. The pattern
I currently use to fix this is

test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"

(In our test scripts, $PWD is a POSIX style path and $(pwd) is a
Windows style path).

With this change, the penultimate case above still fails because the
'home2/..' gets lost somewhere in the actual output, which I still have
to debug.

The two cases beginning with '/u//' cannot be tested on Windows.
Are they important? Are the doubled slashes intentional?

> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" 
> "file:///tmp/subrepo"
> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
> +test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
> +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" 
> "helper:://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" 
> "ssh://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" 
> "ssh://hostname:22/subrepo"
> +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" 
> "user@host:path/to/subrepo"
> +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" 
> "user@host:subrepo"
> +
>   test_done
> 

--
To unsubscribe from this list: send the line "unsubscribe git" in
the 

Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-02-27 Thread Duy Nguyen
On Fri, Feb 12, 2016 at 03:39:15PM -0800, Stefan Beller wrote:
> Later on we want to automatically call `git submodule init` from
> other commands, such that the users don't have to initialize the
> submodule themselves.  As these other commands are written in C
> already, we'd need the init functionality in C, too.  The
> `resolve_relative_url` function is a large part of that init
> functionality, so start by porting this function to C.
> 
> To create the tests in t0060, the function `resolve_relative_url`
> was temporarily enhanced to write all inputs and output to disk
> when running the test suite. The added tests in this patch are
> a small selection thereof.
> 
> Signed-off-by: Stefan Beller 
> Signed-off-by: Junio C Hamano 
> ---
>  builtin/submodule--helper.c | 208 
> +++-

i18n fixes. Can you squash this patch in when it's re-rolled?

-- 8< --
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f4a0fd7..a6e54fa 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -22,7 +22,7 @@ static char *get_default_remote(void)
const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, );
 
if (!refname)
-   die("No such ref: HEAD");
+   die(_("No such ref: %s"), "HEAD");
 
/* detached HEAD */
if (!strcmp(refname, "HEAD"))
-- 8< --
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-02-18 Thread Junio C Hamano
Stefan Beller  writes:

> +static int starts_with_dot_slash(const char *str)
> +{
> + return str[0] == '.' && is_dir_sep(str[1]);
> +}
> +
> +static int starts_with_dot_dot_slash(const char *str)
> +{
> + return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
> +}
> +
> +/*
> + * Returns 1 if it was the last chop before ':'.
> + */
> +static int chop_last_dir(char **remoteurl, int is_relative)
> +{
> + char *rfind = find_last_dir_sep(*remoteurl);
> + if (rfind) {
> + *rfind = '\0';
> + return 0;
> + }
> +
> + rfind = strrchr(*remoteurl, ':');
> + if (rfind) {
> + *rfind = '\0';
> + return 1;
> + }
> +
> + if (is_relative || !strcmp(".", *remoteurl))
> + die(_("cannot strip one component off url '%s'"),
> + *remoteurl);
> +
> + free(*remoteurl);
> + *remoteurl = xstrdup(".");
> + return 0;
> +}
> +
> +/*
> + * The `url` argument is the URL that navigates to the submodule origin
> + * repo. When relative, this URL is relative to the superproject origin
> + * URL repo. The `up_path` argument, if specified, is the relative
> + * path that navigates from the submodule working tree to the superproject
> + * working tree. Returns the origin URL of the submodule.
> + *
> + * Return either 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.
> + *
> + * NEEDSWORK: This works incorrectly on the domain and protocol part.
> + * remote_url  url  outcome  correct
> + * http://a.com/b  ../c http://a.com/c   yes
> + * http://a.com/b  ../../c  http://c no (domain should be 
> kept)
> + * http://a.com/b  ../../../c   http:/c  no
> + * http://a.com/b  ../../../../chttp:c   no
> + * http://a.com/b  ../../../../../c.:c   no
> + */

Not just "no" but we should say what the expected outcome is.  I
think all of them should error out?

Given how chop_last_dir() works, I think this function is broken
when a local part has a colon in its path component, too.  I do not
think the scripted version did any better on such a URL; just
another thing that NEEDSWORK comment should list as a thing to be
fixed in the future.

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] submodule: port resolve_relative_url from shell to C

2016-02-12 Thread Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves.  As these other commands are written in C
already, we'd need the init functionality in C, too.  The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.

To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.

Signed-off-by: Stefan Beller 
Signed-off-by: Junio C Hamano 
---
 builtin/submodule--helper.c | 208 +++-
 git-submodule.sh|  81 +
 t/t0060-path-utils.sh   |  42 +
 3 files changed, 253 insertions(+), 78 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 65bdc14..d1e9118 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,210 @@
 #include "submodule-config.h"
 #include "string-list.h"
 #include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+   char *dest = NULL, *ret;
+   unsigned char sha1[20];
+   int flag = 0;
+   struct strbuf sb = STRBUF_INIT;
+   const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, );
+
+   if (!refname)
+   die("No such ref: HEAD");
+
+   /* detached HEAD */
+   if (!strcmp(refname, "HEAD"))
+   return xstrdup("origin");
+
+   if (!skip_prefix(refname, "refs/heads/", ))
+   die(_("Expecting a full ref name, got %s"), refname);
+
+   strbuf_addf(, "branch.%s.remote", refname);
+   if (git_config_get_string(sb.buf, ))
+   ret = xstrdup("origin");
+   else
+   ret = dest;
+
+   strbuf_release();
+   return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+   return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+   return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+   char *rfind = find_last_dir_sep(*remoteurl);
+   if (rfind) {
+   *rfind = '\0';
+   return 0;
+   }
+
+   rfind = strrchr(*remoteurl, ':');
+   if (rfind) {
+   *rfind = '\0';
+   return 1;
+   }
+
+   if (is_relative || !strcmp(".", *remoteurl))
+   die(_("cannot strip one component off url '%s'"),
+   *remoteurl);
+
+   free(*remoteurl);
+   *remoteurl = xstrdup(".");
+   return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url  url  outcome  correct
+ * http://a.com/b  ../c http://a.com/c   yes
+ * http://a.com/b  ../../c  http://c no (domain should be kept)
+ * http://a.com/b  ../../../c   http:/c  no
+ * http://a.com/b  ../../../../chttp:c   no
+ * http://a.com/b  ../../../../../c.:c   no
+ */
+static char *relative_url(const char *remote_url,
+   const char *url,
+   const char *up_path)
+{
+   int is_relative = 0;
+   int colonsep = 0;
+   char *out;
+   char *remoteurl = xstrdup(remote_url);
+   struct strbuf sb = STRBUF_INIT;
+   size_t len = strlen(remoteurl);
+
+   if (is_dir_sep(remoteurl[len]))
+   remoteurl[len] = '\0';
+
+   if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+   is_relative = 0;
+   else {
+   is_relative = 1;
+   /*
+* Prepend a './' to ensure all relative
+* remoteurls start with './' or '../'
+*/
+   if (!starts_with_dot_slash(remoteurl) &&
+