{"thread":{"id":"42043","subject":"[PATCH 0/2] Another reroll of sb/submodule-init","startedAt":"2016-04-16T00:50:11Z","lastAt":"2016-04-18T19:30:15Z","messageCount":4,"participants":["Stefan Beller","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"283632","messageId":"1460767813-25916-1-git-send-email-sbeller@google.com","threadId":"42043","inReplyTo":null,"subject":"[PATCH 0/2] Another reroll of sb/submodule-init","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-16T00:50:11Z","receivedAt":"2016-04-16T00:50:11Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"* squashed the fixes from Johannes Sixt to unbreak Windows tests.\n  (I had encoding issues; so I manually integrated the changes)\n* fixed memleaks\n* the base to apply did not change (ee30f17805f51d37 Merge branch\n'sb/submodule-path-misc-bugs' into sb/submodule-init)\n\nThanks,\nStefan\n\ndiff to current origin/sb/submodule-init:\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex ad3cba6..b6d4f27 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -309,8 +309,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *upd = NULL;\n-\tchar *url = NULL, *displaypath;\n+\tchar *upd = NULL, *url = NULL, *displaypath;\n \n \t/* Only loads from .gitmodules, no overlay with .git/config */\n \tgitmodules_config();\n@@ -340,7 +339,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t\t/* Possibly a url relative to parent */\n \t\tif (starts_with_dot_dot_slash(url) ||\n \t\t    starts_with_dot_slash(url)) {\n-\t\t\tchar *remoteurl;\n+\t\t\tchar *remoteurl, *relurl;\n \t\t\tchar *remote = get_default_remote();\n \t\t\tstruct strbuf remotesb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&remotesb, \"remote.%s.url\", remote);\n@@ -352,9 +351,11 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t\t\t\t * authoritative upstream\n \t\t\t\t */\n \t\t\t\tremoteurl = xgetcwd();\n-\t\t\turl = relative_url(remoteurl, url, NULL);\n+\t\t\trelurl = relative_url(remoteurl, url, NULL);\n \t\t\tstrbuf_release(&remotesb);\n \t\t\tfree(remoteurl);\n+\t\t\tfree(url);\n+\t\t\turl = relurl;\n \t\t}\n \n \t\tif (git_config_set_gently(sb.buf, url))\n@@ -368,14 +369,14 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t/* Copy \"update\" setting when it is not set yet */\n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"submodule.%s.update\", sub->name);\n-\tif (git_config_get_string_const(sb.buf, &upd) &&\n+\tif (git_config_get_string(sb.buf, &upd) &&\n \t    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND) {\n \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n \t\t\t\tsub->name);\n-\t\t\tupd = \"none\";\n+\t\t\tupd = xstrdup(\"none\");\n \t\t} else\n-\t\t\tupd = submodule_strategy_to_string(&sub->update_strategy);\n+\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n \n \t\tif (git_config_set_gently(sb.buf, upd))\n \t\t\tdie(_(\"Failed to register update mode for submodule path '%s'\"), displaypath);\n@@ -383,6 +384,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \tstrbuf_release(&sb);\n \tfree(displaypath);\n \tfree(url);\n+\tfree(upd);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 2e62548..bf2deee 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -305,13 +305,16 @@ test_git_path GIT_COMMON_DIR=bar config                   bar/config\n test_git_path GIT_COMMON_DIR=bar packed-refs              bar/packed-refs\n test_git_path GIT_COMMON_DIR=bar shallow                  bar/shallow\n \n+# In the tests below, the distinction between $PWD and $(pwd) is important:\n+# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).\n+\n test_submodule_relative_url \"../\" \"../foo\" \"../submodule\" \"../../submodule\"\n test_submodule_relative_url \"../\" \"../foo/bar\" \"../submodule\" \"../../foo/submodule\"\n test_submodule_relative_url \"../\" \"../foo/submodule\" \"../submodule\" \"../../foo/submodule\"\n test_submodule_relative_url \"../\" \"./foo\" \"../submodule\" \"../submodule\"\n test_submodule_relative_url \"../\" \"./foo/bar\" \"../submodule\" \"../foo/submodule\"\n test_submodule_relative_url \"../../../\" \"../foo/bar\" \"../sub/a/b/c\" \"../../../../foo/sub/a/b/c\"\n-test_submodule_relative_url \"../\" \"$PWD/addtest\" \"../repo\" \"$PWD/repo\"\n+test_submodule_relative_url \"../\" \"$PWD/addtest\" \"../repo\" \"$(pwd)/repo\"\n test_submodule_relative_url \"../\" \"foo/bar\" \"../submodule\" \"../foo/submodule\"\n test_submodule_relative_url \"../\" \"foo\" \"../submodule\" \"../submodule\"\n \n@@ -322,16 +325,16 @@ test_submodule_relative_url \"(null)\" \"../foo\" \"../submodule\" \"../submodule\"\n test_submodule_relative_url \"(null)\" \"./foo/bar\" \"../submodule\" \"foo/submodule\"\n test_submodule_relative_url \"(null)\" \"./foo\" \"../submodule\" \"submodule\"\n test_submodule_relative_url \"(null)\" \"//somewhere else/repo\" \"../subrepo\" \"//somewhere else/subrepo\"\n-test_submodule_relative_url \"(null)\" \"$PWD/subsuper_update_r\" \"../subsubsuper_update_r\" \"$PWD/subsubsuper_update_r\"\n-test_submodule_relative_url \"(null)\" \"$PWD/super_update_r2\" \"../subsuper_update_r\" \"$PWD/subsuper_update_r\"\n-test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../.\" \"$PWD/.\"\n-test_submodule_relative_url \"(null)\" \"$PWD\" \"./.\" \"$PWD/.\"\n-test_submodule_relative_url \"(null)\" \"$PWD/addtest\" \"../repo\" \"$PWD/repo\"\n-test_submodule_relative_url \"(null)\" \"$PWD\" \"./å äö\" \"$PWD/å äö\"\n-test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../submodule\" \"$PWD/submodule\"\n-test_submodule_relative_url \"(null)\" \"$PWD/submodule\" \"../submodule\" \"$PWD/submodule\"\n-test_submodule_relative_url \"(null)\" \"$PWD/home2/../remote\" \"../bundle1\" \"$PWD/home2/../bundle1\"\n-test_submodule_relative_url \"(null)\" \"$PWD/submodule_update_repo\" \"./.\" \"$PWD/submodule_update_repo/.\"\n+test_submodule_relative_url \"(null)\" \"$PWD/subsuper_update_r\" \"../subsubsuper_update_r\" \"$(pwd)/subsubsuper_update_r\"\n+test_submodule_relative_url \"(null)\" \"$PWD/super_update_r2\" \"../subsuper_update_r\" \"$(pwd)/subsuper_update_r\"\n+test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../.\" \"$(pwd)/.\"\n+test_submodule_relative_url \"(null)\" \"$PWD\" \"./.\" \"$(pwd)/.\"\n+test_submodule_relative_url \"(null)\" \"$PWD/addtest\" \"../repo\" \"$(pwd)/repo\"\n+test_submodule_relative_url \"(null)\" \"$PWD\" \"./å äö\" \"$(pwd)/å äö\"\n+test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../submodule\" \"$(pwd)/submodule\"\n+test_submodule_relative_url \"(null)\" \"$PWD/submodule\" \"../submodule\" \"$(pwd)/submodule\"\n+test_submodule_relative_url \"(null)\" \"$PWD/home2/../remote\" \"../bundle1\" \"$(pwd)/home2/../bundle1\"\n+test_submodule_relative_url \"(null)\" \"$PWD/submodule_update_repo\" \"./.\" \"$(pwd)/submodule_update_repo/.\"\n test_submodule_relative_url \"(null)\" \"file:///tmp/repo\" \"../subrepo\" \"file:///tmp/subrepo\"\n test_submodule_relative_url \"(null)\" \"foo/bar\" \"../submodule\" \"foo/submodule\"\n test_submodule_relative_url \"(null)\" \"foo\" \"../submodule\" \"submodule\"\n\n\nStefan Beller (2):\n  submodule: port resolve_relative_url from shell to C\n  submodule: port init from shell to C\n\n builtin/submodule--helper.c | 324 +++++++++++++++++++++++++++++++++++++++++++-\n git-submodule.sh            | 127 +----------------\n submodule.c                 |  21 +++\n submodule.h                 |   1 +\n t/t0060-path-utils.sh       |  46 +++++++\n 5 files changed, 397 insertions(+), 122 deletions(-)\n\n-- \n2.8.0.26.gba39a1b.dirty\n"},{"id":"283633","messageId":"1460767813-25916-2-git-send-email-sbeller@google.com","threadId":"42043","inReplyTo":"1460767813-25916-1-git-send-email-sbeller@google.com","subject":"[PATCH 1/2] submodule: port resolve_relative_url from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-16T00:50:12Z","receivedAt":"2016-04-16T00:50:12Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Later on we want to automatically call `git submodule init` from\nother commands, such that the users don't have to initialize the\nsubmodule themselves.  As these other commands are written in C\nalready, we'd need the init functionality in C, too.  The\n`resolve_relative_url` function is a large part of that init\nfunctionality, so start by porting this function to C.\n\nTo create the tests in t0060, the function `resolve_relative_url`\nwas temporarily enhanced to write all inputs and output to disk\nwhen running the test suite. The added tests in this patch are\na small selection thereof.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 209 +++++++++++++++++++++++++++++++++++++++++++-\n git-submodule.sh            |  81 +----------------\n t/t0060-path-utils.sh       |  46 ++++++++++\n 3 files changed, 258 insertions(+), 78 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 864dd18..46946b0 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -9,6 +9,211 @@\n #include \"submodule-config.h\"\n #include \"string-list.h\"\n #include \"run-command.h\"\n+#include \"remote.h\"\n+#include \"refs.h\"\n+#include \"connect.h\"\n+\n+static char *get_default_remote(void)\n+{\n+\tchar *dest = NULL, *ret;\n+\tunsigned char sha1[20];\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, sha1, NULL);\n+\n+\tif (!refname)\n+\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\n+\t/* detached HEAD */\n+\tif (!strcmp(refname, \"HEAD\"))\n+\t\treturn xstrdup(\"origin\");\n+\n+\tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n+\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n+\n+\tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n+\tif (git_config_get_string(sb.buf, &dest))\n+\t\tret = xstrdup(\"origin\");\n+\telse\n+\t\tret = dest;\n+\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+static int starts_with_dot_slash(const char *str)\n+{\n+\treturn str[0] == '.' && is_dir_sep(str[1]);\n+}\n+\n+static int starts_with_dot_dot_slash(const char *str)\n+{\n+\treturn str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);\n+}\n+\n+/*\n+ * Returns 1 if it was the last chop before ':'.\n+ */\n+static int chop_last_dir(char **remoteurl, int is_relative)\n+{\n+\tchar *rfind = find_last_dir_sep(*remoteurl);\n+\tif (rfind) {\n+\t\t*rfind = '\\0';\n+\t\treturn 0;\n+\t}\n+\n+\trfind = strrchr(*remoteurl, ':');\n+\tif (rfind) {\n+\t\t*rfind = '\\0';\n+\t\treturn 1;\n+\t}\n+\n+\tif (is_relative || !strcmp(\".\", *remoteurl))\n+\t\tdie(_(\"cannot strip one component off url '%s'\"),\n+\t\t\t*remoteurl);\n+\n+\tfree(*remoteurl);\n+\t*remoteurl = xstrdup(\".\");\n+\treturn 0;\n+}\n+\n+/*\n+ * The `url` argument is the URL that navigates to the submodule origin\n+ * repo. When relative, this URL is relative to the superproject origin\n+ * URL repo. The `up_path` argument, if specified, is the relative\n+ * path that navigates from the submodule working tree to the superproject\n+ * working tree. Returns the origin URL of the submodule.\n+ *\n+ * Return either an absolute URL or filesystem path (if the superproject\n+ * origin URL is an absolute URL or filesystem path, respectively) or a\n+ * relative file system path (if the superproject origin URL is a relative\n+ * file system path).\n+ *\n+ * When the output is a relative file system path, the path is either\n+ * relative to the submodule working tree, if up_path is specified, or to\n+ * the superproject working tree otherwise.\n+ *\n+ * NEEDSWORK: This works incorrectly on the domain and protocol part.\n+ * remote_url      url              outcome          expectation\n+ * http://a.com/b  ../c             http://a.com/c   as is\n+ * http://a.com/b  ../../c          http://c         error out\n+ * http://a.com/b  ../../../c       http:/c          error out\n+ * http://a.com/b  ../../../../c    http:c           error out\n+ * http://a.com/b  ../../../../../c    .:c           error out\n+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken\n+ * when a local part has a colon in its path component, too.\n+ */\n+static char *relative_url(const char *remote_url,\n+\t\t\t\tconst char *url,\n+\t\t\t\tconst char *up_path)\n+{\n+\tint is_relative = 0;\n+\tint colonsep = 0;\n+\tchar *out;\n+\tchar *remoteurl = xstrdup(remote_url);\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tsize_t len = strlen(remoteurl);\n+\n+\tif (is_dir_sep(remoteurl[len]))\n+\t\tremoteurl[len] = '\\0';\n+\n+\tif (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))\n+\t\tis_relative = 0;\n+\telse {\n+\t\tis_relative = 1;\n+\t\t/*\n+\t\t * Prepend a './' to ensure all relative\n+\t\t * remoteurls start with './' or '../'\n+\t\t */\n+\t\tif (!starts_with_dot_slash(remoteurl) &&\n+\t\t    !starts_with_dot_dot_slash(remoteurl)) {\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"./%s\", remoteurl);\n+\t\t\tfree(remoteurl);\n+\t\t\tremoteurl = strbuf_detach(&sb, NULL);\n+\t\t}\n+\t}\n+\t/*\n+\t * When the url starts with '../', remove that and the\n+\t * last directory in remoteurl.\n+\t */\n+\twhile (url) {\n+\t\tif (starts_with_dot_dot_slash(url)) {\n+\t\t\turl += 3;\n+\t\t\tcolonsep |= chop_last_dir(&remoteurl, is_relative);\n+\t\t} else if (starts_with_dot_slash(url))\n+\t\t\turl += 2;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"%s%s%s\", remoteurl, colonsep ? \":\" : \"/\", url);\n+\tfree(remoteurl);\n+\n+\tif (starts_with_dot_slash(sb.buf))\n+\t\tout = xstrdup(sb.buf + 2);\n+\telse\n+\t\tout = xstrdup(sb.buf);\n+\tstrbuf_reset(&sb);\n+\n+\tif (!up_path || !is_relative)\n+\t\treturn out;\n+\n+\tstrbuf_addf(&sb, \"%s%s\", up_path, out);\n+\tfree(out);\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n+static int resolve_relative_url(int argc, const char **argv, const char *prefix)\n+{\n+\tchar *remoteurl = NULL;\n+\tchar *remote = get_default_remote();\n+\tconst char *up_path = NULL;\n+\tchar *res;\n+\tconst char *url;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tif (argc != 2 && argc != 3)\n+\t\tdie(\"resolve-relative-url only accepts one or two arguments\");\n+\n+\turl = argv[1];\n+\tstrbuf_addf(&sb, \"remote.%s.url\", remote);\n+\tfree(remote);\n+\n+\tif (git_config_get_string(sb.buf, &remoteurl))\n+\t\t/* the repository is its own authoritative upstream */\n+\t\tremoteurl = xgetcwd();\n+\n+\tif (argc == 3)\n+\t\tup_path = argv[2];\n+\n+\tres = relative_url(remoteurl, url, up_path);\n+\tputs(res);\n+\tfree(res);\n+\tfree(remoteurl);\n+\treturn 0;\n+}\n+\n+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)\n+{\n+\tchar *remoteurl, *res;\n+\tconst char *up_path, *url;\n+\n+\tif (argc != 4)\n+\t\tdie(\"resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>\");\n+\n+\tup_path = argv[1];\n+\tremoteurl = xstrdup(argv[2]);\n+\turl = argv[3];\n+\n+\tif (!strcmp(up_path, \"(null)\"))\n+\t\tup_path = NULL;\n+\n+\tres = relative_url(remoteurl, url, up_path);\n+\tputs(res);\n+\tfree(res);\n+\tfree(remoteurl);\n+\treturn 0;\n+}\n \n struct module_list {\n \tconst struct cache_entry **entries;\n@@ -504,7 +709,9 @@ static struct cmd_struct commands[] = {\n \t{\"list\", module_list},\n \t{\"name\", module_name},\n \t{\"clone\", module_clone},\n-\t{\"update-clone\", update_clone}\n+\t{\"update-clone\", update_clone},\n+\t{\"resolve-relative-url\", resolve_relative_url},\n+\t{\"resolve-relative-url-test\", resolve_relative_url_test},\n };\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 07290d0..2423d7c 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -46,79 +46,6 @@ prefix=\n custom_name=\n depth=\n \n-# The function takes at most 2 arguments. The first argument is the\n-# URL that navigates to the submodule origin repo. When relative, this URL\n-# is relative to the superproject origin URL repo. The second up_path\n-# argument, if specified, is the relative path that navigates\n-# from the submodule working tree to the superproject working tree.\n-#\n-# The output of the function is the origin URL of the submodule.\n-#\n-# The output will either be an absolute URL or filesystem path (if the\n-# superproject origin URL is an absolute URL or filesystem path,\n-# respectively) or a relative file system path (if the superproject\n-# origin URL is a relative file system path).\n-#\n-# When the output is a relative file system path, the path is either\n-# relative to the submodule working tree, if up_path is specified, or to\n-# the superproject working tree otherwise.\n-resolve_relative_url ()\n-{\n-\tremote=$(get_default_remote)\n-\tremoteurl=$(git config \"remote.$remote.url\") ||\n-\t\tremoteurl=$(pwd) # the repository is its own authoritative upstream\n-\turl=\"$1\"\n-\tremoteurl=${remoteurl%/}\n-\tsep=/\n-\tup_path=\"$2\"\n-\n-\tcase \"$remoteurl\" in\n-\t*:*|/*)\n-\t\tis_relative=\n-\t\t;;\n-\t./*|../*)\n-\t\tis_relative=t\n-\t\t;;\n-\t*)\n-\t\tis_relative=t\n-\t\tremoteurl=\"./$remoteurl\"\n-\t\t;;\n-\tesac\n-\n-\twhile test -n \"$url\"\n-\tdo\n-\t\tcase \"$url\" in\n-\t\t../*)\n-\t\t\turl=\"${url#../}\"\n-\t\t\tcase \"$remoteurl\" in\n-\t\t\t*/*)\n-\t\t\t\tremoteurl=\"${remoteurl%/*}\"\n-\t\t\t\t;;\n-\t\t\t*:*)\n-\t\t\t\tremoteurl=\"${remoteurl%:*}\"\n-\t\t\t\tsep=:\n-\t\t\t\t;;\n-\t\t\t*)\n-\t\t\t\tif test -z \"$is_relative\" || test \".\" = \"$remoteurl\"\n-\t\t\t\tthen\n-\t\t\t\t\tdie \"$(eval_gettext \"cannot strip one component off url '\\$remoteurl'\")\"\n-\t\t\t\telse\n-\t\t\t\t\tremoteurl=.\n-\t\t\t\tfi\n-\t\t\t\t;;\n-\t\t\tesac\n-\t\t\t;;\n-\t\t./*)\n-\t\t\turl=\"${url#./}\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\tbreak;;\n-\t\tesac\n-\tdone\n-\tremoteurl=\"$remoteurl$sep${url%/}\"\n-\techo \"${is_relative:+${up_path}}${remoteurl#./}\"\n-}\n-\n # Resolve a path to be relative to another path.  This is intended for\n # converting submodule paths when git-submodule is run in a subdirectory\n # and only handles paths where the directory separator is '/'.\n@@ -281,7 +208,7 @@ cmd_add()\n \t\tdie \"$(gettext \"Relative path can only be used from the toplevel of the working tree\")\"\n \n \t\t# dereference source url relative to parent's url\n-\t\trealrepo=$(resolve_relative_url \"$repo\") || exit\n+\t\trealrepo=$(git submodule--helper resolve-relative-url \"$repo\") || exit\n \t\t;;\n \t*:*|/*)\n \t\t# absolute url\n@@ -485,7 +412,7 @@ cmd_init()\n \t\t\t# Possibly a url relative to parent\n \t\t\tcase \"$url\" in\n \t\t\t./*|../*)\n-\t\t\t\turl=$(resolve_relative_url \"$url\") || exit\n+\t\t\t\turl=$(git submodule--helper resolve-relative-url \"$url\") || exit\n \t\t\t\t;;\n \t\t\tesac\n \t\t\tgit config submodule.\"$name\".url \"$url\" ||\n@@ -1202,9 +1129,9 @@ cmd_sync()\n \t\t\t# guarantee a trailing /\n \t\t\tup_path=${up_path%/}/ &&\n \t\t\t# path from submodule work tree to submodule origin repo\n-\t\t\tsub_origin_url=$(resolve_relative_url \"$url\" \"$up_path\") &&\n+\t\t\tsub_origin_url=$(git submodule--helper resolve-relative-url \"$url\" \"$up_path\") &&\n \t\t\t# path from superproject work tree to submodule origin repo\n-\t\t\tsuper_config_url=$(resolve_relative_url \"$url\") || exit\n+\t\t\tsuper_config_url=$(git submodule--helper resolve-relative-url \"$url\") || exit\n \t\t\t;;\n \t\t*)\n \t\t\tsub_origin_url=\"$url\"\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 8532a02..bf2deee 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -19,6 +19,13 @@ relative_path() {\n \t\"test \\\"\\$(test-path-utils relative_path '$1' '$2')\\\" = '$expected'\"\n }\n \n+test_submodule_relative_url() {\n+\ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n+\t\tactual=\\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&\n+\t\ttest \\\"\\$actual\\\" = '$4'\n+\t\"\n+}\n+\n test_git_path() {\n \ttest_expect_success \"git-path $1 $2 => $3\" \"\n \t\t$1 git rev-parse --git-path $2 >actual &&\n@@ -298,4 +305,43 @@ test_git_path GIT_COMMON_DIR=bar config                   bar/config\n test_git_path GIT_COMMON_DIR=bar packed-refs              bar/packed-refs\n test_git_path GIT_COMMON_DIR=bar shallow                  bar/shallow\n \n+# In the tests below, the distinction between $PWD and $(pwd) is important:\n+# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).\n+\n+test_submodule_relative_url \"../\" \"../foo\" \"../submodule\" \"../../submodule\"\n+test_submodule_relative_url \"../\" \"../foo/bar\" \"../submodule\" \"../../foo/submodule\"\n+test_submodule_relative_url \"../\" \"../foo/submodule\" \"../submodule\" \"../../foo/submodule\"\n+test_submodule_relative_url \"../\" \"./foo\" \"../submodule\" \"../submodule\"\n+test_submodule_relative_url \"../\" \"./foo/bar\" \"../submodule\" \"../foo/submodule\"\n+test_submodule_relative_url \"../../../\" \"../foo/bar\" \"../sub/a/b/c\" \"../../../../foo/sub/a/b/c\"\n+test_submodule_relative_url \"../\" \"$PWD/addtest\" \"../repo\" \"$(pwd)/repo\"\n+test_submodule_relative_url \"../\" \"foo/bar\" \"../submodule\" \"../foo/submodule\"\n+test_submodule_relative_url \"../\" \"foo\" \"../submodule\" \"../submodule\"\n+\n+test_submodule_relative_url \"(null)\" \"../foo/bar\" \"../sub/a/b/c\" \"../foo/sub/a/b/c\"\n+test_submodule_relative_url \"(null)\" \"../foo/bar\" \"../submodule\" \"../foo/submodule\"\n+test_submodule_relative_url \"(null)\" \"../foo/submodule\" \"../submodule\" \"../foo/submodule\"\n+test_submodule_relative_url \"(null)\" \"../foo\" \"../submodule\" \"../submodule\"\n+test_submodule_relative_url \"(null)\" \"./foo/bar\" \"../submodule\" \"foo/submodule\"\n+test_submodule_relative_url \"(null)\" \"./foo\" \"../submodule\" \"submodule\"\n+test_submodule_relative_url \"(null)\" \"//somewhere else/repo\" \"../subrepo\" \"//somewhere else/subrepo\"\n+test_submodule_relative_url \"(null)\" \"$PWD/subsuper_update_r\" \"../subsubsuper_update_r\" \"$(pwd)/subsubsuper_update_r\"\n+test_submodule_relative_url \"(null)\" \"$PWD/super_update_r2\" \"../subsuper_update_r\" \"$(pwd)/subsuper_update_r\"\n+test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../.\" \"$(pwd)/.\"\n+test_submodule_relative_url \"(null)\" \"$PWD\" \"./.\" \"$(pwd)/.\"\n+test_submodule_relative_url \"(null)\" \"$PWD/addtest\" \"../repo\" \"$(pwd)/repo\"\n+test_submodule_relative_url \"(null)\" \"$PWD\" \"./å äö\" \"$(pwd)/å äö\"\n+test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../submodule\" \"$(pwd)/submodule\"\n+test_submodule_relative_url \"(null)\" \"$PWD/submodule\" \"../submodule\" \"$(pwd)/submodule\"\n+test_submodule_relative_url \"(null)\" \"$PWD/home2/../remote\" \"../bundle1\" \"$(pwd)/home2/../bundle1\"\n+test_submodule_relative_url \"(null)\" \"$PWD/submodule_update_repo\" \"./.\" \"$(pwd)/submodule_update_repo/.\"\n+test_submodule_relative_url \"(null)\" \"file:///tmp/repo\" \"../subrepo\" \"file:///tmp/subrepo\"\n+test_submodule_relative_url \"(null)\" \"foo/bar\" \"../submodule\" \"foo/submodule\"\n+test_submodule_relative_url \"(null)\" \"foo\" \"../submodule\" \"submodule\"\n+test_submodule_relative_url \"(null)\" \"helper:://hostname/repo\" \"../subrepo\" \"helper:://hostname/subrepo\"\n+test_submodule_relative_url \"(null)\" \"ssh://hostname/repo\" \"../subrepo\" \"ssh://hostname/subrepo\"\n+test_submodule_relative_url \"(null)\" \"ssh://hostname:22/repo\" \"../subrepo\" \"ssh://hostname:22/subrepo\"\n+test_submodule_relative_url \"(null)\" \"user@host:path/to/repo\" \"../subrepo\" \"user@host:path/to/subrepo\"\n+test_submodule_relative_url \"(null)\" \"user@host:repo\" \"../subrepo\" \"user@host:subrepo\"\n+\n test_done\n-- \n2.8.0.26.gba39a1b.dirty\n"},{"id":"283634","messageId":"1460767813-25916-3-git-send-email-sbeller@google.com","threadId":"42043","inReplyTo":"1460767813-25916-1-git-send-email-sbeller@google.com","subject":"[PATCH 2/2] submodule: port init from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-16T00:50:13Z","receivedAt":"2016-04-16T00:50:13Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"By having the `submodule init` functionality in C, we can reference it\neasier from other parts in the code in later patches. The code is split\nup to have one function to initialize one submodule and a calling function\nthat takes care of the rest, such as argument handling and translating the\narguments to the paths of the submodules.\n\nThis is the first submodule subcommand that is fully converted to C\nexcept for the usage string, so this is actually removing a call to\nthe `submodule--helper list` function, which is supposed to be used in\nthis transition. Instead we'll make a direct call to `module_list_compute`.\n\nAn explanation why we need to edit the prefixes in cmd_update in\ngit-submodule.sh in this patch:\n\nBy having no processing in the shell part, we need to convey the notion\nof wt_prefix and prefix to the C parts, which former patches punted on\nand did the processing of displaying path in the shell.\n\n`wt_prefix` used to hold the path from the repository root to the current\ndirectory, e.g. wt_prefix would be t/ if the user invoked the\n`git submodule` command in ~/repo/t and ~repo is the GIT_DIR.\n\n`prefix` used to hold the relative path from the repository root to the\noperation, e.g. if you have recursive submodules, the shell script would\nmodify the `prefix` in each recursive step by adding the submodule path.\n\nWe will pass `wt_prefix` into the C helper via `git -C <dir>` as that\nwill setup git in the directory the user actually called git-submodule.sh\nfrom. The `prefix` will be passed in via the `--prefix` option.\n\nHaving `prefix` and `wt_prefix` relative to the GIT_DIR of the\ncalling superproject is unfortunate with this patch as the C code doesn't\nknow about a possible recursion from a superproject via `submodule update\n--init --recursive`.\n\nTo fix this, we change the meaning of `wt_prefix` to point to the current\nproject instead of the superproject and `prefix` to include any relative\npaths issues in the superproject. That way `prefix` will become the leading\npart for displaying paths and `wt_prefix` will be empty in recursive\ncalls for now.\n\nThe new notion of `wt_prefix` and `prefix` still allows us to reconstruct\nthe calling directory in the superproject by just traveling reverse of\n`prefix`.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  48 ++----------------\n submodule.c                 |  21 ++++++++\n submodule.h                 |   1 +\n 4 files changed, 140 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 46946b0..b6d4f27 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -305,6 +305,120 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+static void init_submodule(const char *path, const char *prefix, int quiet)\n+{\n+\tconst struct submodule *sub;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tchar *upd = NULL, *url = NULL, *displaypath;\n+\n+\t/* Only loads from .gitmodules, no overlay with .git/config */\n+\tgitmodules_config();\n+\n+\tsub = submodule_from_path(null_sha1, path);\n+\n+\tif (prefix) {\n+\t\tstrbuf_addf(&sb, \"%s%s\", prefix, path);\n+\t\tdisplaypath = strbuf_detach(&sb, NULL);\n+\t} else\n+\t\tdisplaypath = xstrdup(sub->path);\n+\n+\t/*\n+\t * Copy url setting when it is not set yet.\n+\t * To look up the url in .git/config, we must not fall back to\n+\t * .gitmodules, so look it up directly.\n+\t */\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"submodule.%s.url\", sub->name);\n+\tif (git_config_get_string(sb.buf, &url)) {\n+\t\turl = xstrdup(sub->url);\n+\n+\t\tif (!url)\n+\t\t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n+\t\t\t\tdisplaypath);\n+\n+\t\t/* Possibly a url relative to parent */\n+\t\tif (starts_with_dot_dot_slash(url) ||\n+\t\t    starts_with_dot_slash(url)) {\n+\t\t\tchar *remoteurl, *relurl;\n+\t\t\tchar *remote = get_default_remote();\n+\t\t\tstruct strbuf remotesb = STRBUF_INIT;\n+\t\t\tstrbuf_addf(&remotesb, \"remote.%s.url\", remote);\n+\t\t\tfree(remote);\n+\n+\t\t\tif (git_config_get_string(remotesb.buf, &remoteurl))\n+\t\t\t\t/*\n+\t\t\t\t * The repository is its own\n+\t\t\t\t * authoritative upstream\n+\t\t\t\t */\n+\t\t\t\tremoteurl = xgetcwd();\n+\t\t\trelurl = relative_url(remoteurl, url, NULL);\n+\t\t\tstrbuf_release(&remotesb);\n+\t\t\tfree(remoteurl);\n+\t\t\tfree(url);\n+\t\t\turl = relurl;\n+\t\t}\n+\n+\t\tif (git_config_set_gently(sb.buf, url))\n+\t\t\tdie(_(\"Failed to register url for submodule path '%s'\"),\n+\t\t\t    displaypath);\n+\t\tif (!quiet)\n+\t\t\tprintf(_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n+\t\t\t\tsub->name, url, displaypath);\n+\t}\n+\n+\t/* Copy \"update\" setting when it is not set yet */\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"submodule.%s.update\", sub->name);\n+\tif (git_config_get_string(sb.buf, &upd) &&\n+\t    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n+\t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND) {\n+\t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n+\t\t\t\tsub->name);\n+\t\t\tupd = xstrdup(\"none\");\n+\t\t} else\n+\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n+\n+\t\tif (git_config_set_gently(sb.buf, upd))\n+\t\t\tdie(_(\"Failed to register update mode for submodule path '%s'\"), displaypath);\n+\t}\n+\tstrbuf_release(&sb);\n+\tfree(displaypath);\n+\tfree(url);\n+\tfree(upd);\n+}\n+\n+static int module_init(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint i;\n+\n+\tstruct option module_init_options[] = {\n+\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"alternative anchor for relative paths\")),\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output for initializing a submodule\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper init [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_init_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n+\n+\treturn 0;\n+}\n+\n static int module_name(int argc, const char **argv, const char *prefix)\n {\n \tconst struct submodule *sub;\n@@ -712,6 +826,7 @@ static struct cmd_struct commands[] = {\n \t{\"update-clone\", update_clone},\n \t{\"resolve-relative-url\", resolve_relative_url},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test},\n+\t{\"init\", module_init}\n };\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 2423d7c..82e95a9 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -394,50 +394,7 @@ cmd_init()\n \t\tshift\n \tdone\n \n-\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" |\n-\twhile read mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\"\n-\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n-\n-\t\tdisplaypath=$(relative_path \"$prefix$sm_path\")\n-\n-\t\t# Copy url setting when it is not set yet\n-\t\tif test -z \"$(git config \"submodule.$name.url\")\"\n-\t\tthen\n-\t\t\turl=$(git config -f .gitmodules submodule.\"$name\".url)\n-\t\t\ttest -z \"$url\" &&\n-\t\t\tdie \"$(eval_gettext \"No url found for submodule path '\\$displaypath' in .gitmodules\")\"\n-\n-\t\t\t# Possibly a url relative to parent\n-\t\t\tcase \"$url\" in\n-\t\t\t./*|../*)\n-\t\t\t\turl=$(git submodule--helper resolve-relative-url \"$url\") || exit\n-\t\t\t\t;;\n-\t\t\tesac\n-\t\t\tgit config submodule.\"$name\".url \"$url\" ||\n-\t\t\tdie \"$(eval_gettext \"Failed to register url for submodule path '\\$displaypath'\")\"\n-\n-\t\t\tsay \"$(eval_gettext \"Submodule '\\$name' (\\$url) registered for path '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\t# Copy \"update\" setting when it is not set yet\n-\t\tif upd=\"$(git config -f .gitmodules submodule.\"$name\".update)\" &&\n-\t\t   test -n \"$upd\" &&\n-\t\t   test -z \"$(git config submodule.\"$name\".update)\"\n-\t\tthen\n-\t\t\tcase \"$upd\" in\n-\t\t\tcheckout | rebase | merge | none)\n-\t\t\t\t;; # known modes of updating\n-\t\t\t*)\n-\t\t\t\techo >&2 \"warning: unknown update mode '$upd' suggested for submodule '$name'\"\n-\t\t\t\tupd=none\n-\t\t\t\t;;\n-\t\t\tesac\n-\t\t\tgit config submodule.\"$name\".update \"$upd\" ||\n-\t\t\tdie \"$(eval_gettext \"Failed to register update mode for submodule path '\\$displaypath'\")\"\n-\t\tfi\n-\tdone\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper init ${GIT_QUIET:+--quiet} ${prefix:+--prefix \"$prefix\"} \"$@\"\n }\n \n #\n@@ -740,7 +697,8 @@ cmd_update()\n \t\tif test -n \"$recursive\"\n \t\tthen\n \t\t\t(\n-\t\t\t\tprefix=\"$prefix$sm_path/\"\n+\t\t\t\tprefix=$(relative_path \"$prefix$sm_path/\")\n+\t\t\t\twt_prefix=\n \t\t\t\tclear_local_git_env\n \t\t\t\tcd \"$sm_path\" &&\n \t\t\t\teval cmd_update\ndiff --git a/submodule.c b/submodule.c\nindex 90825e1..4cc1c27 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -237,6 +237,27 @@ int parse_submodule_update_strategy(const char *value,\n \treturn 0;\n }\n \n+const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tswitch (s->type) {\n+\tcase SM_UPDATE_CHECKOUT:\n+\t\treturn \"checkout\";\n+\tcase SM_UPDATE_MERGE:\n+\t\treturn \"merge\";\n+\tcase SM_UPDATE_REBASE:\n+\t\treturn \"rebase\";\n+\tcase SM_UPDATE_NONE:\n+\t\treturn \"none\";\n+\tcase SM_UPDATE_UNSPECIFIED:\n+\t\treturn NULL;\n+\tcase SM_UPDATE_COMMAND:\n+\t\tstrbuf_addf(&sb, \"!%s\", s->command);\n+\t\treturn strbuf_detach(&sb, NULL);\n+\t}\n+\treturn NULL;\n+}\n+\n void handle_ignore_submodules_arg(struct diff_options *diffopt,\n \t\t\t\t  const char *arg)\n {\ndiff --git a/submodule.h b/submodule.h\nindex 7ef3775..ff4c4f3 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -39,6 +39,7 @@ int submodule_config(const char *var, const char *value, void *cb);\n void gitmodules_config(void);\n int parse_submodule_update_strategy(const char *value,\n \t\tstruct submodule_update_strategy *dst);\n+const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n-- \n2.8.0.26.gba39a1b.dirty\n"},{"id":"283744","messageId":"xmqq1t6267g8.fsf@gitster.mtv.corp.google.com","threadId":"42043","inReplyTo":"1460767813-25916-1-git-send-email-sbeller@google.com","subject":"Re: [PATCH 0/2] Another reroll of sb/submodule-init","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-18T19:30:15Z","receivedAt":"2016-04-18T19:30:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> * squashed the fixes from Johannes Sixt to unbreak Windows tests.\n>   (I had encoding issues; so I manually integrated the changes)\n> * fixed memleaks\n> * the base to apply did not change (ee30f17805f51d37 Merge branch\n> 'sb/submodule-path-misc-bugs' into sb/submodule-init)\n>\n> Thanks,\n> Stefan\n\nQueued.  I read it twice and I think this is ready for 'next'.\n\nComments from others?\n\n>\n> diff to current origin/sb/submodule-init:\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index ad3cba6..b6d4f27 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -309,8 +309,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  {\n>  \tconst struct submodule *sub;\n>  \tstruct strbuf sb = STRBUF_INIT;\n> -\tconst char *upd = NULL;\n> -\tchar *url = NULL, *displaypath;\n> +\tchar *upd = NULL, *url = NULL, *displaypath;\n>  \n>  \t/* Only loads from .gitmodules, no overlay with .git/config */\n>  \tgitmodules_config();\n> @@ -340,7 +339,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  \t\t/* Possibly a url relative to parent */\n>  \t\tif (starts_with_dot_dot_slash(url) ||\n>  \t\t    starts_with_dot_slash(url)) {\n> -\t\t\tchar *remoteurl;\n> +\t\t\tchar *remoteurl, *relurl;\n>  \t\t\tchar *remote = get_default_remote();\n>  \t\t\tstruct strbuf remotesb = STRBUF_INIT;\n>  \t\t\tstrbuf_addf(&remotesb, \"remote.%s.url\", remote);\n> @@ -352,9 +351,11 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  \t\t\t\t * authoritative upstream\n>  \t\t\t\t */\n>  \t\t\t\tremoteurl = xgetcwd();\n> -\t\t\turl = relative_url(remoteurl, url, NULL);\n> +\t\t\trelurl = relative_url(remoteurl, url, NULL);\n>  \t\t\tstrbuf_release(&remotesb);\n>  \t\t\tfree(remoteurl);\n> +\t\t\tfree(url);\n> +\t\t\turl = relurl;\n>  \t\t}\n>  \n>  \t\tif (git_config_set_gently(sb.buf, url))\n> @@ -368,14 +369,14 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  \t/* Copy \"update\" setting when it is not set yet */\n>  \tstrbuf_reset(&sb);\n>  \tstrbuf_addf(&sb, \"submodule.%s.update\", sub->name);\n> -\tif (git_config_get_string_const(sb.buf, &upd) &&\n> +\tif (git_config_get_string(sb.buf, &upd) &&\n>  \t    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n>  \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND) {\n>  \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n>  \t\t\t\tsub->name);\n> -\t\t\tupd = \"none\";\n> +\t\t\tupd = xstrdup(\"none\");\n>  \t\t} else\n> -\t\t\tupd = submodule_strategy_to_string(&sub->update_strategy);\n> +\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n>  \n>  \t\tif (git_config_set_gently(sb.buf, upd))\n>  \t\t\tdie(_(\"Failed to register update mode for submodule path '%s'\"), displaypath);\n> @@ -383,6 +384,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  \tstrbuf_release(&sb);\n>  \tfree(displaypath);\n>  \tfree(url);\n> +\tfree(upd);\n>  }\n>  \n>  static int module_init(int argc, const char **argv, const char *prefix)\n> diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\n> index 2e62548..bf2deee 100755\n> --- a/t/t0060-path-utils.sh\n> +++ b/t/t0060-path-utils.sh\n> @@ -305,13 +305,16 @@ test_git_path GIT_COMMON_DIR=bar config                   bar/config\n>  test_git_path GIT_COMMON_DIR=bar packed-refs              bar/packed-refs\n>  test_git_path GIT_COMMON_DIR=bar shallow                  bar/shallow\n>  \n> +# In the tests below, the distinction between $PWD and $(pwd) is important:\n> +# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).\n> +\n>  test_submodule_relative_url \"../\" \"../foo\" \"../submodule\" \"../../submodule\"\n>  test_submodule_relative_url \"../\" \"../foo/bar\" \"../submodule\" \"../../foo/submodule\"\n>  test_submodule_relative_url \"../\" \"../foo/submodule\" \"../submodule\" \"../../foo/submodule\"\n>  test_submodule_relative_url \"../\" \"./foo\" \"../submodule\" \"../submodule\"\n>  test_submodule_relative_url \"../\" \"./foo/bar\" \"../submodule\" \"../foo/submodule\"\n>  test_submodule_relative_url \"../../../\" \"../foo/bar\" \"../sub/a/b/c\" \"../../../../foo/sub/a/b/c\"\n> -test_submodule_relative_url \"../\" \"$PWD/addtest\" \"../repo\" \"$PWD/repo\"\n> +test_submodule_relative_url \"../\" \"$PWD/addtest\" \"../repo\" \"$(pwd)/repo\"\n>  test_submodule_relative_url \"../\" \"foo/bar\" \"../submodule\" \"../foo/submodule\"\n>  test_submodule_relative_url \"../\" \"foo\" \"../submodule\" \"../submodule\"\n>  \n> @@ -322,16 +325,16 @@ test_submodule_relative_url \"(null)\" \"../foo\" \"../submodule\" \"../submodule\"\n>  test_submodule_relative_url \"(null)\" \"./foo/bar\" \"../submodule\" \"foo/submodule\"\n>  test_submodule_relative_url \"(null)\" \"./foo\" \"../submodule\" \"submodule\"\n>  test_submodule_relative_url \"(null)\" \"//somewhere else/repo\" \"../subrepo\" \"//somewhere else/subrepo\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/subsuper_update_r\" \"../subsubsuper_update_r\" \"$PWD/subsubsuper_update_r\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/super_update_r2\" \"../subsuper_update_r\" \"$PWD/subsuper_update_r\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../.\" \"$PWD/.\"\n> -test_submodule_relative_url \"(null)\" \"$PWD\" \"./.\" \"$PWD/.\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/addtest\" \"../repo\" \"$PWD/repo\"\n> -test_submodule_relative_url \"(null)\" \"$PWD\" \"./å äö\" \"$PWD/å äö\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../submodule\" \"$PWD/submodule\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/submodule\" \"../submodule\" \"$PWD/submodule\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/home2/../remote\" \"../bundle1\" \"$PWD/home2/../bundle1\"\n> -test_submodule_relative_url \"(null)\" \"$PWD/submodule_update_repo\" \"./.\" \"$PWD/submodule_update_repo/.\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/subsuper_update_r\" \"../subsubsuper_update_r\" \"$(pwd)/subsubsuper_update_r\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/super_update_r2\" \"../subsuper_update_r\" \"$(pwd)/subsuper_update_r\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../.\" \"$(pwd)/.\"\n> +test_submodule_relative_url \"(null)\" \"$PWD\" \"./.\" \"$(pwd)/.\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/addtest\" \"../repo\" \"$(pwd)/repo\"\n> +test_submodule_relative_url \"(null)\" \"$PWD\" \"./å äö\" \"$(pwd)/å äö\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/.\" \"../submodule\" \"$(pwd)/submodule\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/submodule\" \"../submodule\" \"$(pwd)/submodule\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/home2/../remote\" \"../bundle1\" \"$(pwd)/home2/../bundle1\"\n> +test_submodule_relative_url \"(null)\" \"$PWD/submodule_update_repo\" \"./.\" \"$(pwd)/submodule_update_repo/.\"\n>  test_submodule_relative_url \"(null)\" \"file:///tmp/repo\" \"../subrepo\" \"file:///tmp/subrepo\"\n>  test_submodule_relative_url \"(null)\" \"foo/bar\" \"../submodule\" \"foo/submodule\"\n>  test_submodule_relative_url \"(null)\" \"foo\" \"../submodule\" \"submodule\"\n>\n>\n> Stefan Beller (2):\n>   submodule: port resolve_relative_url from shell to C\n>   submodule: port init from shell to C\n>\n>  builtin/submodule--helper.c | 324 +++++++++++++++++++++++++++++++++++++++++++-\n>  git-submodule.sh            | 127 +----------------\n>  submodule.c                 |  21 +++\n>  submodule.h                 |   1 +\n>  t/t0060-path-utils.sh       |  46 +++++++\n>  5 files changed, 397 insertions(+), 122 deletions(-)\n"}]}