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

2016-04-15 Thread Stefan Beller
By having the `submodule init` functionality in C, we can reference it
easier from other parts in the code in later patches. The code is split
up to have one function to initialize one submodule and a calling function
that takes care of the rest, such as argument handling and translating the
arguments to the paths of the submodules.

This is the first submodule subcommand that is fully converted to C
except for the usage string, so this is actually removing a call to
the `submodule--helper list` function, which is supposed to be used in
this transition. Instead we'll make a direct call to `module_list_compute`.

An explanation why we need to edit the prefixes in cmd_update in
git-submodule.sh in this patch:

By having no processing in the shell part, we need to convey the notion
of wt_prefix and prefix to the C parts, which former patches punted on
and did the processing of displaying path in the shell.

`wt_prefix` used to hold the path from the repository root to the current
directory, e.g. wt_prefix would be t/ if the user invoked the
`git submodule` command in ~/repo/t and ~repo is the GIT_DIR.

`prefix` used to hold the relative path from the repository root to the
operation, e.g. if you have recursive submodules, the shell script would
modify the `prefix` in each recursive step by adding the submodule path.

We will pass `wt_prefix` into the C helper via `git -C ` as that
will setup git in the directory the user actually called git-submodule.sh
from. The `prefix` will be passed in via the `--prefix` option.

Having `prefix` and `wt_prefix` relative to the GIT_DIR of the
calling superproject is unfortunate with this patch as the C code doesn't
know about a possible recursion from a superproject via `submodule update
--init --recursive`.

To fix this, we change the meaning of `wt_prefix` to point to the current
project instead of the superproject and `prefix` to include any relative
paths issues in the superproject. That way `prefix` will become the leading
part for displaying paths and `wt_prefix` will be empty in recursive
calls for now.

The new notion of `wt_prefix` and `prefix` still allows us to reconstruct
the calling directory in the superproject by just traveling reverse of
`prefix`.

Signed-off-by: Stefan Beller 
---
 builtin/submodule--helper.c | 115 
 git-submodule.sh|  48 ++
 submodule.c |  21 
 submodule.h |   1 +
 4 files changed, 140 insertions(+), 45 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 46946b0..b6d4f27 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -305,6 +305,120 @@ static int module_list(int argc, const char **argv, const 
char *prefix)
return 0;
 }
 
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+   const struct submodule *sub;
+   struct strbuf sb = STRBUF_INIT;
+   char *upd = NULL, *url = NULL, *displaypath;
+
+   /* Only loads from .gitmodules, no overlay with .git/config */
+   gitmodules_config();
+
+   sub = submodule_from_path(null_sha1, path);
+
+   if (prefix) {
+   strbuf_addf(&sb, "%s%s", prefix, path);
+   displaypath = strbuf_detach(&sb, NULL);
+   } else
+   displaypath = xstrdup(sub->path);
+
+   /*
+* Copy url setting when it is not set yet.
+* To look up the url in .git/config, we must not fall back to
+* .gitmodules, so look it up directly.
+*/
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.url", sub->name);
+   if (git_config_get_string(sb.buf, &url)) {
+   url = xstrdup(sub->url);
+
+   if (!url)
+   die(_("No url found for submodule path '%s' in 
.gitmodules"),
+   displaypath);
+
+   /* Possibly a url relative to parent */
+   if (starts_with_dot_dot_slash(url) ||
+   starts_with_dot_slash(url)) {
+   char *remoteurl, *relurl;
+   char *remote = get_default_remote();
+   struct strbuf remotesb = STRBUF_INIT;
+   strbuf_addf(&remotesb, "remote.%s.url", remote);
+   free(remote);
+
+   if (git_config_get_string(remotesb.buf, &remoteurl))
+   /*
+* The repository is its own
+* authoritative upstream
+*/
+   remoteurl = xgetcwd();
+   relurl = relative_url(remoteurl, url, NULL);
+   strbuf_release(&remotesb);
+   free(remoteurl);
+   free(url);
+   url = relurl;
+   }
+
+   if (git_config_set_gently(sb.buf

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

2016-04-14 Thread Stefan Beller
By having the `submodule init` functionality in C, we can reference it
easier from other parts in the code in later patches. The code is split
up to have one function to initialize one submodule and a calling function
that takes care of the rest, such as argument handling and translating the
arguments to the paths of the submodules.

This is the first submodule subcommand that is fully converted to C
except for the usage string, so this is actually removing a call to
the `submodule--helper list` function, which is supposed to be used in
this transition. Instead we'll make a direct call to `module_list_compute`.

An explanation why we need to edit the prefixes in cmd_update in
git-submodule.sh in this patch:

By having no processing in the shell part, we need to convey the notion
of wt_prefix and prefix to the C parts, which former patches punted on
and did the processing of displaying path in the shell.

`wt_prefix` used to hold the path from the repository root to the current
directory, e.g. wt_prefix would be t/ if the user invoked the
`git submodule` command in ~/repo/t and ~repo is the GIT_DIR.

`prefix` used to hold the relative path from the repository root to the
operation, e.g. if you have recursive submodules, the shell script would
modify the `prefix` in each recursive step by adding the submodule path.

We will pass `wt_prefix` into the C helper via `git -C ` as that
will setup git in the directory the user actually called git-submodule.sh
from. The `prefix` will be passed in via the `--prefix` option.

Having `prefix` and `wt_prefix` relative to the GIT_DIR of the
calling superproject is unfortunate with this patch as the C code doesn't
know about a possible recursion from a superproject via `submodule update
--init --recursive`.

To fix this, we change the meaning of `wt_prefix` to point to the current
project instead of the superproject and `prefix` to include any relative
paths issues in the superproject. That way `prefix` will become the leading
part for displaying paths and `wt_prefix` will be empty in recursive
calls for now.

The new notion of `wt_prefix` and `prefix` still allows us to reconstruct
the calling directory in the superproject by just traveling reverse of
`prefix`.

Signed-off-by: Stefan Beller 
---
 builtin/submodule--helper.c | 113 
 git-submodule.sh|  48 ++-
 submodule.c |  21 
 submodule.h |   1 +
 4 files changed, 138 insertions(+), 45 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 46946b0..ad3cba6 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -305,6 +305,118 @@ static int module_list(int argc, const char **argv, const 
char *prefix)
return 0;
 }
 
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+   const struct submodule *sub;
+   struct strbuf sb = STRBUF_INIT;
+   const char *upd = NULL;
+   char *url = NULL, *displaypath;
+
+   /* Only loads from .gitmodules, no overlay with .git/config */
+   gitmodules_config();
+
+   sub = submodule_from_path(null_sha1, path);
+
+   if (prefix) {
+   strbuf_addf(&sb, "%s%s", prefix, path);
+   displaypath = strbuf_detach(&sb, NULL);
+   } else
+   displaypath = xstrdup(sub->path);
+
+   /*
+* Copy url setting when it is not set yet.
+* To look up the url in .git/config, we must not fall back to
+* .gitmodules, so look it up directly.
+*/
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.url", sub->name);
+   if (git_config_get_string(sb.buf, &url)) {
+   url = xstrdup(sub->url);
+
+   if (!url)
+   die(_("No url found for submodule path '%s' in 
.gitmodules"),
+   displaypath);
+
+   /* Possibly a url relative to parent */
+   if (starts_with_dot_dot_slash(url) ||
+   starts_with_dot_slash(url)) {
+   char *remoteurl;
+   char *remote = get_default_remote();
+   struct strbuf remotesb = STRBUF_INIT;
+   strbuf_addf(&remotesb, "remote.%s.url", remote);
+   free(remote);
+
+   if (git_config_get_string(remotesb.buf, &remoteurl))
+   /*
+* The repository is its own
+* authoritative upstream
+*/
+   remoteurl = xgetcwd();
+   url = relative_url(remoteurl, url, NULL);
+   strbuf_release(&remotesb);
+   free(remoteurl);
+   }
+
+   if (git_config_set_gently(sb.buf, url))
+   die(_("Failed to register url for

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

2016-04-12 Thread Stefan Beller
By having the `init` functionality in C, we can reference it easier
from other parts in the code.

Signed-off-by: Stefan Beller 
Signed-off-by: Junio C Hamano 
---
 builtin/submodule--helper.c | 107 
 git-submodule.sh|  39 +---
 submodule.c |  21 +
 submodule.h |   1 +
 4 files changed, 130 insertions(+), 38 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 2ab3662..3078790 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -215,6 +215,112 @@ static int resolve_relative_url_test(int argc, const char 
**argv, const char *pr
return 0;
 }
 
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+   const struct submodule *sub;
+   struct strbuf sb = STRBUF_INIT;
+   char *url = NULL;
+   const char *upd = NULL;
+   char *cwd = xgetcwd();
+   const char *displaypath = relative_path(cwd, prefix, &sb);
+
+   /* Only loads from .gitmodules, no overlay with .git/config */
+   gitmodules_config();
+
+   sub = submodule_from_path(null_sha1, path);
+
+   /*
+* Copy url setting when it is not set yet.
+* To look up the url in .git/config, we must not fall back to
+* .gitmodules, so look it up directly.
+*/
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.url", sub->name);
+   if (git_config_get_string(sb.buf, &url)) {
+   url = xstrdup(sub->url);
+
+   if (!url)
+   die(_("No url found for submodule path '%s' in 
.gitmodules"),
+   displaypath);
+
+   /* Possibly a url relative to parent */
+   if (starts_with_dot_dot_slash(url) ||
+   starts_with_dot_slash(url)) {
+   char *remoteurl;
+   char *remote = get_default_remote();
+   struct strbuf remotesb = STRBUF_INIT;
+   strbuf_addf(&remotesb, "remote.%s.url", remote);
+   free(remote);
+
+   if (git_config_get_string(remotesb.buf, &remoteurl))
+   /*
+* The repository is its own
+* authoritative upstream
+*/
+   remoteurl = xgetcwd();
+   url = relative_url(remoteurl, url, NULL);
+   strbuf_release(&remotesb);
+   free(remoteurl);
+   }
+
+   if (git_config_set(sb.buf, url))
+   die(_("Failed to register url for submodule path '%s'"),
+   displaypath);
+   if (!quiet)
+   printf(_("Submodule '%s' (%s) registered for path 
'%s'\n"),
+   sub->name, url, displaypath);
+   }
+
+   /* Copy "update" setting when it is not set yet */
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.update", sub->name);
+   if (git_config_get_string_const(sb.buf, &upd) &&
+   sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
+   if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
+   fprintf(stderr, _("warning: command update mode 
suggested for submodule '%s'\n"),
+   sub->name);
+   upd = "none";
+   } else
+   upd = 
submodule_strategy_to_string(&sub->update_strategy);
+
+   if (git_config_set(sb.buf, upd))
+   die(_("Failed to register update mode for submodule 
path '%s'"), displaypath);
+   }
+   strbuf_release(&sb);
+   free(cwd);
+   free(url);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+   int quiet = 0;
+   int i;
+
+   struct option module_init_options[] = {
+   OPT_STRING(0, "prefix", &prefix,
+  N_("path"),
+  N_("alternative anchor for relative paths")),
+   OPT__QUIET(&quiet, N_("Suppress output for initializing a 
submodule")),
+   OPT_END()
+   };
+
+   const char *const git_submodule_helper_usage[] = {
+   N_("git submodule--helper init []"),
+   NULL
+   };
+
+   argc = parse_options(argc, argv, prefix, module_init_options,
+git_submodule_helper_usage, 0);
+
+   if (argc == 0)
+   die(_("Pass at least one submodule"));
+
+   for (i = 0; i < argc; i++)
+   init_submodule(argv[i], prefix, quiet);
+
+   return 0;
+}
+
 struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -723,6 +829,7 @@ static struct cmd_struct commands[] = {
{"update-clone

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

2016-03-14 Thread Stefan Beller
By having the `init` functionality in C, we can reference it easier
from other parts in the code.

Signed-off-by: Stefan Beller 
Signed-off-by: Junio C Hamano 
---
 builtin/submodule--helper.c | 107 
 git-submodule.sh|  39 +---
 submodule.c |  21 +
 submodule.h |   1 +
 4 files changed, 130 insertions(+), 38 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index bc7cf87..d942463 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -216,6 +216,112 @@ static int resolve_relative_url_test(int argc, const char 
**argv, const char *pr
return 0;
 }
 
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+   const struct submodule *sub;
+   struct strbuf sb = STRBUF_INIT;
+   char *url = NULL;
+   const char *upd = NULL;
+   char *cwd = xgetcwd();
+   const char *displaypath = relative_path(cwd, prefix, &sb);
+
+   /* Only loads from .gitmodules, no overlay with .git/config */
+   gitmodules_config();
+
+   sub = submodule_from_path(null_sha1, path);
+
+   /*
+* Copy url setting when it is not set yet.
+* To look up the url in .git/config, we must not fall back to
+* .gitmodules, so look it up directly.
+*/
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.url", sub->name);
+   if (git_config_get_string(sb.buf, &url)) {
+   url = xstrdup(sub->url);
+
+   if (!url)
+   die(_("No url found for submodule path '%s' in 
.gitmodules"),
+   displaypath);
+
+   /* Possibly a url relative to parent */
+   if (starts_with_dot_dot_slash(url) ||
+   starts_with_dot_slash(url)) {
+   char *remoteurl;
+   char *remote = get_default_remote();
+   struct strbuf remotesb = STRBUF_INIT;
+   strbuf_addf(&remotesb, "remote.%s.url", remote);
+   free(remote);
+
+   if (git_config_get_string(remotesb.buf, &remoteurl))
+   /*
+* The repository is its own
+* authoritative upstream
+*/
+   remoteurl = xgetcwd();
+   url = relative_url(remoteurl, url, NULL);
+   strbuf_release(&remotesb);
+   free(remoteurl);
+   }
+
+   if (git_config_set(sb.buf, url))
+   die(_("Failed to register url for submodule path '%s'"),
+   displaypath);
+   if (!quiet)
+   printf(_("Submodule '%s' (%s) registered for path 
'%s'\n"),
+   sub->name, url, displaypath);
+   }
+
+   /* Copy "update" setting when it is not set yet */
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.update", sub->name);
+   if (git_config_get_string_const(sb.buf, &upd) &&
+   sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
+   if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
+   fprintf(stderr, _("warning: command update mode 
suggested for submodule '%s'\n"),
+   sub->name);
+   upd = "none";
+   } else
+   upd = 
submodule_strategy_to_string(&sub->update_strategy);
+
+   if (git_config_set(sb.buf, upd))
+   die(_("Failed to register update mode for submodule 
path '%s'"), displaypath);
+   }
+   strbuf_release(&sb);
+   free(cwd);
+   free(url);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+   int quiet = 0;
+   int i;
+
+   struct option module_init_options[] = {
+   OPT_STRING(0, "prefix", &prefix,
+  N_("path"),
+  N_("alternative anchor for relative paths")),
+   OPT__QUIET(&quiet, N_("Suppress output for initializing a 
submodule")),
+   OPT_END()
+   };
+
+   const char *const git_submodule_helper_usage[] = {
+   N_("git submodule--helper init []"),
+   NULL
+   };
+
+   argc = parse_options(argc, argv, prefix, module_init_options,
+git_submodule_helper_usage, 0);
+
+   if (argc == 0)
+   die(_("Pass at least one submodule"));
+
+   for (i = 0; i < argc; i++)
+   init_submodule(argv[i], prefix, quiet);
+
+   return 0;
+}
+
 struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -724,6 +830,7 @@ static struct cmd_struct commands[] = {
{"update-clone

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

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

>> +strbuf_reset(&sb);
>> +strbuf_addf(&sb, "submodule.%s.url", sub->name);
>> +if (git_config_get_string(sb.buf, &url)) {
>> +url = xstrdup(sub->url);
>> +if (!url)
>> +die(_("No url found for submodule path '%s' in 
>> .gitmodules"),
>> +displaypath);
>
> I am assuming that this corresponds to these lines in the original
> scripted version:
>
>   url=$(git config -f .gitmodules submodule."$name".url)
>   test -z "$url" &&
>   die "$(eval_gettext "No url found for submodule path...
>
> but what makes git_config_get_string() to read from ".gitmodules"
> file?  Doesn't it read from $GIT_DIR/config & ~/.gitconfig instead?

I am starting to suspect that reading of ".gitmodules" in the
context of "git submodule" command is a good use case for the
configset API.  It wants to read variables from ".gitmodules" and
the regular configuration file, and cares about where they come
from, illustrated by this codepath.  Read URL from .gitmodules, do
something to it, and update the regular configuration file.  Read
Update from .gitmodules, do some verification, and selectively store
it in the regular configuration file.  There may be cases where you
want to check if a variable is in the regular configuration file
(i.e. read from there), see its value in ".gitmodules", and
conditionally update the regular configuration file (i.e. write into
it).  The configset API was designed to help implement this kind of
thing in a clean manner (i.e. initialize one, add ".gitmodules"
file, and then configset_get_* on it, without affecting what you
read and write with the regular config_get_*/config_set_* to the
regular configuration file).


--
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 2/2] submodule: port init from shell to C

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

> By having the `init` functionality in C, we can reference it easier
> from other parts in the code.
>
> Signed-off-by: Stefan Beller 
> ---
>  builtin/submodule--helper.c | 107 
> 
>  git-submodule.sh|  39 +---
>  submodule.c |  21 +
>  submodule.h |   1 +
>  4 files changed, 130 insertions(+), 38 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index d1e9118..30e623a 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -214,6 +214,112 @@ static int resolve_relative_url_test(int argc, const 
> char **argv, const char *pr
>   return 0;
>  }
>  
> +static void init_submodule(const char *path, const char *prefix, int quiet)
> +{
> + const struct submodule *sub;
> + struct strbuf sb = STRBUF_INIT;
> + char *url = NULL;
> + const char *upd = NULL;
> + char *cwd = xgetcwd();
> + const char *displaypath = relative_path(cwd, prefix, &sb);
> +
> + /* Only loads from .gitmodules, no overlay with .git/config */
> + gitmodules_config();

This feeds submodule_config() function with the contents of
".gitmodules".

> + sub = submodule_from_path(null_sha1, path);
> +
> + /*
> +  * Copy url setting when it is not set yet.
> +  * To look up the url in .git/config, we must not fall back to
> +  * .gitmodules, so look it up directly.
> +  */
> + strbuf_reset(&sb);
> + strbuf_addf(&sb, "submodule.%s.url", sub->name);
> + if (git_config_get_string(sb.buf, &url)) {
> + url = xstrdup(sub->url);
> + if (!url)
> + die(_("No url found for submodule path '%s' in 
> .gitmodules"),
> + displaypath);

I am assuming that this corresponds to these lines in the original
scripted version:

url=$(git config -f .gitmodules submodule."$name".url)
test -z "$url" &&
die "$(eval_gettext "No url found for submodule path...

but what makes git_config_get_string() to read from ".gitmodules"
file?  Doesn't it read from $GIT_DIR/config & ~/.gitconfig instead?

> + /* Possibly a url relative to parent */
> + if (starts_with_dot_dot_slash(url) ||
> + starts_with_dot_slash(url)) {
> + char *remoteurl;
> + char *remote = get_default_remote();
> + struct strbuf remotesb = STRBUF_INIT;
> + strbuf_addf(&remotesb, "remote.%s.url", remote);
> + free(remote);
> +
> + if (git_config_get_string(remotesb.buf, &remoteurl))
> + /*
> +  * The repository is its own
> +  * authoritative upstream
> +  */
> + remoteurl = xgetcwd();
> + url = relative_url(remoteurl, url, NULL);
> + strbuf_release(&remotesb);
> + free(remoteurl);

Does the code inside this block correspond to this single line in
the original?

url=$(git submodule--helper resolve-relative-url "$url") || exit

It seems to be doing quite a different thing, though.

> + }
> +
> + if (git_config_set(sb.buf, url))
> + die(_("Failed to register url for submodule path '%s'"),
> + displaypath);
> + if (!quiet)
> + printf(_("Submodule '%s' (%s) registered for path 
> '%s'\n"),
> + sub->name, url, displaypath);
> + }
> +
> + /* Copy "update" setting when it is not set yet */
> + strbuf_reset(&sb);
> + strbuf_addf(&sb, "submodule.%s.update", sub->name);
> + if (git_config_get_string_const(sb.buf, &upd) &&



This part of the code is supposed to read from in-tree ".gitmodules"
and copy to $GIT_DIR/config (i.e. git_config_set() below), but
again, I am not sure what makes this read from ".gitmodules".

Puzzled.

> + sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
> + if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
> + fprintf(stderr, _("warning: command update mode 
> suggested for submodule '%s'\n"),
> + sub->name);
> + upd = "none";
> + } else
> + upd = 
> submodule_strategy_to_string(&sub->update_strategy);
> +
> + if (git_config_set(sb.buf, upd))
> + die(_("Failed to register update mode for submodule 
> path '%s'"), displaypath);
> + }
> + strbuf_release(&sb);
> + free(cwd);
> + free(url);
> +}
--
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://

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

2016-02-12 Thread Stefan Beller
By having the `init` functionality in C, we can reference it easier
from other parts in the code.

Signed-off-by: Stefan Beller 
---
 builtin/submodule--helper.c | 107 
 git-submodule.sh|  39 +---
 submodule.c |  21 +
 submodule.h |   1 +
 4 files changed, 130 insertions(+), 38 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index d1e9118..30e623a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -214,6 +214,112 @@ static int resolve_relative_url_test(int argc, const char 
**argv, const char *pr
return 0;
 }
 
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+   const struct submodule *sub;
+   struct strbuf sb = STRBUF_INIT;
+   char *url = NULL;
+   const char *upd = NULL;
+   char *cwd = xgetcwd();
+   const char *displaypath = relative_path(cwd, prefix, &sb);
+
+   /* Only loads from .gitmodules, no overlay with .git/config */
+   gitmodules_config();
+
+   sub = submodule_from_path(null_sha1, path);
+
+   /*
+* Copy url setting when it is not set yet.
+* To look up the url in .git/config, we must not fall back to
+* .gitmodules, so look it up directly.
+*/
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.url", sub->name);
+   if (git_config_get_string(sb.buf, &url)) {
+   url = xstrdup(sub->url);
+
+   if (!url)
+   die(_("No url found for submodule path '%s' in 
.gitmodules"),
+   displaypath);
+
+   /* Possibly a url relative to parent */
+   if (starts_with_dot_dot_slash(url) ||
+   starts_with_dot_slash(url)) {
+   char *remoteurl;
+   char *remote = get_default_remote();
+   struct strbuf remotesb = STRBUF_INIT;
+   strbuf_addf(&remotesb, "remote.%s.url", remote);
+   free(remote);
+
+   if (git_config_get_string(remotesb.buf, &remoteurl))
+   /*
+* The repository is its own
+* authoritative upstream
+*/
+   remoteurl = xgetcwd();
+   url = relative_url(remoteurl, url, NULL);
+   strbuf_release(&remotesb);
+   free(remoteurl);
+   }
+
+   if (git_config_set(sb.buf, url))
+   die(_("Failed to register url for submodule path '%s'"),
+   displaypath);
+   if (!quiet)
+   printf(_("Submodule '%s' (%s) registered for path 
'%s'\n"),
+   sub->name, url, displaypath);
+   }
+
+   /* Copy "update" setting when it is not set yet */
+   strbuf_reset(&sb);
+   strbuf_addf(&sb, "submodule.%s.update", sub->name);
+   if (git_config_get_string_const(sb.buf, &upd) &&
+   sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
+   if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
+   fprintf(stderr, _("warning: command update mode 
suggested for submodule '%s'\n"),
+   sub->name);
+   upd = "none";
+   } else
+   upd = 
submodule_strategy_to_string(&sub->update_strategy);
+
+   if (git_config_set(sb.buf, upd))
+   die(_("Failed to register update mode for submodule 
path '%s'"), displaypath);
+   }
+   strbuf_release(&sb);
+   free(cwd);
+   free(url);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+   int quiet = 0;
+   int i;
+
+   struct option module_init_options[] = {
+   OPT_STRING(0, "prefix", &prefix,
+  N_("path"),
+  N_("alternative anchor for relative paths")),
+   OPT__QUIET(&quiet, "Suppress output for initialzing a 
submodule"),
+   OPT_END()
+   };
+
+   const char *const git_submodule_helper_usage[] = {
+   N_("git submodule--helper init []"),
+   NULL
+   };
+
+   argc = parse_options(argc, argv, prefix, module_init_options,
+git_submodule_helper_usage, 0);
+
+   if (argc == 0)
+   die(_("Pass at least one submodule"));
+
+   for (i = 0; i < argc; i++)
+   init_submodule(argv[i], prefix, quiet);
+
+   return 0;
+}
+
 struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -709,6 +815,7 @@ static struct cmd_struct commands[] = {
{"update-clone", update_clone},
{"resolve-