git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
* [PATCH 00/13] submodule: convert the rest of 'update' to C
@ 2021-09-07 11:59 Atharva Raykar
  2021-09-07 11:59 ` [PATCH 01/13] submodule--helper: split up ensure_core_worktree() Atharva Raykar
                   ` (15 more replies)
  0 siblings, 16 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

NOTE: This series uses ar/submodule-run-update-procedure [1]

This series builds upon the previous conversion work on 'submodule update' and
moves out all of that shell logic in 'git-submodule.sh' into
'builtin/submodule--helper.c'. Even though this patch series looks long, a lot
of it is preparatory patches and cleanup of unused functions that result from
this conversion. The real action happens at [6/8].

As with the other series, the goal is to be a faithful conversion, with no
change in behaviour.

This would be the last command whose logic would be moved into C, other than
'submodule add', whose patches have been sent already.

After this works out, we can invert the shell-C relationship and make
'submodule' a proper C builtin.

Fetch-it-Via:
git fetch https://github.com/tfidfwastaken/git submodule-update-list-1

[1] https://lore.kernel.org/git/20210824140609.1496-1-raykar.ath@gmail.com/

Atharva Raykar (13):
  submodule--helper: split up ensure_core_worktree()
  submodule--helper: get remote names from any repository
  submodule--helper: introduce get_default_remote_submodule()
  submodule--helper: rename helpers for update-clone
  submodule--helper: refactor get_submodule_displaypath()
  submodule: move core cmd_update() logic to C
  submodule: remove fetch_in_submodule shell function
  submodule--helper: remove update-clone subcommand
  submodule--helper: remove update-module-mode subcommand
  submodule--helper: remove shell interface to ensure_core_worktree()
  submodule--helper: remove print-default-remote subcommand
  submodule--helper: remove relative-path subcommand
  submodule--helper: remove run-update-procedure subcommand

 builtin/submodule--helper.c | 764 +++++++++++++++++++++---------------
 git-submodule.sh            | 145 +------
 2 files changed, 455 insertions(+), 454 deletions(-)

-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 01/13] submodule--helper: split up ensure_core_worktree()
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 11:59 ` [PATCH 02/13] submodule--helper: get remote names from any repository Atharva Raykar
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

Let's split up `ensure_core_worktree()` so that we can call it from C
code without needing to deal with command line arguments.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 80619361fc..97512ccf0b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2794,18 +2794,12 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
+static void do_ensure_core_worktree(const char *path)
 {
 	const struct submodule *sub;
-	const char *path;
 	const char *cw;
 	struct repository subrepo;
 
-	if (argc != 2)
-		BUG("submodule--helper ensure-core-worktree <path>");
-
-	path = argv[1];
-
 	sub = submodule_from_path(the_repository, null_oid(), path);
 	if (!sub)
 		BUG("We could get the submodule handle before?");
@@ -2829,6 +2823,17 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 		free(abs_path);
 		strbuf_release(&sb);
 	}
+}
+
+static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
+{
+	const char *path;
+
+	if (argc != 2)
+		BUG("submodule--helper ensure-core-worktree <path>");
+
+	path = argv[1];
+	do_ensure_core_worktree(path);
 
 	return 0;
 }
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 02/13] submodule--helper: get remote names from any repository
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
  2021-09-07 11:59 ` [PATCH 01/13] submodule--helper: split up ensure_core_worktree() Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 12:37   ` Ævar Arnfjörð Bjarmason
  2021-09-07 11:59 ` [PATCH 03/13] submodule--helper: introduce get_default_remote_submodule() Atharva Raykar
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

`get_default_remote()` retrieves the name of a remote by resolving the
refs from of the current repository's ref store.

Thus in order to use it for retrieving the remote name of a submodule,
we have to start a new subprocess which runs from the submodule
directory.

Let's instead introduce a function called `repo_get_default_remote()`
which takes any repository object and retrieves the remote accordingly.

`get_default_remote()` is then defined as a call to
`repo_get_default_remote()` with 'the_repository' passed to it.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 97512ccf0b..1a65de4fa4 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -29,11 +29,10 @@
 typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
 				  void *cb_data);
 
-static char *get_default_remote(void)
+static char *repo_get_default_remote(struct repository *repo, const char *refname)
 {
 	char *dest = NULL, *ret;
 	struct strbuf sb = STRBUF_INIT;
-	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 
 	if (!refname)
 		die(_("No such ref: %s"), "HEAD");
@@ -46,7 +45,7 @@ static char *get_default_remote(void)
 		die(_("Expecting a full ref name, got %s"), refname);
 
 	strbuf_addf(&sb, "branch.%s.remote", refname);
-	if (git_config_get_string(sb.buf, &dest))
+	if (repo_config_get_string(repo, sb.buf, &dest))
 		ret = xstrdup("origin");
 	else
 		ret = dest;
@@ -55,6 +54,12 @@ static char *get_default_remote(void)
 	return ret;
 }
 
+static char *get_default_remote(void)
+{
+	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+	return repo_get_default_remote(the_repository, refname);
+}
+
 static int print_default_remote(int argc, const char **argv, const char *prefix)
 {
 	char *remote;
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 03/13] submodule--helper: introduce get_default_remote_submodule()
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
  2021-09-07 11:59 ` [PATCH 01/13] submodule--helper: split up ensure_core_worktree() Atharva Raykar
  2021-09-07 11:59 ` [PATCH 02/13] submodule--helper: get remote names from any repository Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 11:59 ` [PATCH 04/13] submodule--helper: rename helpers for update-clone Atharva Raykar
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

Before 8ef1d2b549 (submodule--helper: get remote names from any
repository, 2021-07-20), it was not possible to directly retrieve a
submodule's remote name within the same process, because
`get_default_remote()` used only knew about the current repository.

Now that we have `repo_get_default_remote()`, we no longer have to start
a subprocess that called `submodule--helper get-default-remote` from
within the submodule directory.

Let's make a function called `get_default_remote_submodule()` which
takes a submodule path, and returns the default remote for that
submodule, all within the same process.

We can now use this function to save an unnecessary subprocess spawn in
`sync_submodule()`, and also in the next patch, which will require this
functionality.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1a65de4fa4..f6c4fc349b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -54,6 +54,19 @@ static char *repo_get_default_remote(struct repository *repo, const char *refnam
 	return ret;
 }
 
+static char *get_default_remote_submodule(const char *module_path)
+{
+	const char *refname;
+	const struct submodule *sub;
+	struct repository subrepo;
+
+	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
+					  "HEAD", 0, NULL, NULL);
+	sub = submodule_from_path(the_repository, null_oid(), module_path);
+	repo_submodule_init(&subrepo, the_repository, sub);
+	return repo_get_default_remote(&subrepo, refname);
+}
+
 static char *get_default_remote(void)
 {
 	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
@@ -1374,7 +1387,6 @@ static void sync_submodule(const char *path, const char *prefix,
 	char *remote_key = NULL;
 	char *sub_origin_url, *super_config_url, *displaypath;
 	struct strbuf sb = STRBUF_INIT;
-	struct child_process cp = CHILD_PROCESS_INIT;
 	char *sub_config_path = NULL;
 
 	if (!is_submodule_active(the_repository, path))
@@ -1423,14 +1435,9 @@ static void sync_submodule(const char *path, const char *prefix,
 	if (!is_submodule_populated_gently(path, NULL))
 		goto cleanup;
 
-	prepare_submodule_repo_env(&cp.env_array);
-	cp.git_cmd = 1;
-	cp.dir = path;
-	strvec_pushl(&cp.args, "submodule--helper",
-		     "print-default-remote", NULL);
-
 	strbuf_reset(&sb);
-	if (capture_command(&cp, &sb, 0))
+	strbuf_addstr(&sb, get_default_remote_submodule(path));
+	if (!sb.buf)
 		die(_("failed to get the default remote for submodule '%s'"),
 		      path);
 
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 04/13] submodule--helper: rename helpers for update-clone
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (2 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 03/13] submodule--helper: introduce get_default_remote_submodule() Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 11:59 ` [PATCH 05/13] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

The `update-clone` subcommand helpers that perform the parallel clone
and printing to stdout for shell script consumption, are renamed.

This lets us use the names `update_submodules()` and
`update_submodule()` for the helpers in the next patch, when we create
an `update` subcommand that does a full conversion.

We will get rid of these helpers in a cleanup patch at the end of this
series, when the `update-clone` command is no longer useful to us.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f6c4fc349b..b0336b0377 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2499,7 +2499,7 @@ static int do_run_update_procedure(struct update_data *ud)
 	return run_update_command(ud, subforce);
 }
 
-static void update_submodule(struct update_clone_data *ucd)
+static void update_clone_submodule(struct update_clone_data *ucd)
 {
 	fprintf(stdout, "dummy %s %d\t%s\n",
 		oid_to_hex(&ucd->oid),
@@ -2507,7 +2507,7 @@ static void update_submodule(struct update_clone_data *ucd)
 		ucd->sub->path);
 }
 
-static int update_submodules(struct submodule_update_clone *suc)
+static int update_clone_submodules(struct submodule_update_clone *suc)
 {
 	int i;
 
@@ -2528,7 +2528,7 @@ static int update_submodules(struct submodule_update_clone *suc)
 		return 1;
 
 	for (i = 0; i < suc->update_clone_nr; i++)
-		update_submodule(&suc->update_clone[i]);
+		update_clone_submodule(&suc->update_clone[i]);
 
 	return 0;
 }
@@ -2593,7 +2593,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	if (pathspec.nr)
 		suc.warn_if_uninitialized = 1;
 
-	return update_submodules(&suc);
+	return update_clone_submodules(&suc);
 }
 
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 05/13] submodule--helper: refactor get_submodule_displaypath()
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (3 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 04/13] submodule--helper: rename helpers for update-clone Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 11:59 ` [PATCH 06/13] submodule: move core cmd_update() logic to C Atharva Raykar
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

We create a function called `do_get_submodule_displaypath()` that
generates the display path required by several submodule functions, and
takes a custom superprefix parameter, instead of reading it from the
environment.

We then redefine the existing `get_submodule_displaypath()` function
as a call to this new function, where the superprefix is obtained from
the environment.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b0336b0377..10de01a1f7 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -269,11 +269,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
 	return 0;
 }
 
-/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *do_get_submodule_displaypath(const char *path, const char *prefix, const char *super_prefix)
 {
-	const char *super_prefix = get_super_prefix();
-
 	if (prefix && super_prefix) {
 		BUG("cannot have prefix '%s' and superprefix '%s'",
 		    prefix, super_prefix);
@@ -289,6 +286,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)
 	}
 }
 
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+	const char *super_prefix = get_super_prefix();
+	return do_get_submodule_displaypath(path, prefix, super_prefix);
+}
+
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
 	struct strbuf sb = STRBUF_INIT;
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 06/13] submodule: move core cmd_update() logic to C
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (4 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 05/13] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 12:40   ` Ævar Arnfjörð Bjarmason
  2021-09-07 11:59 ` [PATCH 07/13] submodule: remove fetch_in_submodule shell function Atharva Raykar
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

This patch completes the conversion past the flag parsing of
`submodule update` by introducing a helper subcommand called
`submodule--helper update`. The behaviour of `submodule update` should
remain the same after this patch.

We add more fields to the `struct update_data` that are required by
`struct submodule_update_clone` to be able to perform a clone, when that
is needed to be done.

Recursing on a submodule is done by calling a subprocess that launches
`submodule--helper update`, with a modified `--recursive-prefix` and
`--prefix` parameter.

We also introduce `update_submodules()` and `update_submodule()` which
are quite similar to `update_clone_submodules()` and
`update_clone_submodule()`, and will supersede them.

When the `--init` flag is passed to the subcommand, we do not spawn a
new subprocess and call `submodule--helper init` on the submodule paths,
because the Git machinery is not able to pick up the configuration
changes introduced by that init call[1]. So we instead run the
`init_submodule_cb()` callback over each submodule directly.

This introduces another problem, because there is no mechanism to pass
the superproject path prefix (ie, `--super-prefix`) without starting a
new git process. This field is required for obtaining the display path
for that is used by the command's output messages. So let's add a field
into the `init_cb` struct that lets us pass this information to
`init_submodule()`, which will now also take an explicit 'superprefix'
argument.

[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 502 ++++++++++++++++++++++++++++++------
 git-submodule.sh            | 131 +---------
 2 files changed, 430 insertions(+), 203 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 10de01a1f7..2cccb9a9ab 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -634,18 +634,22 @@ static char *compute_submodule_clone_url(const char *rel_url)
 
 struct init_cb {
 	const char *prefix;
+	const char *superprefix;
 	unsigned int flags;
 };
-#define INIT_CB_INIT { NULL, 0 }
+#define INIT_CB_INIT { NULL, NULL, 0 }
 
 static void init_submodule(const char *path, const char *prefix,
-			   unsigned int flags)
+			   const char *superprefix, unsigned int flags)
 {
 	const struct submodule *sub;
 	struct strbuf sb = STRBUF_INIT;
 	char *upd = NULL, *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	/* try superprefix from the environment, if it is not passed explicitly */
+	if (!superprefix)
+		superprefix = get_super_prefix();
+	displaypath = do_get_submodule_displaypath(path, prefix, superprefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -719,7 +723,7 @@ static void init_submodule(const char *path, const char *prefix,
 static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 {
 	struct init_cb *info = cb_data;
-	init_submodule(list_item->name, info->prefix, info->flags);
+	init_submodule(list_item->name, info->prefix, info->superprefix, info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
@@ -2039,7 +2043,6 @@ struct submodule_update_clone {
 	const char *prefix;
 	int single_branch;
 
-	/* to be consumed by git-submodule.sh */
 	struct update_clone_data *update_clone;
 	int update_clone_nr; int update_clone_alloc;
 
@@ -2062,19 +2065,63 @@ struct submodule_update_clone {
 }
 
 struct update_data {
+	const char *prefix;
 	const char *recursive_prefix;
 	const char *sm_path;
 	const char *displaypath;
 	struct object_id oid;
 	struct object_id suboid;
-	struct submodule_update_strategy update_strategy;
+	int max_jobs;
 	int depth;
+	int recommend_shallow;
+	int single_branch;
+	unsigned int init: 1;
 	unsigned int force: 1;
 	unsigned int quiet: 1;
 	unsigned int nofetch: 1;
-	unsigned int just_cloned: 1;
+	unsigned int remote: 1;
+	unsigned int recursive: 1;
+	unsigned int progress: 1;
+	unsigned int dissociate: 1;
+	unsigned int require_init: 1;
+	unsigned warn_if_uninitialized : 1;
+	unsigned int just_cloned : 1;
+	struct submodule_update_strategy update_strategy;
+	struct string_list references;
+	struct module_list list;
 };
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+	.list = MODULE_LIST_INIT, \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+	.recommend_shallow = -1, \
+	.references = STRING_LIST_INIT_DUP, \
+	.single_branch = -1, \
+	.max_jobs = 1, \
+}
+
+static void update_clone_from_update_data(struct submodule_update_clone *suc,
+					  struct update_data *update_data)
+{
+	suc->prefix = update_data->prefix;
+	suc->recursive_prefix = update_data->recursive_prefix;
+	suc->max_jobs = update_data->max_jobs;
+	suc->progress = update_data->progress;
+	suc->quiet = update_data->quiet;
+	suc->dissociate = update_data->dissociate;
+	suc->require_init = update_data->require_init;
+	suc->single_branch = update_data->single_branch;
+	suc->warn_if_uninitialized = update_data->warn_if_uninitialized;
+	suc->list = update_data->list;
+	suc->update = update_data->update_strategy;
+	suc->recommend_shallow = update_data->recommend_shallow;
+	if (update_data->depth)
+		suc->depth = xstrfmt("--depth=%d", update_data->depth);
+	if (update_data->references.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &update_data->references)
+			string_list_append(&suc->references, item->string);
+	}
+}
 
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
 		struct strbuf *out, const char *displaypath)
@@ -2369,111 +2416,113 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
 	return run_command(&cp);
 }
 
-static int run_update_command(struct update_data *ud, int subforce)
+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)
 {
-	struct strvec args = STRVEC_INIT;
-	struct strvec child_env = STRVEC_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
 	char *oid = oid_to_hex(&ud->oid);
+	struct strbuf out = STRBUF_INIT;
 	int must_die_on_failure = 0;
-	int git_cmd;
+	struct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;
 
-	switch (ud->update_strategy.type) {
+	if (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)
+		determine_submodule_update_strategy(the_repository, ud->just_cloned,
+						    ud->sm_path, NULL, &strategy);
+	else
+		strategy = ud->update_strategy;
+
+	cp.dir = xstrdup(ud->sm_path);
+	switch (strategy.type) {
 	case SM_UPDATE_CHECKOUT:
-		git_cmd = 1;
-		strvec_pushl(&args, "checkout", "-q", NULL);
+		cp.git_cmd = 1;
+		strvec_pushl(&cp.args, "checkout", "-q", NULL);
 		if (subforce)
-			strvec_push(&args, "-f");
+			strvec_push(&cp.args, "-f");
 		break;
 	case SM_UPDATE_REBASE:
-		git_cmd = 1;
-		strvec_push(&args, "rebase");
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "rebase");
 		if (ud->quiet)
-			strvec_push(&args, "--quiet");
+			strvec_push(&cp.args, "--quiet");
 		must_die_on_failure = 1;
 		break;
 	case SM_UPDATE_MERGE:
-		git_cmd = 1;
-		strvec_push(&args, "merge");
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "merge");
 		if (ud->quiet)
-			strvec_push(&args, "--quiet");
+			strvec_push(&cp.args, "--quiet");
 		must_die_on_failure = 1;
 		break;
 	case SM_UPDATE_COMMAND:
-		git_cmd = 0;
-		strvec_push(&args, ud->update_strategy.command);
+		cp.git_cmd = 0;
+		cp.use_shell = 1;
+		strvec_push(&cp.args, strategy.command);
 		must_die_on_failure = 1;
 		break;
 	default:
 		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+		    submodule_strategy_to_string(&strategy));
 	}
-	strvec_push(&args, oid);
+	strvec_push(&cp.args, oid);
 
-	prepare_submodule_repo_env(&child_env);
-	if (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,
-				     ud->sm_path, child_env.v)) {
-		switch (ud->update_strategy.type) {
-		case SM_UPDATE_CHECKOUT:
-			printf(_("Unable to checkout '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_REBASE:
-			printf(_("Unable to rebase '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_MERGE:
-			printf(_("Unable to merge '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_COMMAND:
-			printf(_("Execution of '%s %s' failed in submodule path '%s'"),
-			       ud->update_strategy.command, oid, ud->displaypath);
-			break;
-		default:
-			BUG("unexpected update strategy type: %s",
-			    submodule_strategy_to_string(&ud->update_strategy));
+	prepare_submodule_repo_env(&cp.env_array);
+	if (capture_command(&cp, &out, 0)) {
+		if (must_die_on_failure) {
+			switch (strategy.type) {
+			case SM_UPDATE_CHECKOUT:
+				die(_("Unable to checkout '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_REBASE:
+				die(_("Unable to rebase '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_MERGE:
+				die(_("Unable to merge '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_COMMAND:
+				die(_("Execution of '%s %s' failed in submodule path '%s'"),
+				    strategy.command, oid, ud->displaypath);
+				break;
+			default:
+				BUG("unexpected update strategy type: %s",
+				    submodule_strategy_to_string(&strategy));
+			}
 		}
-		/*
-		 * NEEDSWORK: We are currently printing to stdout with error
-		 * return so that the shell caller handles the error output
-		 * properly. Once we start handling the error messages within
-		 * C, we should use die() instead.
-		 */
-		if (must_die_on_failure)
-			return 2;
-		/*
-		 * This signifies to the caller in shell that the command
-		 * failed without dying
-		 */
+
+		/* the command failed, but update must continue */
+		string_list_append(err, out.buf);
 		return 1;
 	}
 
-	switch (ud->update_strategy.type) {
-	case SM_UPDATE_CHECKOUT:
-		printf(_("Submodule path '%s': checked out '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_REBASE:
-		printf(_("Submodule path '%s': rebased into '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_MERGE:
-		printf(_("Submodule path '%s': merged in '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_COMMAND:
-		printf(_("Submodule path '%s': '%s %s'\n"),
-		       ud->displaypath, ud->update_strategy.command, oid);
-		break;
-	default:
-		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+	if (!ud->quiet) {
+		switch (strategy.type) {
+		case SM_UPDATE_CHECKOUT:
+			printf(_("Submodule path '%s': checked out '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_REBASE:
+			printf(_("Submodule path '%s': rebased into '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_MERGE:
+			printf(_("Submodule path '%s': merged in '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_COMMAND:
+			printf(_("Submodule path '%s': '%s %s'\n"),
+			       ud->displaypath, strategy.command, oid);
+			break;
+		default:
+			BUG("unexpected update strategy type: %s",
+			    submodule_strategy_to_string(&strategy));
+		}
 	}
 
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud)
+static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2500,7 +2549,7 @@ static int do_run_update_procedure(struct update_data *ud)
 			    ud->displaypath, oid_to_hex(&ud->oid));
 	}
 
-	return run_update_command(ud, subforce);
+	return run_update_command(ud, subforce, err);
 }
 
 static void update_clone_submodule(struct update_clone_data *ucd)
@@ -2605,6 +2654,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
 	char *prefixed_path, *update = NULL;
 	struct update_data update_data = UPDATE_DATA_INIT;
+	struct string_list err = STRING_LIST_INIT_DUP;
 
 	struct option options[] = {
 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
@@ -2662,7 +2712,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	free(prefixed_path);
 
 	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data);
+		return do_run_update_procedure(&update_data, &err);
 
 	return 3;
 }
@@ -3038,6 +3088,288 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 	return !!ret;
 }
 
+static void update_data_to_args(struct update_data *update_data, struct strvec *args)
+{
+	const char *update = submodule_strategy_to_string(&update_data->update_strategy);
+
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
+	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
+	if (update_data->prefix)
+		strvec_pushl(args, "--prefix", update_data->prefix, NULL);
+	if (update_data->recursive_prefix)
+		strvec_pushl(args, "--recursive-prefix",
+			     update_data->recursive_prefix, NULL);
+	if (update_data->quiet)
+		strvec_push(args, "--quiet");
+	if (update_data->force)
+		strvec_push(args, "--force");
+	if (update_data->init)
+		strvec_push(args, "--init");
+	if (update_data->remote)
+		strvec_push(args, "--remote");
+	if (update_data->nofetch)
+		strvec_push(args, "--no-fetch");
+	if (update_data->dissociate)
+		strvec_push(args, "--dissociate");
+	if (update_data->progress)
+		strvec_push(args, "--progress");
+	if (update_data->require_init)
+		strvec_push(args, "--require-init");
+	if (update_data->depth)
+		strvec_pushf(args, "--depth=%d", update_data->depth);
+	if (update)
+		strvec_pushl(args, "--update", update, NULL);
+	if (update_data->references.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &update_data->references)
+			strvec_pushl(args, "--reference", item->string, NULL);
+	}
+	if (update_data->recommend_shallow == 0)
+		strvec_push(args, "--no-recommend-shallow");
+	else if (update_data->recommend_shallow == 1)
+		strvec_push(args, "--recommend-shallow");
+	if (update_data->single_branch >= 0)
+		strvec_push(args, "--single-branch");
+}
+
+static int update_submodule(struct update_data *update_data)
+{
+	char *prefixed_path;
+	struct string_list err = STRING_LIST_INIT_DUP;
+
+	do_ensure_core_worktree(update_data->sm_path);
+
+	if (update_data->recursive_prefix)
+		prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
+					update_data->sm_path);
+	else
+		prefixed_path = xstrdup(update_data->sm_path);
+
+	update_data->displaypath = get_submodule_displaypath(prefixed_path,
+							     update_data->prefix);
+	free(prefixed_path);
+
+	if (update_data->just_cloned) {
+		oidcpy(&update_data->suboid, null_oid());
+	} else {
+		if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
+			die(_("Unable to find current revision in submodule path '%s'"),
+			    update_data->displaypath);
+	}
+
+	if (update_data->remote) {
+		char *remote_name = get_default_remote_submodule(update_data->sm_path);
+		const char *branch = remote_submodule_branch(update_data->sm_path);
+		char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+
+		if (!update_data->nofetch) {
+			if(fetch_in_submodule(update_data->sm_path, update_data->depth,
+					      0, NULL))
+				die(_("Unable to fetch in submodule path '%s'"),
+				    update_data->sm_path);
+		}
+
+		if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
+			die(_("Unable to find %s revision in submodule path '%s'"),
+			    remote_ref, update_data->sm_path);
+
+		free(remote_ref);
+	}
+
+	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
+		if (do_run_update_procedure(update_data, &err))
+			return 1;
+
+	if (update_data->recursive) {
+		int res;
+		struct child_process cp = CHILD_PROCESS_INIT;
+		struct update_data next = *update_data;
+		char *die_msg = xstrfmt(_("Failed to recurse into submodule path '%s'"),
+					update_data->displaypath);
+
+		if (update_data->recursive_prefix)
+			prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
+						update_data->sm_path);
+		else
+			prefixed_path = xstrfmt("%s/", update_data->sm_path);
+
+		next.recursive_prefix = get_submodule_displaypath(prefixed_path,
+								  update_data->prefix);
+		next.prefix = NULL;
+		oidcpy(&next.oid, null_oid());
+		oidcpy(&next.suboid, null_oid());
+
+		cp.dir = update_data->sm_path;
+		cp.git_cmd = 1;
+		prepare_submodule_repo_env(&cp.env_array);
+		update_data_to_args(&next, &cp.args);
+
+		/* die() if child process die()'d */
+		if ((res = run_command(&cp)) == 128)
+			die("%s", die_msg);
+		if (res)
+			string_list_append(&err, die_msg);
+
+		free(die_msg);
+	}
+
+	if (err.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &err)
+			fputs(item->string, stderr);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int update_submodules(struct update_data *update_data)
+{
+	int i, res = 0;
+	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+
+	update_clone_from_update_data(&suc, update_data);
+	run_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,
+				   update_clone_start_failure,
+				   update_clone_task_finished, &suc, "submodule",
+				   "parallel/update");
+
+	/*
+	 * We saved the output and put it out all at once now.
+	 * That means:
+	 * - the listener does not have to interleave their (checkout)
+	 *   work with our fetching.  The writes involved in a
+	 *   checkout involve more straightforward sequential I/O.
+	 * - the listener can avoid doing any work if fetching failed.
+	 */
+	if (suc.quickstop)
+		return 1;
+
+	for (i = 0; i < suc.update_clone_nr; i++) {
+		struct update_clone_data ucd = suc.update_clone[i];
+
+		oidcpy(&update_data->oid, &ucd.oid);
+		update_data->just_cloned = ucd.just_cloned;
+		update_data->sm_path = ucd.sub->path;
+
+		if (update_submodule(update_data))
+			res = 1;
+	}
+
+	return res;
+}
+
+static int module_update(int argc, const char **argv, const char *prefix)
+{
+	int init = 0, force = 0, quiet = 0, nofetch = 0;
+	int remote = 0, recursive = 0, dissociate = 0;
+	int progress = 0, require_init = 0;
+	const char *update = NULL;
+	struct pathspec pathspec;
+	struct update_data update_data = UPDATE_DATA_INIT;
+
+	struct option module_update_clone_options[] = {
+		OPT__FORCE(&force, N_("force checkout updates"), 0),
+		OPT_BOOL(0, "init", &init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_BOOL(0, "remote", &remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_STRING(0, "prefix", &prefix,
+			   N_("path"),
+			   N_("path into the working tree")),
+		OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix,
+			   N_("path"),
+			   N_("path into the working tree, across nested "
+			      "submodule boundaries")),
+		OPT_STRING(0, "update", &update,
+			   N_("string"),
+			   N_("rebase, merge, checkout or none")),
+		OPT_STRING_LIST(0, "reference", &update_data.references, N_("repo"),
+				N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &dissociate,
+			 N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &update_data.depth,
+			    N_("create a shallow clone truncated to the "
+			       "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &update_data.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &update_data.recommend_shallow,
+			 N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &progress,
+			 N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &require_init,
+			 N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &update_data.single_branch,
+			 N_("clone only one branch, HEAD or --branch")),
+		OPT_END()
+	};
+
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
+		NULL
+	};
+
+	update_clone_config_from_gitmodules(&update_data.max_jobs);
+	git_config(git_update_clone_config, &update_data.max_jobs);
+
+	argc = parse_options(argc, argv, prefix, module_update_clone_options,
+			     git_submodule_helper_usage, 0);
+	update_data.prefix = prefix;
+
+	update_data.force = !!force;
+	update_data.quiet = !!quiet;
+	update_data.nofetch = !!nofetch;
+	update_data.init = !!init;
+	update_data.require_init = !!require_init;
+	update_data.remote = !!remote;
+	update_data.recursive = !!recursive;
+	update_data.progress = !!progress;
+	update_data.dissociate = !!dissociate;
+	oidcpy(&update_data.oid, null_oid());
+	oidcpy(&update_data.suboid, null_oid());
+
+	if (update)
+		if (parse_submodule_update_strategy(update,
+						    &update_data.update_strategy) < 0)
+			die(_("bad value for update parameter"));
+
+	if (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)
+		return 1;
+
+	if (pathspec.nr)
+		update_data.warn_if_uninitialized = 1;
+
+	if (update_data.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, update_data.prefix,
+					&pathspec, &list) < 0)
+			return 1;
+
+		/*
+		 * If there are no path args and submodule.active is set then,
+		 * by default, only initialize 'active' modules.
+		 */
+		if (!argc && git_config_get_value_multi("submodule.active"))
+			module_list_active(&list);
+
+		info.prefix = update_data.prefix;
+		info.superprefix = update_data.recursive_prefix;
+		if (update_data.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
+	return update_submodules(&update_data);
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
@@ -3213,6 +3545,7 @@ static int add_clone(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
+
 #define SUPPORT_SUPER_PREFIX (1<<0)
 
 struct cmd_struct {
@@ -3226,6 +3559,7 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add-clone", add_clone, 0},
+	{"update", module_update, 0},
 	{"update-module-mode", module_update_module_mode, 0},
 	{"update-clone", update_clone, 0},
 	{"run-update-procedure", run_update_procedure, 0},
diff --git a/git-submodule.sh b/git-submodule.sh
index f703cddce8..4e21d9715c 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -484,133 +484,26 @@ cmd_update()
 		shift
 	done
 
-	if test -n "$init"
-	then
-		cmd_init "--" "$@" || return
-	fi
-
-	{
-	git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
-		${progress:+"--progress"} \
+	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
+		${GIT_QUIET:+--quiet} \
+		${force:+--force} \
+		${progress:+--progress} \
+		${dissociate:+--dissociate} \
+		${remote:+--remote} \
+		${recursive:+--recursive} \
+		${init:+--init} \
+		${require_init:+--require-init} \
+		${nofetch:+--no-fetch} \
 		${wt_prefix:+--prefix "$wt_prefix"} \
 		${prefix:+--recursive-prefix "$prefix"} \
 		${update:+--update "$update"} \
 		${reference:+"$reference"} \
-		${dissociate:+"--dissociate"} \
-		${depth:+--depth "$depth"} \
-		${require_init:+--require-init} \
+		${depth:+"$depth"} \
 		$single_branch \
 		$recommend_shallow \
 		$jobs \
 		-- \
-		"$@" || echo "#unmatched" $?
-	} | {
-	err=
-	while read -r quickabort sha1 just_cloned sm_path
-	do
-		die_if_unmatched "$quickabort" "$sha1"
-
-		git submodule--helper ensure-core-worktree "$sm_path" || exit 1
-
-		displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
-
-		if test $just_cloned -eq 1
-		then
-			subsha1=
-		else
-			just_cloned=
-			subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
-				git rev-parse --verify HEAD) ||
-			die "fatal: $(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
-		fi
-
-		if test -n "$remote"
-		then
-			branch=$(git submodule--helper remote-branch "$sm_path")
-			if test -z "$nofetch"
-			then
-				# Fetch remote before determining tracking $sha1
-				fetch_in_submodule "$sm_path" $depth ||
-				die "fatal: $(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
-			fi
-			remote_name=$(sanitize_submodule_env; cd "$sm_path" && git submodule--helper print-default-remote)
-			sha1=$(sanitize_submodule_env; cd "$sm_path" &&
-				git rev-parse --verify "${remote_name}/${branch}") ||
-			die "fatal: $(eval_gettext "Unable to find current \${remote_name}/\${branch} revision in submodule path '\$sm_path'")"
-		fi
-
-		out=$(git submodule--helper run-update-procedure \
-			  ${wt_prefix:+--prefix "$wt_prefix"} \
-			  ${GIT_QUIET:+--quiet} \
-			  ${force:+--force} \
-			  ${just_cloned:+--just-cloned} \
-			  ${nofetch:+--no-fetch} \
-			  ${depth:+"$depth"} \
-			  ${update:+--update "$update"} \
-			  ${prefix:+--recursive-prefix "$prefix"} \
-			  ${sha1:+--oid "$sha1"} \
-			  ${subsha1:+--suboid "$subsha1"} \
-			  "--" \
-			  "$sm_path")
-
-		# exit codes for run-update-procedure:
-		# 0: update was successful, say command output
-		# 1: update procedure failed, but should not die
-		# 2 or 128: subcommand died during execution
-		# 3: no update procedure was run
-		res="$?"
-		case $res in
-		0)
-			say "$out"
-			;;
-		1)
-			err="${err};fatal: $out"
-			continue
-			;;
-		2|128)
-			die_with_status $res "fatal: $out"
-			;;
-		esac
-
-		if test -n "$recursive"
-		then
-			(
-				prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
-				wt_prefix=
-				sanitize_submodule_env
-				cd "$sm_path" &&
-				eval cmd_update
-			)
-			res=$?
-			if test $res -gt 0
-			then
-				die_msg="fatal: $(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
-				if test $res -ne 2
-				then
-					err="${err};$die_msg"
-					continue
-				else
-					die_with_status $res "$die_msg"
-				fi
-			fi
-		fi
-	done
-
-	if test -n "$err"
-	then
-		OIFS=$IFS
-		IFS=';'
-		for e in $err
-		do
-			if test -n "$e"
-			then
-				echo >&2 "$e"
-			fi
-		done
-		IFS=$OIFS
-		exit 1
-	fi
-	}
+		"$@"
 }
 
 #
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 07/13] submodule: remove fetch_in_submodule shell function
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (5 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 06/13] submodule: move core cmd_update() logic to C Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 12:44   ` Ævar Arnfjörð Bjarmason
  2021-09-07 11:59 ` [PATCH 08/13] submodule--helper: remove update-clone subcommand Atharva Raykar
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

This function has no more use in 'git-submodule.sh' after
bd82d7d467 (submodule: move core cmd_update() logic to C, 2021-07-20),
where we moved all of its uses to C, which has its own version for the
same.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 git-submodule.sh | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 4e21d9715c..5197de4551 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -369,20 +369,6 @@ cmd_deinit()
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
 }
 
-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]
-# Because arguments are positional, use an empty string to omit <depth>
-# but include <sha1>.
-fetch_in_submodule () (
-	sanitize_submodule_env &&
-	cd "$1" &&
-	if test $# -eq 3
-	then
-		echo "$3" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+"$2"}
-	else
-		git fetch ${GIT_QUIET:+--quiet} ${2:+"$2"}
-	fi
-)
-
 #
 # Update each submodule path to correct revision, using clone and checkout as needed
 #
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 08/13] submodule--helper: remove update-clone subcommand
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (6 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 07/13] submodule: remove fetch_in_submodule shell function Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 12:46   ` Ævar Arnfjörð Bjarmason
  2021-09-07 11:59 ` [PATCH 09/13] submodule--helper: remove update-module-mode subcommand Atharva Raykar
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

We no longer need this subcommand as the shell version calls the
'update' subcommand instead, which does all the cloning within C itself.

We also no longer need the 'update_clone_submodules()' and
'update_clone_submodule()' functions, so we remove those as well.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 98 -------------------------------------
 1 file changed, 98 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 2cccb9a9ab..a628660d6b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2552,103 +2552,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e
 	return run_update_command(ud, subforce, err);
 }
 
-static void update_clone_submodule(struct update_clone_data *ucd)
-{
-	fprintf(stdout, "dummy %s %d\t%s\n",
-		oid_to_hex(&ucd->oid),
-		ucd->just_cloned,
-		ucd->sub->path);
-}
-
-static int update_clone_submodules(struct submodule_update_clone *suc)
-{
-	int i;
-
-	run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
-				   update_clone_start_failure,
-				   update_clone_task_finished, suc, "submodule",
-				   "parallel/update");
-
-	/*
-	 * We saved the output and put it out all at once now.
-	 * That means:
-	 * - the listener does not have to interleave their (checkout)
-	 *   work with our fetching.  The writes involved in a
-	 *   checkout involve more straightforward sequential I/O.
-	 * - the listener can avoid doing any work if fetching failed.
-	 */
-	if (suc->quickstop)
-		return 1;
-
-	for (i = 0; i < suc->update_clone_nr; i++)
-		update_clone_submodule(&suc->update_clone[i]);
-
-	return 0;
-}
-
-static int update_clone(int argc, const char **argv, const char *prefix)
-{
-	const char *update = NULL;
-	struct pathspec pathspec;
-	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
-
-	struct option module_update_clone_options[] = {
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "recursive-prefix", &suc.recursive_prefix,
-			   N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_STRING(0, "update", &update,
-			   N_("string"),
-			   N_("rebase, merge, checkout or none")),
-		OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
-			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &suc.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
-			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
-		OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
-		OPT_BOOL(0, "progress", &suc.progress,
-			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &suc.require_init,
-			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &suc.single_branch,
-			 N_("clone only one branch, HEAD or --branch")),
-		OPT_END()
-	};
-
-	const char *const git_submodule_helper_usage[] = {
-		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
-		NULL
-	};
-	suc.prefix = prefix;
-
-	update_clone_config_from_gitmodules(&suc.max_jobs);
-	git_config(git_update_clone_config, &suc.max_jobs);
-
-	argc = parse_options(argc, argv, prefix, module_update_clone_options,
-			     git_submodule_helper_usage, 0);
-
-	if (update)
-		if (parse_submodule_update_strategy(update, &suc.update) < 0)
-			die(_("bad value for update parameter"));
-
-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
-		return 1;
-
-	if (pathspec.nr)
-		suc.warn_if_uninitialized = 1;
-
-	return update_clone_submodules(&suc);
-}
-
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
 {
 	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
@@ -3561,7 +3464,6 @@ static struct cmd_struct commands[] = {
 	{"add-clone", add_clone, 0},
 	{"update", module_update, 0},
 	{"update-module-mode", module_update_module_mode, 0},
-	{"update-clone", update_clone, 0},
 	{"run-update-procedure", run_update_procedure, 0},
 	{"ensure-core-worktree", ensure_core_worktree, 0},
 	{"relative-path", resolve_relative_path, 0},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 09/13] submodule--helper: remove update-module-mode subcommand
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (7 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 08/13] submodule--helper: remove update-clone subcommand Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 12:49   ` Ævar Arnfjörð Bjarmason
  2021-09-07 11:59 ` [PATCH 10/13] submodule--helper: remove shell interface to ensure_core_worktree() Atharva Raykar
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

This subcommand was once useful for 'submodule update', but now that we
have converted the shell code to C, it is no longer used.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a628660d6b..e3e85600c3 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1993,29 +1993,6 @@ static void determine_submodule_update_strategy(struct repository *r,
 	free(key);
 }
 
-static int module_update_module_mode(int argc, const char **argv, const char *prefix)
-{
-	const char *path, *update = NULL;
-	int just_cloned;
-	struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
-
-	if (argc < 3 || argc > 4)
-		die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
-
-	just_cloned = git_config_int("just_cloned", argv[1]);
-	path = argv[2];
-
-	if (argc == 4)
-		update = argv[3];
-
-	determine_submodule_update_strategy(the_repository,
-					    just_cloned, path, update,
-					    &update_strategy);
-	fputs(submodule_strategy_to_string(&update_strategy), stdout);
-
-	return 0;
-}
-
 struct update_clone_data {
 	const struct submodule *sub;
 	struct object_id oid;
@@ -3463,7 +3440,6 @@ static struct cmd_struct commands[] = {
 	{"clone", module_clone, 0},
 	{"add-clone", add_clone, 0},
 	{"update", module_update, 0},
-	{"update-module-mode", module_update_module_mode, 0},
 	{"run-update-procedure", run_update_procedure, 0},
 	{"ensure-core-worktree", ensure_core_worktree, 0},
 	{"relative-path", resolve_relative_path, 0},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 10/13] submodule--helper: remove shell interface to ensure_core_worktree()
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (8 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 09/13] submodule--helper: remove update-module-mode subcommand Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 11:59 ` [PATCH 11/13] submodule--helper: remove print-default-remote subcommand Atharva Raykar
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

The 'ensure-core-worktree' subcommand is no longer needed since the
conversion of the update code from shell to C.

Let's remove the subcommand, and while we are at it, let's rename
'do_ensure_core_worktree()' to 'ensure_core_worktree()' to signal that
it is no longer a utility function meant to be called by another
function.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index e3e85600c3..597e303889 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2740,7 +2740,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
-static void do_ensure_core_worktree(const char *path)
+static void ensure_core_worktree(const char *path)
 {
 	const struct submodule *sub;
 	const char *cw;
@@ -2771,19 +2771,6 @@ static void do_ensure_core_worktree(const char *path)
 	}
 }
 
-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
-{
-	const char *path;
-
-	if (argc != 2)
-		BUG("submodule--helper ensure-core-worktree <path>");
-
-	path = argv[1];
-	do_ensure_core_worktree(path);
-
-	return 0;
-}
-
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -3017,7 +3004,7 @@ static int update_submodule(struct update_data *update_data)
 	char *prefixed_path;
 	struct string_list err = STRING_LIST_INIT_DUP;
 
-	do_ensure_core_worktree(update_data->sm_path);
+	ensure_core_worktree(update_data->sm_path);
 
 	if (update_data->recursive_prefix)
 		prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
@@ -3441,7 +3428,6 @@ static struct cmd_struct commands[] = {
 	{"add-clone", add_clone, 0},
 	{"update", module_update, 0},
 	{"run-update-procedure", run_update_procedure, 0},
-	{"ensure-core-worktree", ensure_core_worktree, 0},
 	{"relative-path", resolve_relative_path, 0},
 	{"resolve-relative-url", resolve_relative_url, 0},
 	{"resolve-relative-url-test", resolve_relative_url_test, 0},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 11/13] submodule--helper: remove print-default-remote subcommand
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (9 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 10/13] submodule--helper: remove shell interface to ensure_core_worktree() Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 11:59 ` [PATCH 12/13] submodule--helper: remove relative-path subcommand Atharva Raykar
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

This subcommand was once useful for submodule functionality, but after
the various conversions of shell code to C, it is no longer used.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 597e303889..9470ff3de0 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -73,21 +73,6 @@ static char *get_default_remote(void)
 	return repo_get_default_remote(the_repository, refname);
 }
 
-static int print_default_remote(int argc, const char **argv, const char *prefix)
-{
-	char *remote;
-
-	if (argc != 1)
-		die(_("submodule--helper print-default-remote takes no arguments"));
-
-	remote = get_default_remote();
-	if (remote)
-		printf("%s\n", remote);
-
-	free(remote);
-	return 0;
-}
-
 static int starts_with_dot_slash(const char *str)
 {
 	return str[0] == '.' && is_dir_sep(str[1]);
@@ -3434,7 +3419,6 @@ static struct cmd_struct commands[] = {
 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
 	{"init", module_init, SUPPORT_SUPER_PREFIX},
 	{"status", module_status, SUPPORT_SUPER_PREFIX},
-	{"print-default-remote", print_default_remote, 0},
 	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
 	{"deinit", module_deinit, 0},
 	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 12/13] submodule--helper: remove relative-path subcommand
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (10 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 11/13] submodule--helper: remove print-default-remote subcommand Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 11:59 ` [PATCH 13/13] submodule--helper: remove run-update-procedure subcommand Atharva Raykar
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

This subcommand was once used extensively for submodule functionality
when it was written in shell, but now that we have converted the shell
code to C, it is no longer used.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9470ff3de0..7622d6bd24 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2582,17 +2582,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	return 3;
 }
 
-static int resolve_relative_path(int argc, const char **argv, const char *prefix)
-{
-	struct strbuf sb = STRBUF_INIT;
-	if (argc != 3)
-		die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
-
-	printf("%s", relative_path(argv[1], argv[2], &sb));
-	strbuf_release(&sb);
-	return 0;
-}
-
 static const char *remote_submodule_branch(const char *path)
 {
 	const struct submodule *sub;
@@ -3413,7 +3402,6 @@ static struct cmd_struct commands[] = {
 	{"add-clone", add_clone, 0},
 	{"update", module_update, 0},
 	{"run-update-procedure", run_update_procedure, 0},
-	{"relative-path", resolve_relative_path, 0},
 	{"resolve-relative-url", resolve_relative_url, 0},
 	{"resolve-relative-url-test", resolve_relative_url_test, 0},
 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 13/13] submodule--helper: remove run-update-procedure subcommand
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (11 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 12/13] submodule--helper: remove relative-path subcommand Atharva Raykar
@ 2021-09-07 11:59 ` Atharva Raykar
  2021-09-07 12:34 ` [PATCH 00/13] submodule: convert the rest of 'update' to C Ævar Arnfjörð Bjarmason
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 11:59 UTC (permalink / raw)
  To: git
  Cc: christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip, avarab, Atharva Raykar

The subcommand 'submodule--helper run-update-procedure' is no longer
needed after the conversion of the bulk of 'update' to C.

While we are at it, let's rename 'do_run_update_procedure()' to
'run_update_procedure()' to reflect the fact that it is no longer a
utility function meant to be wrapped in another function.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 73 +------------------------------------
 1 file changed, 2 insertions(+), 71 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 7622d6bd24..6565e2cd78 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2484,7 +2484,7 @@ static int run_update_command(struct update_data *ud, int subforce, struct strin
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
+static int run_update_procedure(struct update_data *ud, struct string_list *err)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2514,74 +2514,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e
 	return run_update_command(ud, subforce, err);
 }
 
-static int run_update_procedure(int argc, const char **argv, const char *prefix)
-{
-	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
-	char *prefixed_path, *update = NULL;
-	struct update_data update_data = UPDATE_DATA_INIT;
-	struct string_list err = STRING_LIST_INIT_DUP;
-
-	struct option options[] = {
-		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
-		OPT__FORCE(&force, N_("force checkout updates"), 0),
-		OPT_BOOL('N', "no-fetch", &nofetch,
-			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &just_cloned,
-			 N_("overrides update mode in case the repository is a fresh clone")),
-		OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")),
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "update", &update,
-			   N_("string"),
-			   N_("rebase, merge, checkout or none")),
-		OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix, N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
-			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_CALLBACK_F(0, "suboid", &update_data.suboid, N_("subsha1"),
-			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_END()
-	};
-
-	const char *const usage[] = {
-		N_("git submodule--helper run-update-procedure [<options>] <path>"),
-		NULL
-	};
-
-	argc = parse_options(argc, argv, prefix, options, usage, 0);
-
-	if (argc != 1)
-		usage_with_options(usage, options);
-
-	update_data.force = !!force;
-	update_data.quiet = !!quiet;
-	update_data.nofetch = !!nofetch;
-	update_data.just_cloned = !!just_cloned;
-	update_data.sm_path = argv[0];
-
-	if (update_data.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
-	else
-		prefixed_path = xstrdup(update_data.sm_path);
-
-	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
-
-	determine_submodule_update_strategy(the_repository, update_data.just_cloned,
-					    update_data.sm_path, update,
-					    &update_data.update_strategy);
-
-	free(prefixed_path);
-
-	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data, &err);
-
-	return 3;
-}
-
 static const char *remote_submodule_branch(const char *path)
 {
 	const struct submodule *sub;
@@ -3018,7 +2950,7 @@ static int update_submodule(struct update_data *update_data)
 	}
 
 	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
-		if (do_run_update_procedure(update_data, &err))
+		if (run_update_procedure(update_data, &err))
 			return 1;
 
 	if (update_data->recursive) {
@@ -3401,7 +3333,6 @@ static struct cmd_struct commands[] = {
 	{"clone", module_clone, 0},
 	{"add-clone", add_clone, 0},
 	{"update", module_update, 0},
-	{"run-update-procedure", run_update_procedure, 0},
 	{"resolve-relative-url", resolve_relative_url, 0},
 	{"resolve-relative-url-test", resolve_relative_url_test, 0},
 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/13] submodule: convert the rest of 'update' to C
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (12 preceding siblings ...)
  2021-09-07 11:59 ` [PATCH 13/13] submodule--helper: remove run-update-procedure subcommand Atharva Raykar
@ 2021-09-07 12:34 ` Ævar Arnfjörð Bjarmason
  2021-09-07 12:53   ` Atharva Raykar
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
  2021-10-14 21:50 ` [PATCH 00/13] " Glen Choo
  15 siblings, 1 reply; 56+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-07 12:34 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


On Tue, Sep 07 2021, Atharva Raykar wrote:

> NOTE: This series uses ar/submodule-run-update-procedure [1]
>
> This series builds upon the previous conversion work on 'submodule update' and
> moves out all of that shell logic in 'git-submodule.sh' into
> 'builtin/submodule--helper.c'. Even though this patch series looks long, a lot
> of it is preparatory patches and cleanup of unused functions that result from
> this conversion. The real action happens at [6/8].

It looks like the 6/x part of that still applies, but not the "/8",
i.e. this is now a 13-part series. Is this summary otherwise still
current with what's being submitted here?

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 02/13] submodule--helper: get remote names from any repository
  2021-09-07 11:59 ` [PATCH 02/13] submodule--helper: get remote names from any repository Atharva Raykar
@ 2021-09-07 12:37   ` Ævar Arnfjörð Bjarmason
  2021-09-07 13:33     ` Atharva Raykar
  0 siblings, 1 reply; 56+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-07 12:37 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


On Tue, Sep 07 2021, Atharva Raykar wrote:

> `get_default_remote()` retrieves the name of a remote by resolving the
> refs from of the current repository's ref store.
>
> Thus in order to use it for retrieving the remote name of a submodule,
> we have to start a new subprocess which runs from the submodule
> directory.
>
> Let's instead introduce a function called `repo_get_default_remote()`
> which takes any repository object and retrieves the remote accordingly.
>
> `get_default_remote()` is then defined as a call to
> `repo_get_default_remote()` with 'the_repository' passed to it.

I'd find this easier to follow if this were just squashed into the next
commit. Both are rather small, but following the context of first adding
a function, then using it, instead of just adding it, changing the old
users etc. is harder than just having it in one commit.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 06/13] submodule: move core cmd_update() logic to C
  2021-09-07 11:59 ` [PATCH 06/13] submodule: move core cmd_update() logic to C Atharva Raykar
@ 2021-09-07 12:40   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 56+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-07 12:40 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


On Tue, Sep 07 2021, Atharva Raykar wrote:

>  struct init_cb {
>  	const char *prefix;
> +	const char *superprefix;
>  	unsigned int flags;
>  };
> -#define INIT_CB_INIT { NULL, 0 }
> +#define INIT_CB_INIT { NULL, NULL, 0 }

Since you're doing some cleanup while you're at it, just changing this
in some earlier step to:

    define INIT_CB_INIT { 0 }

Is better, i.e. the NULL-ing out is implicit here. I have an unsubmitted
series that does that across the codebase.

> +	.references = STRING_LIST_INIT_DUP, \

We do inits here, and append, but it seems nothing clears this string_list.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 07/13] submodule: remove fetch_in_submodule shell function
  2021-09-07 11:59 ` [PATCH 07/13] submodule: remove fetch_in_submodule shell function Atharva Raykar
@ 2021-09-07 12:44   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 56+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-07 12:44 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


On Tue, Sep 07 2021, Atharva Raykar wrote:

> This function has no more use in 'git-submodule.sh' after
> bd82d7d467 (submodule: move core cmd_update() logic to C, 2021-07-20),
> where we moved all of its uses to C, which has its own version for the
> same.

This commit ID appears to be a reference to your own 06/13, so the OID
won't work once this is merged to git.git.

Perhaps just squash this into 06/13 instead?

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 08/13] submodule--helper: remove update-clone subcommand
  2021-09-07 11:59 ` [PATCH 08/13] submodule--helper: remove update-clone subcommand Atharva Raykar
@ 2021-09-07 12:46   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 56+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-07 12:46 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


On Tue, Sep 07 2021, Atharva Raykar wrote:

> We no longer need this subcommand as the shell version calls the
> 'update' subcommand instead, which does all the cloning within C itself.
>
> We also no longer need the 'update_clone_submodules()' and
> 'update_clone_submodule()' functions, so we remove those as well.

So in 04/13 update_clone_submodules() was renamed, but now we're getting
rid of it. Maybe there's not an easy way to avoid this churn, but if there is...

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 09/13] submodule--helper: remove update-module-mode subcommand
  2021-09-07 11:59 ` [PATCH 09/13] submodule--helper: remove update-module-mode subcommand Atharva Raykar
@ 2021-09-07 12:49   ` Ævar Arnfjörð Bjarmason
  2021-09-07 13:50     ` Atharva Raykar
  0 siblings, 1 reply; 56+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-07 12:49 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


On Tue, Sep 07 2021, Atharva Raykar wrote:

> This subcommand was once useful for 'submodule update', but now that we
> have converted the shell code to C, it is no longer used.
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Shourya Shukla <periperidip@gmail.com>
> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
> ---
>  builtin/submodule--helper.c | 24 ------------------------
>  1 file changed, 24 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index a628660d6b..e3e85600c3 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -1993,29 +1993,6 @@ static void determine_submodule_update_strategy(struct repository *r,
>  	free(key);
>  }
>  
> -static int module_update_module_mode(int argc, const char **argv, const char *prefix)
> -{
> -	const char *path, *update = NULL;
> -	int just_cloned;
> -	struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
> -
> -	if (argc < 3 || argc > 4)
> -		die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
> -
> -	just_cloned = git_config_int("just_cloned", argv[1]);
> -	path = argv[2];
> -
> -	if (argc == 4)
> -		update = argv[3];
> -
> -	determine_submodule_update_strategy(the_repository,
> -					    just_cloned, path, update,
> -					    &update_strategy);
> -	fputs(submodule_strategy_to_string(&update_strategy), stdout);
> -
> -	return 0;
> -}
> -
>  struct update_clone_data {
>  	const struct submodule *sub;
>  	struct object_id oid;
> @@ -3463,7 +3440,6 @@ static struct cmd_struct commands[] = {
>  	{"clone", module_clone, 0},
>  	{"add-clone", add_clone, 0},
>  	{"update", module_update, 0},
> -	{"update-module-mode", module_update_module_mode, 0},
>  	{"run-update-procedure", run_update_procedure, 0},
>  	{"ensure-core-worktree", ensure_core_worktree, 0},
>  	{"relative-path", resolve_relative_path, 0},

So in https://lore.kernel.org/git/87sfyglfl9.fsf@evledraar.gmail.com I
suggested squashing the shell removal, but I see now that here later in
09-13/13.

So yeah, having 08/13 stand-alone is easier to read then, but I think
then squashing all of 09-13 together is better. I.e. there's no reason
to remove these one at a time, let's just remove them all at once.

That also makes it clear that it's a remove-only change aside from your
"refactor while at it" of renaming this function:

    -static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
    +static int run_update_procedure(struct update_data *ud, struct string_list *err)

We could either skip that, or split that later refactoring into another
commit.

Thanks for working on this, I'm exciting to see more of git-submodule.sh
go away. Hopefully these comments I left are useful / will aid future
reviewer readability of this series.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/13] submodule: convert the rest of 'update' to C
  2021-09-07 12:34 ` [PATCH 00/13] submodule: convert the rest of 'update' to C Ævar Arnfjörð Bjarmason
@ 2021-09-07 12:53   ` Atharva Raykar
  0 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 12:53 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Tue, Sep 07 2021, Atharva Raykar wrote:
>
>> NOTE: This series uses ar/submodule-run-update-procedure [1]
>>
>> This series builds upon the previous conversion work on 'submodule update' and
>> moves out all of that shell logic in 'git-submodule.sh' into
>> 'builtin/submodule--helper.c'. Even though this patch series looks long, a lot
>> of it is preparatory patches and cleanup of unused functions that result from
>> this conversion. The real action happens at [6/8].
>
> It looks like the 6/x part of that still applies, but not the "/8",
> i.e. this is now a 13-part series. Is this summary otherwise still
> current with what's being submitted here?

Sorry, I meant [6/13], this is meant to be 13 parts only. Other than
that typo, the summary is up-to-date with what the series contains (I
wrote all of it today).

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 02/13] submodule--helper: get remote names from any repository
  2021-09-07 12:37   ` Ævar Arnfjörð Bjarmason
@ 2021-09-07 13:33     ` Atharva Raykar
  0 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 13:33 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Tue, Sep 07 2021, Atharva Raykar wrote:
>
>> `get_default_remote()` retrieves the name of a remote by resolving the
>> refs from of the current repository's ref store.
>>
>> Thus in order to use it for retrieving the remote name of a submodule,
>> we have to start a new subprocess which runs from the submodule
>> directory.
>>
>> Let's instead introduce a function called `repo_get_default_remote()`
>> which takes any repository object and retrieves the remote accordingly.
>>
>> `get_default_remote()` is then defined as a call to
>> `repo_get_default_remote()` with 'the_repository' passed to it.
>
> I'd find this easier to follow if this were just squashed into the next
> commit. Both are rather small, but following the context of first adding
> a function, then using it, instead of just adding it, changing the old
> users etc. is harder than just having it in one commit.

I am in two minds about this. I initially had both these changes in one
commit, but Christian suggested I split the changes into a part that
refactors existing code (this commit), and one that introduces a new
helper (the next commit).

I guess I will squash it for now and see how it is received. Maybe
bringing down the "/13" might help get more reviews ;-)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 09/13] submodule--helper: remove update-module-mode subcommand
  2021-09-07 12:49   ` Ævar Arnfjörð Bjarmason
@ 2021-09-07 13:50     ` Atharva Raykar
  0 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-07 13:50 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, christian.couder, emilyshaffer, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Tue, Sep 07 2021, Atharva Raykar wrote:
>
>> This subcommand was once useful for 'submodule update', but now that we
>> have converted the shell code to C, it is no longer used.
>>
>> Mentored-by: Christian Couder <christian.couder@gmail.com>
>> Mentored-by: Shourya Shukla <periperidip@gmail.com>
>> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
>> ---
>>  builtin/submodule--helper.c | 24 ------------------------
>>  1 file changed, 24 deletions(-)
>>
>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
>> index a628660d6b..e3e85600c3 100644
>> --- a/builtin/submodule--helper.c
>> +++ b/builtin/submodule--helper.c
>> @@ -1993,29 +1993,6 @@ static void determine_submodule_update_strategy(struct repository *r,
>>  	free(key);
>>  }
>>
>> -static int module_update_module_mode(int argc, const char **argv, const char *prefix)
>> -{
>> -	const char *path, *update = NULL;
>> -	int just_cloned;
>> -	struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
>> -
>> -	if (argc < 3 || argc > 4)
>> -		die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
>> -
>> -	just_cloned = git_config_int("just_cloned", argv[1]);
>> -	path = argv[2];
>> -
>> -	if (argc == 4)
>> -		update = argv[3];
>> -
>> -	determine_submodule_update_strategy(the_repository,
>> -					    just_cloned, path, update,
>> -					    &update_strategy);
>> -	fputs(submodule_strategy_to_string(&update_strategy), stdout);
>> -
>> -	return 0;
>> -}
>> -
>>  struct update_clone_data {
>>  	const struct submodule *sub;
>>  	struct object_id oid;
>> @@ -3463,7 +3440,6 @@ static struct cmd_struct commands[] = {
>>  	{"clone", module_clone, 0},
>>  	{"add-clone", add_clone, 0},
>>  	{"update", module_update, 0},
>> -	{"update-module-mode", module_update_module_mode, 0},
>>  	{"run-update-procedure", run_update_procedure, 0},
>>  	{"ensure-core-worktree", ensure_core_worktree, 0},
>>  	{"relative-path", resolve_relative_path, 0},
>
> So in https://lore.kernel.org/git/87sfyglfl9.fsf@evledraar.gmail.com I
> suggested squashing the shell removal, but I see now that here later in
> 09-13/13.
>
> So yeah, having 08/13 stand-alone is easier to read then, but I think
> then squashing all of 09-13 together is better. I.e. there's no reason
> to remove these one at a time, let's just remove them all at once.

Okay, I shall do this.

> That also makes it clear that it's a remove-only change aside from your
> "refactor while at it" of renaming this function:
>
>     -static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
>     +static int run_update_procedure(struct update_data *ud, struct string_list *err)
>
> We could either skip that, or split that later refactoring into another
> commit.
>
> Thanks for working on this, I'm exciting to see more of git-submodule.sh
> go away. Hopefully these comments I left are useful / will aid future
> reviewer readability of this series.

Thanks for your suggestions. I've gone through all of them, and I'll
reroll soon.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 0/8] submodule: convert the rest of 'update' to C
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (13 preceding siblings ...)
  2021-09-07 12:34 ` [PATCH 00/13] submodule: convert the rest of 'update' to C Ævar Arnfjörð Bjarmason
@ 2021-09-16 10:32 ` Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 1/8] submodule--helper: split up ensure_core_worktree() Atharva Raykar
                     ` (8 more replies)
  2021-10-14 21:50 ` [PATCH 00/13] " Glen Choo
  15 siblings, 9 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

NOTE: This series uses ar/submodule-run-update-procedure, which is now part of
'next'. [1]

Since v1:
  I have incorporated Ævar's suggestions, and attempted to make this easier to
  review.

This series builds upon the previous conversion work on 'submodule update' and
moves out all of that shell logic in 'git-submodule.sh' into
'builtin/submodule--helper.c'. Even though this patch series looks a bit long, a
lot of it is preparatory patches and cleanup of unused functions that result
from this conversion. The real action happens at [5/8].

As with the other series, the goal is to be a faithful conversion, with no
change in behaviour.

This would be the last command whose logic would be moved into C, other than
'submodule add', whose patches have been sent already.

After this works out, we can invert the shell-C relationship and make
'submodule' a proper C builtin.

Fetch-it-Via:
git fetch https://github.com/tfidfwastaken/git submodule-update-list-2

[1] https://lore.kernel.org/git/20210824140609.1496-1-raykar.ath@gmail.com/

Atharva Raykar (8):
  submodule--helper: split up ensure_core_worktree()
  submodule--helper: get remote names from any repository
  submodule--helper: rename helpers for update-clone
  submodule--helper: refactor get_submodule_displaypath()
  submodule: move core cmd_update() logic to C
  submodule--helper: remove update-clone subcommand
  submodule--helper: remove unused helpers
  submodule--helper: rename helper functions

 builtin/submodule--helper.c | 767 +++++++++++++++++++++---------------
 git-submodule.sh            | 145 +------
 2 files changed, 458 insertions(+), 454 deletions(-)

Range-diff against v1:
 1:  2cfdc0e10a <  -:  ---------- submodule--helper: get remote names from any repository
 -:  ---------- >  1:  f83a5b7f34 submodule--helper: split up ensure_core_worktree()
 2:  be83ba7fdb !  2:  7f4e24ce25 submodule--helper: introduce get_default_remote_submodule()
    @@ Metadata
     Author: Atharva Raykar <raykar.ath@gmail.com>
     
      ## Commit message ##
    -    submodule--helper: introduce get_default_remote_submodule()
    +    submodule--helper: get remote names from any repository
     
    -    Before 8ef1d2b549 (submodule--helper: get remote names from any
    -    repository, 2021-07-20), it was not possible to directly retrieve a
    -    submodule's remote name within the same process, because
    -    `get_default_remote()` used only knew about the current repository.
    +    `get_default_remote()` retrieves the name of a remote by resolving the
    +    refs from of the current repository's ref store.
    +
    +    Thus in order to use it for retrieving the remote name of a submodule,
    +    we have to start a new subprocess which runs from the submodule
    +    directory.
    +
    +    Let's instead introduce a function called `repo_get_default_remote()`
    +    which takes any repository object and retrieves the remote accordingly.
    +
    +    `get_default_remote()` is then defined as a call to
    +    `repo_get_default_remote()` with 'the_repository' passed to it.
     
         Now that we have `repo_get_default_remote()`, we no longer have to start
         a subprocess that called `submodule--helper get-default-remote` from
         within the submodule directory.
     
    -    Let's make a function called `get_default_remote_submodule()` which
    +    So let's make a function called `get_default_remote_submodule()` which
         takes a submodule path, and returns the default remote for that
         submodule, all within the same process.
     
    @@ Commit message
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
     
      ## builtin/submodule--helper.c ##
    -@@ builtin/submodule--helper.c: static char *repo_get_default_remote(struct repository *repo, const char *refnam
    +@@
    + typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
    + 				  void *cb_data);
    + 
    +-static char *get_default_remote(void)
    ++static char *repo_get_default_remote(struct repository *repo, const char *refname)
    + {
    + 	char *dest = NULL, *ret;
    + 	struct strbuf sb = STRBUF_INIT;
    +-	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
    + 
    + 	if (!refname)
    + 		die(_("No such ref: %s"), "HEAD");
    +@@ builtin/submodule--helper.c: static char *get_default_remote(void)
    + 		die(_("Expecting a full ref name, got %s"), refname);
    + 
    + 	strbuf_addf(&sb, "branch.%s.remote", refname);
    +-	if (git_config_get_string(sb.buf, &dest))
    ++	if (repo_config_get_string(repo, sb.buf, &dest))
    + 		ret = xstrdup("origin");
    + 	else
    + 		ret = dest;
    +@@ builtin/submodule--helper.c: static char *get_default_remote(void)
      	return ret;
      }
      
    @@ builtin/submodule--helper.c: static char *repo_get_default_remote(struct reposit
     +	return repo_get_default_remote(&subrepo, refname);
     +}
     +
    - static char *get_default_remote(void)
    ++static char *get_default_remote(void)
    ++{
    ++	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
    ++	return repo_get_default_remote(the_repository, refname);
    ++}
    ++
    + static int print_default_remote(int argc, const char **argv, const char *prefix)
      {
    - 	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
    + 	char *remote;
     @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const char *prefix,
      	char *remote_key = NULL;
      	char *sub_origin_url, *super_config_url, *displaypath;
 3:  8981b2c4c5 =  3:  390596ee7c submodule--helper: rename helpers for update-clone
 4:  420d792f99 =  4:  2a2ddcac91 submodule--helper: refactor get_submodule_displaypath()
 5:  6c4696b70a !  5:  832020a290 submodule: move core cmd_update() logic to C
    @@ Commit message
         `init_submodule()`, which will now also take an explicit 'superprefix'
         argument.
     
    +    While we are at it, we also remove the fetch_in_submodule() shell
    +    function since it is no longer used anywhere.
    +
         [1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/
     
         Mentored-by: Christian Couder <christian.couder@gmail.com>
    @@ builtin/submodule--helper.c: static char *compute_submodule_clone_url(const char
      	unsigned int flags;
      };
     -#define INIT_CB_INIT { NULL, 0 }
    -+#define INIT_CB_INIT { NULL, NULL, 0 }
    ++#define INIT_CB_INIT { 0 }
      
      static void init_submodule(const char *path, const char *prefix,
     -			   unsigned int flags)
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +	 *   checkout involve more straightforward sequential I/O.
     +	 * - the listener can avoid doing any work if fetching failed.
     +	 */
    -+	if (suc.quickstop)
    ++	if (suc.quickstop) {
    ++		string_list_clear(&update_data->references, 0);
     +		return 1;
    ++	}
     +
     +	for (i = 0; i < suc.update_clone_nr; i++) {
     +		struct update_clone_data ucd = suc.update_clone[i];
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +			res = 1;
     +	}
     +
    ++	string_list_clear(&update_data->references, 0);
     +	return res;
     +}
     +
    @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {
      	{"run-update-procedure", run_update_procedure, 0},
     
      ## git-submodule.sh ##
    +@@ git-submodule.sh: cmd_deinit()
    + 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
    + }
    + 
    +-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]
    +-# Because arguments are positional, use an empty string to omit <depth>
    +-# but include <sha1>.
    +-fetch_in_submodule () (
    +-	sanitize_submodule_env &&
    +-	cd "$1" &&
    +-	if test $# -eq 3
    +-	then
    +-		echo "$3" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+"$2"}
    +-	else
    +-		git fetch ${GIT_QUIET:+--quiet} ${2:+"$2"}
    +-	fi
    +-)
    +-
    + #
    + # Update each submodule path to correct revision, using clone and checkout as needed
    + #
     @@ git-submodule.sh: cmd_update()
      		shift
      	done
 6:  524ae77c3f <  -:  ---------- submodule: remove fetch_in_submodule shell function
 7:  ea56f7319a =  6:  fb3fa8174a submodule--helper: remove update-clone subcommand
 8:  10a62172a2 <  -:  ---------- submodule--helper: remove update-module-mode subcommand
 9:  dbbe5d3f53 <  -:  ---------- submodule--helper: remove shell interface to ensure_core_worktree()
10:  a015af3a16 <  -:  ---------- submodule--helper: remove print-default-remote subcommand
11:  f5a7ba1405 <  -:  ---------- submodule--helper: remove relative-path subcommand
12:  9f54eb5972 !  7:  364f72f870 submodule--helper: remove run-update-procedure subcommand
    @@ Metadata
     Author: Atharva Raykar <raykar.ath@gmail.com>
     
      ## Commit message ##
    -    submodule--helper: remove run-update-procedure subcommand
    +    submodule--helper: remove unused helpers
     
    -    The subcommand 'submodule--helper run-update-procedure' is no longer
    -    needed after the conversion of the bulk of 'update' to C.
    -
    -    While we are at it, let's rename 'do_run_update_procedure()' to
    -    'run_update_procedure()' to reflect the fact that it is no longer a
    -    utility function meant to be wrapped in another function.
    +    These helpers were useful back when 'submodule update' had most of its
    +    logic in shell. Now that they will never be invoked, let us remove them.
     
         Mentored-by: Christian Couder <christian.couder@gmail.com>
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
     
      ## builtin/submodule--helper.c ##
    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce, struct strin
    - 	return 0;
    +@@ builtin/submodule--helper.c: static char *get_default_remote(void)
    + 	return repo_get_default_remote(the_repository, refname);
      }
      
    --static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
    -+static int run_update_procedure(struct update_data *ud, struct string_list *err)
    +-static int print_default_remote(int argc, const char **argv, const char *prefix)
    +-{
    +-	char *remote;
    +-
    +-	if (argc != 1)
    +-		die(_("submodule--helper print-default-remote takes no arguments"));
    +-
    +-	remote = get_default_remote();
    +-	if (remote)
    +-		printf("%s\n", remote);
    +-
    +-	free(remote);
    +-	return 0;
    +-}
    +-
    + static int starts_with_dot_slash(const char *str)
      {
    - 	int subforce = is_null_oid(&ud->suboid) || ud->force;
    + 	return str[0] == '.' && is_dir_sep(str[1]);
    +@@ builtin/submodule--helper.c: static void determine_submodule_update_strategy(struct repository *r,
    + 	free(key);
    + }
      
    +-static int module_update_module_mode(int argc, const char **argv, const char *prefix)
    +-{
    +-	const char *path, *update = NULL;
    +-	int just_cloned;
    +-	struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
    +-
    +-	if (argc < 3 || argc > 4)
    +-		die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
    +-
    +-	just_cloned = git_config_int("just_cloned", argv[1]);
    +-	path = argv[2];
    +-
    +-	if (argc == 4)
    +-		update = argv[3];
    +-
    +-	determine_submodule_update_strategy(the_repository,
    +-					    just_cloned, path, update,
    +-					    &update_strategy);
    +-	fputs(submodule_strategy_to_string(&update_strategy), stdout);
    +-
    +-	return 0;
    +-}
    +-
    + struct update_clone_data {
    + 	const struct submodule *sub;
    + 	struct object_id oid;
     @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_data *ud, struct string_list *e
      	return run_update_command(ud, subforce, err);
      }
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -
     -	return 3;
     -}
    +-
    +-static int resolve_relative_path(int argc, const char **argv, const char *prefix)
    +-{
    +-	struct strbuf sb = STRBUF_INIT;
    +-	if (argc != 3)
    +-		die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
    +-
    +-	printf("%s", relative_path(argv[1], argv[2], &sb));
    +-	strbuf_release(&sb);
    +-	return 0;
    +-}
     -
      static const char *remote_submodule_branch(const char *path)
      {
      	const struct submodule *sub;
    -@@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)
    +@@ builtin/submodule--helper.c: static void do_ensure_core_worktree(const char *path)
      	}
    + }
      
    - 	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
    --		if (do_run_update_procedure(update_data, &err))
    -+		if (run_update_procedure(update_data, &err))
    - 			return 1;
    - 
    - 	if (update_data->recursive) {
    +-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
    +-{
    +-	const char *path;
    +-
    +-	if (argc != 2)
    +-		BUG("submodule--helper ensure-core-worktree <path>");
    +-
    +-	path = argv[1];
    +-	do_ensure_core_worktree(path);
    +-
    +-	return 0;
    +-}
    +-
    + static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
    + {
    + 	int i;
     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {
      	{"clone", module_clone, 0},
      	{"add-clone", add_clone, 0},
      	{"update", module_update, 0},
    +-	{"update-module-mode", module_update_module_mode, 0},
     -	{"run-update-procedure", run_update_procedure, 0},
    +-	{"ensure-core-worktree", ensure_core_worktree, 0},
    +-	{"relative-path", resolve_relative_path, 0},
      	{"resolve-relative-url", resolve_relative_url, 0},
      	{"resolve-relative-url-test", resolve_relative_url_test, 0},
      	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
    + 	{"init", module_init, SUPPORT_SUPER_PREFIX},
    + 	{"status", module_status, SUPPORT_SUPER_PREFIX},
    +-	{"print-default-remote", print_default_remote, 0},
    + 	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
    + 	{"deinit", module_deinit, 0},
    + 	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
 -:  ---------- >  8:  ca48dd452c submodule--helper: rename helper functions
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 1/8] submodule--helper: split up ensure_core_worktree()
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 2/8] submodule--helper: get remote names from any repository Atharva Raykar
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Let's split up `ensure_core_worktree()` so that we can call it from C
code without needing to deal with command line arguments.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 80619361fc..97512ccf0b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2794,18 +2794,12 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
+static void do_ensure_core_worktree(const char *path)
 {
 	const struct submodule *sub;
-	const char *path;
 	const char *cw;
 	struct repository subrepo;
 
-	if (argc != 2)
-		BUG("submodule--helper ensure-core-worktree <path>");
-
-	path = argv[1];
-
 	sub = submodule_from_path(the_repository, null_oid(), path);
 	if (!sub)
 		BUG("We could get the submodule handle before?");
@@ -2829,6 +2823,17 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 		free(abs_path);
 		strbuf_release(&sb);
 	}
+}
+
+static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
+{
+	const char *path;
+
+	if (argc != 2)
+		BUG("submodule--helper ensure-core-worktree <path>");
+
+	path = argv[1];
+	do_ensure_core_worktree(path);
 
 	return 0;
 }
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 2/8] submodule--helper: get remote names from any repository
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 1/8] submodule--helper: split up ensure_core_worktree() Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-20 16:52     ` Junio C Hamano
  2021-09-20 21:28     ` Junio C Hamano
  2021-09-16 10:32   ` [PATCH v2 3/8] submodule--helper: rename helpers for update-clone Atharva Raykar
                     ` (6 subsequent siblings)
  8 siblings, 2 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

`get_default_remote()` retrieves the name of a remote by resolving the
refs from of the current repository's ref store.

Thus in order to use it for retrieving the remote name of a submodule,
we have to start a new subprocess which runs from the submodule
directory.

Let's instead introduce a function called `repo_get_default_remote()`
which takes any repository object and retrieves the remote accordingly.

`get_default_remote()` is then defined as a call to
`repo_get_default_remote()` with 'the_repository' passed to it.

Now that we have `repo_get_default_remote()`, we no longer have to start
a subprocess that called `submodule--helper get-default-remote` from
within the submodule directory.

So let's make a function called `get_default_remote_submodule()` which
takes a submodule path, and returns the default remote for that
submodule, all within the same process.

We can now use this function to save an unnecessary subprocess spawn in
`sync_submodule()`, and also in the next patch, which will require this
functionality.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 97512ccf0b..f6c4fc349b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -29,11 +29,10 @@
 typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
 				  void *cb_data);
 
-static char *get_default_remote(void)
+static char *repo_get_default_remote(struct repository *repo, const char *refname)
 {
 	char *dest = NULL, *ret;
 	struct strbuf sb = STRBUF_INIT;
-	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 
 	if (!refname)
 		die(_("No such ref: %s"), "HEAD");
@@ -46,7 +45,7 @@ static char *get_default_remote(void)
 		die(_("Expecting a full ref name, got %s"), refname);
 
 	strbuf_addf(&sb, "branch.%s.remote", refname);
-	if (git_config_get_string(sb.buf, &dest))
+	if (repo_config_get_string(repo, sb.buf, &dest))
 		ret = xstrdup("origin");
 	else
 		ret = dest;
@@ -55,6 +54,25 @@ static char *get_default_remote(void)
 	return ret;
 }
 
+static char *get_default_remote_submodule(const char *module_path)
+{
+	const char *refname;
+	const struct submodule *sub;
+	struct repository subrepo;
+
+	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
+					  "HEAD", 0, NULL, NULL);
+	sub = submodule_from_path(the_repository, null_oid(), module_path);
+	repo_submodule_init(&subrepo, the_repository, sub);
+	return repo_get_default_remote(&subrepo, refname);
+}
+
+static char *get_default_remote(void)
+{
+	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+	return repo_get_default_remote(the_repository, refname);
+}
+
 static int print_default_remote(int argc, const char **argv, const char *prefix)
 {
 	char *remote;
@@ -1369,7 +1387,6 @@ static void sync_submodule(const char *path, const char *prefix,
 	char *remote_key = NULL;
 	char *sub_origin_url, *super_config_url, *displaypath;
 	struct strbuf sb = STRBUF_INIT;
-	struct child_process cp = CHILD_PROCESS_INIT;
 	char *sub_config_path = NULL;
 
 	if (!is_submodule_active(the_repository, path))
@@ -1418,14 +1435,9 @@ static void sync_submodule(const char *path, const char *prefix,
 	if (!is_submodule_populated_gently(path, NULL))
 		goto cleanup;
 
-	prepare_submodule_repo_env(&cp.env_array);
-	cp.git_cmd = 1;
-	cp.dir = path;
-	strvec_pushl(&cp.args, "submodule--helper",
-		     "print-default-remote", NULL);
-
 	strbuf_reset(&sb);
-	if (capture_command(&cp, &sb, 0))
+	strbuf_addstr(&sb, get_default_remote_submodule(path));
+	if (!sb.buf)
 		die(_("failed to get the default remote for submodule '%s'"),
 		      path);
 
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 3/8] submodule--helper: rename helpers for update-clone
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 1/8] submodule--helper: split up ensure_core_worktree() Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 2/8] submodule--helper: get remote names from any repository Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 4/8] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

The `update-clone` subcommand helpers that perform the parallel clone
and printing to stdout for shell script consumption, are renamed.

This lets us use the names `update_submodules()` and
`update_submodule()` for the helpers in the next patch, when we create
an `update` subcommand that does a full conversion.

We will get rid of these helpers in a cleanup patch at the end of this
series, when the `update-clone` command is no longer useful to us.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f6c4fc349b..b0336b0377 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2499,7 +2499,7 @@ static int do_run_update_procedure(struct update_data *ud)
 	return run_update_command(ud, subforce);
 }
 
-static void update_submodule(struct update_clone_data *ucd)
+static void update_clone_submodule(struct update_clone_data *ucd)
 {
 	fprintf(stdout, "dummy %s %d\t%s\n",
 		oid_to_hex(&ucd->oid),
@@ -2507,7 +2507,7 @@ static void update_submodule(struct update_clone_data *ucd)
 		ucd->sub->path);
 }
 
-static int update_submodules(struct submodule_update_clone *suc)
+static int update_clone_submodules(struct submodule_update_clone *suc)
 {
 	int i;
 
@@ -2528,7 +2528,7 @@ static int update_submodules(struct submodule_update_clone *suc)
 		return 1;
 
 	for (i = 0; i < suc->update_clone_nr; i++)
-		update_submodule(&suc->update_clone[i]);
+		update_clone_submodule(&suc->update_clone[i]);
 
 	return 0;
 }
@@ -2593,7 +2593,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	if (pathspec.nr)
 		suc.warn_if_uninitialized = 1;
 
-	return update_submodules(&suc);
+	return update_clone_submodules(&suc);
 }
 
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 4/8] submodule--helper: refactor get_submodule_displaypath()
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
                     ` (2 preceding siblings ...)
  2021-09-16 10:32   ` [PATCH v2 3/8] submodule--helper: rename helpers for update-clone Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 5/8] submodule: move core cmd_update() logic to C Atharva Raykar
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

We create a function called `do_get_submodule_displaypath()` that
generates the display path required by several submodule functions, and
takes a custom superprefix parameter, instead of reading it from the
environment.

We then redefine the existing `get_submodule_displaypath()` function
as a call to this new function, where the superprefix is obtained from
the environment.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b0336b0377..10de01a1f7 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -269,11 +269,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
 	return 0;
 }
 
-/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *do_get_submodule_displaypath(const char *path, const char *prefix, const char *super_prefix)
 {
-	const char *super_prefix = get_super_prefix();
-
 	if (prefix && super_prefix) {
 		BUG("cannot have prefix '%s' and superprefix '%s'",
 		    prefix, super_prefix);
@@ -289,6 +286,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)
 	}
 }
 
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+	const char *super_prefix = get_super_prefix();
+	return do_get_submodule_displaypath(path, prefix, super_prefix);
+}
+
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
 	struct strbuf sb = STRBUF_INIT;
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 5/8] submodule: move core cmd_update() logic to C
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
                     ` (3 preceding siblings ...)
  2021-09-16 10:32   ` [PATCH v2 4/8] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-20 17:13     ` Junio C Hamano
                       ` (2 more replies)
  2021-09-16 10:32   ` [PATCH v2 6/8] submodule--helper: remove update-clone subcommand Atharva Raykar
                     ` (3 subsequent siblings)
  8 siblings, 3 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

This patch completes the conversion past the flag parsing of
`submodule update` by introducing a helper subcommand called
`submodule--helper update`. The behaviour of `submodule update` should
remain the same after this patch.

We add more fields to the `struct update_data` that are required by
`struct submodule_update_clone` to be able to perform a clone, when that
is needed to be done.

Recursing on a submodule is done by calling a subprocess that launches
`submodule--helper update`, with a modified `--recursive-prefix` and
`--prefix` parameter.

We also introduce `update_submodules()` and `update_submodule()` which
are quite similar to `update_clone_submodules()` and
`update_clone_submodule()`, and will supersede them.

When the `--init` flag is passed to the subcommand, we do not spawn a
new subprocess and call `submodule--helper init` on the submodule paths,
because the Git machinery is not able to pick up the configuration
changes introduced by that init call[1]. So we instead run the
`init_submodule_cb()` callback over each submodule directly.

This introduces another problem, because there is no mechanism to pass
the superproject path prefix (ie, `--super-prefix`) without starting a
new git process. This field is required for obtaining the display path
for that is used by the command's output messages. So let's add a field
into the `init_cb` struct that lets us pass this information to
`init_submodule()`, which will now also take an explicit 'superprefix'
argument.

While we are at it, we also remove the fetch_in_submodule() shell
function since it is no longer used anywhere.

[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 505 ++++++++++++++++++++++++++++++------
 git-submodule.sh            | 145 +----------
 2 files changed, 433 insertions(+), 217 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 10de01a1f7..1eea626864 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -634,18 +634,22 @@ static char *compute_submodule_clone_url(const char *rel_url)
 
 struct init_cb {
 	const char *prefix;
+	const char *superprefix;
 	unsigned int flags;
 };
-#define INIT_CB_INIT { NULL, 0 }
+#define INIT_CB_INIT { 0 }
 
 static void init_submodule(const char *path, const char *prefix,
-			   unsigned int flags)
+			   const char *superprefix, unsigned int flags)
 {
 	const struct submodule *sub;
 	struct strbuf sb = STRBUF_INIT;
 	char *upd = NULL, *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	/* try superprefix from the environment, if it is not passed explicitly */
+	if (!superprefix)
+		superprefix = get_super_prefix();
+	displaypath = do_get_submodule_displaypath(path, prefix, superprefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -719,7 +723,7 @@ static void init_submodule(const char *path, const char *prefix,
 static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 {
 	struct init_cb *info = cb_data;
-	init_submodule(list_item->name, info->prefix, info->flags);
+	init_submodule(list_item->name, info->prefix, info->superprefix, info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
@@ -2039,7 +2043,6 @@ struct submodule_update_clone {
 	const char *prefix;
 	int single_branch;
 
-	/* to be consumed by git-submodule.sh */
 	struct update_clone_data *update_clone;
 	int update_clone_nr; int update_clone_alloc;
 
@@ -2062,19 +2065,63 @@ struct submodule_update_clone {
 }
 
 struct update_data {
+	const char *prefix;
 	const char *recursive_prefix;
 	const char *sm_path;
 	const char *displaypath;
 	struct object_id oid;
 	struct object_id suboid;
-	struct submodule_update_strategy update_strategy;
+	int max_jobs;
 	int depth;
+	int recommend_shallow;
+	int single_branch;
+	unsigned int init: 1;
 	unsigned int force: 1;
 	unsigned int quiet: 1;
 	unsigned int nofetch: 1;
-	unsigned int just_cloned: 1;
+	unsigned int remote: 1;
+	unsigned int recursive: 1;
+	unsigned int progress: 1;
+	unsigned int dissociate: 1;
+	unsigned int require_init: 1;
+	unsigned warn_if_uninitialized : 1;
+	unsigned int just_cloned : 1;
+	struct submodule_update_strategy update_strategy;
+	struct string_list references;
+	struct module_list list;
 };
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+	.list = MODULE_LIST_INIT, \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+	.recommend_shallow = -1, \
+	.references = STRING_LIST_INIT_DUP, \
+	.single_branch = -1, \
+	.max_jobs = 1, \
+}
+
+static void update_clone_from_update_data(struct submodule_update_clone *suc,
+					  struct update_data *update_data)
+{
+	suc->prefix = update_data->prefix;
+	suc->recursive_prefix = update_data->recursive_prefix;
+	suc->max_jobs = update_data->max_jobs;
+	suc->progress = update_data->progress;
+	suc->quiet = update_data->quiet;
+	suc->dissociate = update_data->dissociate;
+	suc->require_init = update_data->require_init;
+	suc->single_branch = update_data->single_branch;
+	suc->warn_if_uninitialized = update_data->warn_if_uninitialized;
+	suc->list = update_data->list;
+	suc->update = update_data->update_strategy;
+	suc->recommend_shallow = update_data->recommend_shallow;
+	if (update_data->depth)
+		suc->depth = xstrfmt("--depth=%d", update_data->depth);
+	if (update_data->references.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &update_data->references)
+			string_list_append(&suc->references, item->string);
+	}
+}
 
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
 		struct strbuf *out, const char *displaypath)
@@ -2369,111 +2416,113 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
 	return run_command(&cp);
 }
 
-static int run_update_command(struct update_data *ud, int subforce)
+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)
 {
-	struct strvec args = STRVEC_INIT;
-	struct strvec child_env = STRVEC_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
 	char *oid = oid_to_hex(&ud->oid);
+	struct strbuf out = STRBUF_INIT;
 	int must_die_on_failure = 0;
-	int git_cmd;
+	struct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;
 
-	switch (ud->update_strategy.type) {
+	if (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)
+		determine_submodule_update_strategy(the_repository, ud->just_cloned,
+						    ud->sm_path, NULL, &strategy);
+	else
+		strategy = ud->update_strategy;
+
+	cp.dir = xstrdup(ud->sm_path);
+	switch (strategy.type) {
 	case SM_UPDATE_CHECKOUT:
-		git_cmd = 1;
-		strvec_pushl(&args, "checkout", "-q", NULL);
+		cp.git_cmd = 1;
+		strvec_pushl(&cp.args, "checkout", "-q", NULL);
 		if (subforce)
-			strvec_push(&args, "-f");
+			strvec_push(&cp.args, "-f");
 		break;
 	case SM_UPDATE_REBASE:
-		git_cmd = 1;
-		strvec_push(&args, "rebase");
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "rebase");
 		if (ud->quiet)
-			strvec_push(&args, "--quiet");
+			strvec_push(&cp.args, "--quiet");
 		must_die_on_failure = 1;
 		break;
 	case SM_UPDATE_MERGE:
-		git_cmd = 1;
-		strvec_push(&args, "merge");
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "merge");
 		if (ud->quiet)
-			strvec_push(&args, "--quiet");
+			strvec_push(&cp.args, "--quiet");
 		must_die_on_failure = 1;
 		break;
 	case SM_UPDATE_COMMAND:
-		git_cmd = 0;
-		strvec_push(&args, ud->update_strategy.command);
+		cp.git_cmd = 0;
+		cp.use_shell = 1;
+		strvec_push(&cp.args, strategy.command);
 		must_die_on_failure = 1;
 		break;
 	default:
 		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+		    submodule_strategy_to_string(&strategy));
 	}
-	strvec_push(&args, oid);
+	strvec_push(&cp.args, oid);
 
-	prepare_submodule_repo_env(&child_env);
-	if (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,
-				     ud->sm_path, child_env.v)) {
-		switch (ud->update_strategy.type) {
-		case SM_UPDATE_CHECKOUT:
-			printf(_("Unable to checkout '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_REBASE:
-			printf(_("Unable to rebase '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_MERGE:
-			printf(_("Unable to merge '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_COMMAND:
-			printf(_("Execution of '%s %s' failed in submodule path '%s'"),
-			       ud->update_strategy.command, oid, ud->displaypath);
-			break;
-		default:
-			BUG("unexpected update strategy type: %s",
-			    submodule_strategy_to_string(&ud->update_strategy));
+	prepare_submodule_repo_env(&cp.env_array);
+	if (capture_command(&cp, &out, 0)) {
+		if (must_die_on_failure) {
+			switch (strategy.type) {
+			case SM_UPDATE_CHECKOUT:
+				die(_("Unable to checkout '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_REBASE:
+				die(_("Unable to rebase '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_MERGE:
+				die(_("Unable to merge '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_COMMAND:
+				die(_("Execution of '%s %s' failed in submodule path '%s'"),
+				    strategy.command, oid, ud->displaypath);
+				break;
+			default:
+				BUG("unexpected update strategy type: %s",
+				    submodule_strategy_to_string(&strategy));
+			}
 		}
-		/*
-		 * NEEDSWORK: We are currently printing to stdout with error
-		 * return so that the shell caller handles the error output
-		 * properly. Once we start handling the error messages within
-		 * C, we should use die() instead.
-		 */
-		if (must_die_on_failure)
-			return 2;
-		/*
-		 * This signifies to the caller in shell that the command
-		 * failed without dying
-		 */
+
+		/* the command failed, but update must continue */
+		string_list_append(err, out.buf);
 		return 1;
 	}
 
-	switch (ud->update_strategy.type) {
-	case SM_UPDATE_CHECKOUT:
-		printf(_("Submodule path '%s': checked out '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_REBASE:
-		printf(_("Submodule path '%s': rebased into '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_MERGE:
-		printf(_("Submodule path '%s': merged in '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_COMMAND:
-		printf(_("Submodule path '%s': '%s %s'\n"),
-		       ud->displaypath, ud->update_strategy.command, oid);
-		break;
-	default:
-		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+	if (!ud->quiet) {
+		switch (strategy.type) {
+		case SM_UPDATE_CHECKOUT:
+			printf(_("Submodule path '%s': checked out '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_REBASE:
+			printf(_("Submodule path '%s': rebased into '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_MERGE:
+			printf(_("Submodule path '%s': merged in '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_COMMAND:
+			printf(_("Submodule path '%s': '%s %s'\n"),
+			       ud->displaypath, strategy.command, oid);
+			break;
+		default:
+			BUG("unexpected update strategy type: %s",
+			    submodule_strategy_to_string(&strategy));
+		}
 	}
 
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud)
+static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2500,7 +2549,7 @@ static int do_run_update_procedure(struct update_data *ud)
 			    ud->displaypath, oid_to_hex(&ud->oid));
 	}
 
-	return run_update_command(ud, subforce);
+	return run_update_command(ud, subforce, err);
 }
 
 static void update_clone_submodule(struct update_clone_data *ucd)
@@ -2605,6 +2654,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
 	char *prefixed_path, *update = NULL;
 	struct update_data update_data = UPDATE_DATA_INIT;
+	struct string_list err = STRING_LIST_INIT_DUP;
 
 	struct option options[] = {
 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
@@ -2662,7 +2712,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	free(prefixed_path);
 
 	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data);
+		return do_run_update_procedure(&update_data, &err);
 
 	return 3;
 }
@@ -3038,6 +3088,291 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 	return !!ret;
 }
 
+static void update_data_to_args(struct update_data *update_data, struct strvec *args)
+{
+	const char *update = submodule_strategy_to_string(&update_data->update_strategy);
+
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
+	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
+	if (update_data->prefix)
+		strvec_pushl(args, "--prefix", update_data->prefix, NULL);
+	if (update_data->recursive_prefix)
+		strvec_pushl(args, "--recursive-prefix",
+			     update_data->recursive_prefix, NULL);
+	if (update_data->quiet)
+		strvec_push(args, "--quiet");
+	if (update_data->force)
+		strvec_push(args, "--force");
+	if (update_data->init)
+		strvec_push(args, "--init");
+	if (update_data->remote)
+		strvec_push(args, "--remote");
+	if (update_data->nofetch)
+		strvec_push(args, "--no-fetch");
+	if (update_data->dissociate)
+		strvec_push(args, "--dissociate");
+	if (update_data->progress)
+		strvec_push(args, "--progress");
+	if (update_data->require_init)
+		strvec_push(args, "--require-init");
+	if (update_data->depth)
+		strvec_pushf(args, "--depth=%d", update_data->depth);
+	if (update)
+		strvec_pushl(args, "--update", update, NULL);
+	if (update_data->references.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &update_data->references)
+			strvec_pushl(args, "--reference", item->string, NULL);
+	}
+	if (update_data->recommend_shallow == 0)
+		strvec_push(args, "--no-recommend-shallow");
+	else if (update_data->recommend_shallow == 1)
+		strvec_push(args, "--recommend-shallow");
+	if (update_data->single_branch >= 0)
+		strvec_push(args, "--single-branch");
+}
+
+static int update_submodule(struct update_data *update_data)
+{
+	char *prefixed_path;
+	struct string_list err = STRING_LIST_INIT_DUP;
+
+	do_ensure_core_worktree(update_data->sm_path);
+
+	if (update_data->recursive_prefix)
+		prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
+					update_data->sm_path);
+	else
+		prefixed_path = xstrdup(update_data->sm_path);
+
+	update_data->displaypath = get_submodule_displaypath(prefixed_path,
+							     update_data->prefix);
+	free(prefixed_path);
+
+	if (update_data->just_cloned) {
+		oidcpy(&update_data->suboid, null_oid());
+	} else {
+		if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
+			die(_("Unable to find current revision in submodule path '%s'"),
+			    update_data->displaypath);
+	}
+
+	if (update_data->remote) {
+		char *remote_name = get_default_remote_submodule(update_data->sm_path);
+		const char *branch = remote_submodule_branch(update_data->sm_path);
+		char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+
+		if (!update_data->nofetch) {
+			if(fetch_in_submodule(update_data->sm_path, update_data->depth,
+					      0, NULL))
+				die(_("Unable to fetch in submodule path '%s'"),
+				    update_data->sm_path);
+		}
+
+		if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
+			die(_("Unable to find %s revision in submodule path '%s'"),
+			    remote_ref, update_data->sm_path);
+
+		free(remote_ref);
+	}
+
+	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
+		if (do_run_update_procedure(update_data, &err))
+			return 1;
+
+	if (update_data->recursive) {
+		int res;
+		struct child_process cp = CHILD_PROCESS_INIT;
+		struct update_data next = *update_data;
+		char *die_msg = xstrfmt(_("Failed to recurse into submodule path '%s'"),
+					update_data->displaypath);
+
+		if (update_data->recursive_prefix)
+			prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
+						update_data->sm_path);
+		else
+			prefixed_path = xstrfmt("%s/", update_data->sm_path);
+
+		next.recursive_prefix = get_submodule_displaypath(prefixed_path,
+								  update_data->prefix);
+		next.prefix = NULL;
+		oidcpy(&next.oid, null_oid());
+		oidcpy(&next.suboid, null_oid());
+
+		cp.dir = update_data->sm_path;
+		cp.git_cmd = 1;
+		prepare_submodule_repo_env(&cp.env_array);
+		update_data_to_args(&next, &cp.args);
+
+		/* die() if child process die()'d */
+		if ((res = run_command(&cp)) == 128)
+			die("%s", die_msg);
+		if (res)
+			string_list_append(&err, die_msg);
+
+		free(die_msg);
+	}
+
+	if (err.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &err)
+			fputs(item->string, stderr);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int update_submodules(struct update_data *update_data)
+{
+	int i, res = 0;
+	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+
+	update_clone_from_update_data(&suc, update_data);
+	run_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,
+				   update_clone_start_failure,
+				   update_clone_task_finished, &suc, "submodule",
+				   "parallel/update");
+
+	/*
+	 * We saved the output and put it out all at once now.
+	 * That means:
+	 * - the listener does not have to interleave their (checkout)
+	 *   work with our fetching.  The writes involved in a
+	 *   checkout involve more straightforward sequential I/O.
+	 * - the listener can avoid doing any work if fetching failed.
+	 */
+	if (suc.quickstop) {
+		string_list_clear(&update_data->references, 0);
+		return 1;
+	}
+
+	for (i = 0; i < suc.update_clone_nr; i++) {
+		struct update_clone_data ucd = suc.update_clone[i];
+
+		oidcpy(&update_data->oid, &ucd.oid);
+		update_data->just_cloned = ucd.just_cloned;
+		update_data->sm_path = ucd.sub->path;
+
+		if (update_submodule(update_data))
+			res = 1;
+	}
+
+	string_list_clear(&update_data->references, 0);
+	return res;
+}
+
+static int module_update(int argc, const char **argv, const char *prefix)
+{
+	int init = 0, force = 0, quiet = 0, nofetch = 0;
+	int remote = 0, recursive = 0, dissociate = 0;
+	int progress = 0, require_init = 0;
+	const char *update = NULL;
+	struct pathspec pathspec;
+	struct update_data update_data = UPDATE_DATA_INIT;
+
+	struct option module_update_clone_options[] = {
+		OPT__FORCE(&force, N_("force checkout updates"), 0),
+		OPT_BOOL(0, "init", &init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_BOOL(0, "remote", &remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_STRING(0, "prefix", &prefix,
+			   N_("path"),
+			   N_("path into the working tree")),
+		OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix,
+			   N_("path"),
+			   N_("path into the working tree, across nested "
+			      "submodule boundaries")),
+		OPT_STRING(0, "update", &update,
+			   N_("string"),
+			   N_("rebase, merge, checkout or none")),
+		OPT_STRING_LIST(0, "reference", &update_data.references, N_("repo"),
+				N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &dissociate,
+			 N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &update_data.depth,
+			    N_("create a shallow clone truncated to the "
+			       "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &update_data.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &update_data.recommend_shallow,
+			 N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &progress,
+			 N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &require_init,
+			 N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &update_data.single_branch,
+			 N_("clone only one branch, HEAD or --branch")),
+		OPT_END()
+	};
+
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
+		NULL
+	};
+
+	update_clone_config_from_gitmodules(&update_data.max_jobs);
+	git_config(git_update_clone_config, &update_data.max_jobs);
+
+	argc = parse_options(argc, argv, prefix, module_update_clone_options,
+			     git_submodule_helper_usage, 0);
+	update_data.prefix = prefix;
+
+	update_data.force = !!force;
+	update_data.quiet = !!quiet;
+	update_data.nofetch = !!nofetch;
+	update_data.init = !!init;
+	update_data.require_init = !!require_init;
+	update_data.remote = !!remote;
+	update_data.recursive = !!recursive;
+	update_data.progress = !!progress;
+	update_data.dissociate = !!dissociate;
+	oidcpy(&update_data.oid, null_oid());
+	oidcpy(&update_data.suboid, null_oid());
+
+	if (update)
+		if (parse_submodule_update_strategy(update,
+						    &update_data.update_strategy) < 0)
+			die(_("bad value for update parameter"));
+
+	if (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)
+		return 1;
+
+	if (pathspec.nr)
+		update_data.warn_if_uninitialized = 1;
+
+	if (update_data.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, update_data.prefix,
+					&pathspec, &list) < 0)
+			return 1;
+
+		/*
+		 * If there are no path args and submodule.active is set then,
+		 * by default, only initialize 'active' modules.
+		 */
+		if (!argc && git_config_get_value_multi("submodule.active"))
+			module_list_active(&list);
+
+		info.prefix = update_data.prefix;
+		info.superprefix = update_data.recursive_prefix;
+		if (update_data.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
+	return update_submodules(&update_data);
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
@@ -3213,6 +3548,7 @@ static int add_clone(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
+
 #define SUPPORT_SUPER_PREFIX (1<<0)
 
 struct cmd_struct {
@@ -3226,6 +3562,7 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add-clone", add_clone, 0},
+	{"update", module_update, 0},
 	{"update-module-mode", module_update_module_mode, 0},
 	{"update-clone", update_clone, 0},
 	{"run-update-procedure", run_update_procedure, 0},
diff --git a/git-submodule.sh b/git-submodule.sh
index f703cddce8..5197de4551 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -369,20 +369,6 @@ cmd_deinit()
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
 }
 
-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]
-# Because arguments are positional, use an empty string to omit <depth>
-# but include <sha1>.
-fetch_in_submodule () (
-	sanitize_submodule_env &&
-	cd "$1" &&
-	if test $# -eq 3
-	then
-		echo "$3" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+"$2"}
-	else
-		git fetch ${GIT_QUIET:+--quiet} ${2:+"$2"}
-	fi
-)
-
 #
 # Update each submodule path to correct revision, using clone and checkout as needed
 #
@@ -484,133 +470,26 @@ cmd_update()
 		shift
 	done
 
-	if test -n "$init"
-	then
-		cmd_init "--" "$@" || return
-	fi
-
-	{
-	git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
-		${progress:+"--progress"} \
+	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
+		${GIT_QUIET:+--quiet} \
+		${force:+--force} \
+		${progress:+--progress} \
+		${dissociate:+--dissociate} \
+		${remote:+--remote} \
+		${recursive:+--recursive} \
+		${init:+--init} \
+		${require_init:+--require-init} \
+		${nofetch:+--no-fetch} \
 		${wt_prefix:+--prefix "$wt_prefix"} \
 		${prefix:+--recursive-prefix "$prefix"} \
 		${update:+--update "$update"} \
 		${reference:+"$reference"} \
-		${dissociate:+"--dissociate"} \
-		${depth:+--depth "$depth"} \
-		${require_init:+--require-init} \
+		${depth:+"$depth"} \
 		$single_branch \
 		$recommend_shallow \
 		$jobs \
 		-- \
-		"$@" || echo "#unmatched" $?
-	} | {
-	err=
-	while read -r quickabort sha1 just_cloned sm_path
-	do
-		die_if_unmatched "$quickabort" "$sha1"
-
-		git submodule--helper ensure-core-worktree "$sm_path" || exit 1
-
-		displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
-
-		if test $just_cloned -eq 1
-		then
-			subsha1=
-		else
-			just_cloned=
-			subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
-				git rev-parse --verify HEAD) ||
-			die "fatal: $(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
-		fi
-
-		if test -n "$remote"
-		then
-			branch=$(git submodule--helper remote-branch "$sm_path")
-			if test -z "$nofetch"
-			then
-				# Fetch remote before determining tracking $sha1
-				fetch_in_submodule "$sm_path" $depth ||
-				die "fatal: $(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
-			fi
-			remote_name=$(sanitize_submodule_env; cd "$sm_path" && git submodule--helper print-default-remote)
-			sha1=$(sanitize_submodule_env; cd "$sm_path" &&
-				git rev-parse --verify "${remote_name}/${branch}") ||
-			die "fatal: $(eval_gettext "Unable to find current \${remote_name}/\${branch} revision in submodule path '\$sm_path'")"
-		fi
-
-		out=$(git submodule--helper run-update-procedure \
-			  ${wt_prefix:+--prefix "$wt_prefix"} \
-			  ${GIT_QUIET:+--quiet} \
-			  ${force:+--force} \
-			  ${just_cloned:+--just-cloned} \
-			  ${nofetch:+--no-fetch} \
-			  ${depth:+"$depth"} \
-			  ${update:+--update "$update"} \
-			  ${prefix:+--recursive-prefix "$prefix"} \
-			  ${sha1:+--oid "$sha1"} \
-			  ${subsha1:+--suboid "$subsha1"} \
-			  "--" \
-			  "$sm_path")
-
-		# exit codes for run-update-procedure:
-		# 0: update was successful, say command output
-		# 1: update procedure failed, but should not die
-		# 2 or 128: subcommand died during execution
-		# 3: no update procedure was run
-		res="$?"
-		case $res in
-		0)
-			say "$out"
-			;;
-		1)
-			err="${err};fatal: $out"
-			continue
-			;;
-		2|128)
-			die_with_status $res "fatal: $out"
-			;;
-		esac
-
-		if test -n "$recursive"
-		then
-			(
-				prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
-				wt_prefix=
-				sanitize_submodule_env
-				cd "$sm_path" &&
-				eval cmd_update
-			)
-			res=$?
-			if test $res -gt 0
-			then
-				die_msg="fatal: $(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
-				if test $res -ne 2
-				then
-					err="${err};$die_msg"
-					continue
-				else
-					die_with_status $res "$die_msg"
-				fi
-			fi
-		fi
-	done
-
-	if test -n "$err"
-	then
-		OIFS=$IFS
-		IFS=';'
-		for e in $err
-		do
-			if test -n "$e"
-			then
-				echo >&2 "$e"
-			fi
-		done
-		IFS=$OIFS
-		exit 1
-	fi
-	}
+		"$@"
 }
 
 #
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 6/8] submodule--helper: remove update-clone subcommand
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
                     ` (4 preceding siblings ...)
  2021-09-16 10:32   ` [PATCH v2 5/8] submodule: move core cmd_update() logic to C Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-16 10:32   ` [PATCH v2 7/8] submodule--helper: remove unused helpers Atharva Raykar
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

We no longer need this subcommand as the shell version calls the
'update' subcommand instead, which does all the cloning within C itself.

We also no longer need the 'update_clone_submodules()' and
'update_clone_submodule()' functions, so we remove those as well.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 98 -------------------------------------
 1 file changed, 98 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1eea626864..c1ce3981ad 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2552,103 +2552,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e
 	return run_update_command(ud, subforce, err);
 }
 
-static void update_clone_submodule(struct update_clone_data *ucd)
-{
-	fprintf(stdout, "dummy %s %d\t%s\n",
-		oid_to_hex(&ucd->oid),
-		ucd->just_cloned,
-		ucd->sub->path);
-}
-
-static int update_clone_submodules(struct submodule_update_clone *suc)
-{
-	int i;
-
-	run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
-				   update_clone_start_failure,
-				   update_clone_task_finished, suc, "submodule",
-				   "parallel/update");
-
-	/*
-	 * We saved the output and put it out all at once now.
-	 * That means:
-	 * - the listener does not have to interleave their (checkout)
-	 *   work with our fetching.  The writes involved in a
-	 *   checkout involve more straightforward sequential I/O.
-	 * - the listener can avoid doing any work if fetching failed.
-	 */
-	if (suc->quickstop)
-		return 1;
-
-	for (i = 0; i < suc->update_clone_nr; i++)
-		update_clone_submodule(&suc->update_clone[i]);
-
-	return 0;
-}
-
-static int update_clone(int argc, const char **argv, const char *prefix)
-{
-	const char *update = NULL;
-	struct pathspec pathspec;
-	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
-
-	struct option module_update_clone_options[] = {
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "recursive-prefix", &suc.recursive_prefix,
-			   N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_STRING(0, "update", &update,
-			   N_("string"),
-			   N_("rebase, merge, checkout or none")),
-		OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
-			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &suc.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
-			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
-		OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
-		OPT_BOOL(0, "progress", &suc.progress,
-			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &suc.require_init,
-			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &suc.single_branch,
-			 N_("clone only one branch, HEAD or --branch")),
-		OPT_END()
-	};
-
-	const char *const git_submodule_helper_usage[] = {
-		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
-		NULL
-	};
-	suc.prefix = prefix;
-
-	update_clone_config_from_gitmodules(&suc.max_jobs);
-	git_config(git_update_clone_config, &suc.max_jobs);
-
-	argc = parse_options(argc, argv, prefix, module_update_clone_options,
-			     git_submodule_helper_usage, 0);
-
-	if (update)
-		if (parse_submodule_update_strategy(update, &suc.update) < 0)
-			die(_("bad value for update parameter"));
-
-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
-		return 1;
-
-	if (pathspec.nr)
-		suc.warn_if_uninitialized = 1;
-
-	return update_clone_submodules(&suc);
-}
-
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
 {
 	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
@@ -3564,7 +3467,6 @@ static struct cmd_struct commands[] = {
 	{"add-clone", add_clone, 0},
 	{"update", module_update, 0},
 	{"update-module-mode", module_update_module_mode, 0},
-	{"update-clone", update_clone, 0},
 	{"run-update-procedure", run_update_procedure, 0},
 	{"ensure-core-worktree", ensure_core_worktree, 0},
 	{"relative-path", resolve_relative_path, 0},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 7/8] submodule--helper: remove unused helpers
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
                     ` (5 preceding siblings ...)
  2021-09-16 10:32   ` [PATCH v2 6/8] submodule--helper: remove update-clone subcommand Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-20 17:19     ` Junio C Hamano
  2021-09-16 10:32   ` [PATCH v2 8/8] submodule--helper: rename helper functions Atharva Raykar
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
  8 siblings, 1 reply; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

These helpers were useful back when 'submodule update' had most of its
logic in shell. Now that they will never be invoked, let us remove them.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 135 ------------------------------------
 1 file changed, 135 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c1ce3981ad..0910af9c71 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -73,21 +73,6 @@ static char *get_default_remote(void)
 	return repo_get_default_remote(the_repository, refname);
 }
 
-static int print_default_remote(int argc, const char **argv, const char *prefix)
-{
-	char *remote;
-
-	if (argc != 1)
-		die(_("submodule--helper print-default-remote takes no arguments"));
-
-	remote = get_default_remote();
-	if (remote)
-		printf("%s\n", remote);
-
-	free(remote);
-	return 0;
-}
-
 static int starts_with_dot_slash(const char *str)
 {
 	return str[0] == '.' && is_dir_sep(str[1]);
@@ -1993,29 +1978,6 @@ static void determine_submodule_update_strategy(struct repository *r,
 	free(key);
 }
 
-static int module_update_module_mode(int argc, const char **argv, const char *prefix)
-{
-	const char *path, *update = NULL;
-	int just_cloned;
-	struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
-
-	if (argc < 3 || argc > 4)
-		die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
-
-	just_cloned = git_config_int("just_cloned", argv[1]);
-	path = argv[2];
-
-	if (argc == 4)
-		update = argv[3];
-
-	determine_submodule_update_strategy(the_repository,
-					    just_cloned, path, update,
-					    &update_strategy);
-	fputs(submodule_strategy_to_string(&update_strategy), stdout);
-
-	return 0;
-}
-
 struct update_clone_data {
 	const struct submodule *sub;
 	struct object_id oid;
@@ -2552,85 +2514,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e
 	return run_update_command(ud, subforce, err);
 }
 
-static int run_update_procedure(int argc, const char **argv, const char *prefix)
-{
-	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
-	char *prefixed_path, *update = NULL;
-	struct update_data update_data = UPDATE_DATA_INIT;
-	struct string_list err = STRING_LIST_INIT_DUP;
-
-	struct option options[] = {
-		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
-		OPT__FORCE(&force, N_("force checkout updates"), 0),
-		OPT_BOOL('N', "no-fetch", &nofetch,
-			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &just_cloned,
-			 N_("overrides update mode in case the repository is a fresh clone")),
-		OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")),
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "update", &update,
-			   N_("string"),
-			   N_("rebase, merge, checkout or none")),
-		OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix, N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
-			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_CALLBACK_F(0, "suboid", &update_data.suboid, N_("subsha1"),
-			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_END()
-	};
-
-	const char *const usage[] = {
-		N_("git submodule--helper run-update-procedure [<options>] <path>"),
-		NULL
-	};
-
-	argc = parse_options(argc, argv, prefix, options, usage, 0);
-
-	if (argc != 1)
-		usage_with_options(usage, options);
-
-	update_data.force = !!force;
-	update_data.quiet = !!quiet;
-	update_data.nofetch = !!nofetch;
-	update_data.just_cloned = !!just_cloned;
-	update_data.sm_path = argv[0];
-
-	if (update_data.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
-	else
-		prefixed_path = xstrdup(update_data.sm_path);
-
-	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
-
-	determine_submodule_update_strategy(the_repository, update_data.just_cloned,
-					    update_data.sm_path, update,
-					    &update_data.update_strategy);
-
-	free(prefixed_path);
-
-	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data, &err);
-
-	return 3;
-}
-
-static int resolve_relative_path(int argc, const char **argv, const char *prefix)
-{
-	struct strbuf sb = STRBUF_INIT;
-	if (argc != 3)
-		die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
-
-	printf("%s", relative_path(argv[1], argv[2], &sb));
-	strbuf_release(&sb);
-	return 0;
-}
-
 static const char *remote_submodule_branch(const char *path)
 {
 	const struct submodule *sub;
@@ -2794,19 +2677,6 @@ static void do_ensure_core_worktree(const char *path)
 	}
 }
 
-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
-{
-	const char *path;
-
-	if (argc != 2)
-		BUG("submodule--helper ensure-core-worktree <path>");
-
-	path = argv[1];
-	do_ensure_core_worktree(path);
-
-	return 0;
-}
-
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -3466,16 +3336,11 @@ static struct cmd_struct commands[] = {
 	{"clone", module_clone, 0},
 	{"add-clone", add_clone, 0},
 	{"update", module_update, 0},
-	{"update-module-mode", module_update_module_mode, 0},
-	{"run-update-procedure", run_update_procedure, 0},
-	{"ensure-core-worktree", ensure_core_worktree, 0},
-	{"relative-path", resolve_relative_path, 0},
 	{"resolve-relative-url", resolve_relative_url, 0},
 	{"resolve-relative-url-test", resolve_relative_url_test, 0},
 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
 	{"init", module_init, SUPPORT_SUPER_PREFIX},
 	{"status", module_status, SUPPORT_SUPER_PREFIX},
-	{"print-default-remote", print_default_remote, 0},
 	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
 	{"deinit", module_deinit, 0},
 	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v2 8/8] submodule--helper: rename helper functions
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
                     ` (6 preceding siblings ...)
  2021-09-16 10:32   ` [PATCH v2 7/8] submodule--helper: remove unused helpers Atharva Raykar
@ 2021-09-16 10:32   ` Atharva Raykar
  2021-09-20 17:19     ` Junio C Hamano
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
  8 siblings, 1 reply; 56+ messages in thread
From: Atharva Raykar @ 2021-09-16 10:32 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

These two functions were prefixed with 'do' before the shell-to-C
conversion because they were utility functions meant to be called by
their non-prefixed counterpart.

Since those callers don't exist anymore, and these functions can now be
used directly, let's rename them to signal this fact.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0910af9c71..e5e33be6ea 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2484,7 +2484,7 @@ static int run_update_command(struct update_data *ud, int subforce, struct strin
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
+static int run_update_procedure(struct update_data *ud, struct string_list *err)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2646,7 +2646,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
-static void do_ensure_core_worktree(const char *path)
+static void ensure_core_worktree(const char *path)
 {
 	const struct submodule *sub;
 	const char *cw;
@@ -2910,7 +2910,7 @@ static int update_submodule(struct update_data *update_data)
 	char *prefixed_path;
 	struct string_list err = STRING_LIST_INIT_DUP;
 
-	do_ensure_core_worktree(update_data->sm_path);
+	ensure_core_worktree(update_data->sm_path);
 
 	if (update_data->recursive_prefix)
 		prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
@@ -2950,7 +2950,7 @@ static int update_submodule(struct update_data *update_data)
 	}
 
 	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
-		if (do_run_update_procedure(update_data, &err))
+		if (run_update_procedure(update_data, &err))
 			return 1;
 
 	if (update_data->recursive) {
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository
  2021-09-16 10:32   ` [PATCH v2 2/8] submodule--helper: get remote names from any repository Atharva Raykar
@ 2021-09-20 16:52     ` Junio C Hamano
  2021-10-03 13:22       ` Atharva Raykar
  2021-09-20 21:28     ` Junio C Hamano
  1 sibling, 1 reply; 56+ messages in thread
From: Junio C Hamano @ 2021-09-20 16:52 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> `get_default_remote()` retrieves the name of a remote by resolving the
> refs from of the current repository's ref store.
>
> Thus in order to use it for retrieving the remote name of a submodule,
> we have to start a new subprocess which runs from the submodule
> directory.
>
> Let's instead introduce a function called `repo_get_default_remote()`
> which takes any repository object and retrieves the remote accordingly.
>
> `get_default_remote()` is then defined as a call to
> `repo_get_default_remote()` with 'the_repository' passed to it.
>
> Now that we have `repo_get_default_remote()`, we no longer have to start
> a subprocess that called `submodule--helper get-default-remote` from
> within the submodule directory.
>
> So let's make a function called `get_default_remote_submodule()` which
> takes a submodule path, and returns the default remote for that
> submodule, all within the same process.
>
> We can now use this function to save an unnecessary subprocess spawn in
> `sync_submodule()`, and also in the next patch, which will require this
> functionality.
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Shourya Shukla <periperidip@gmail.com>
> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
> ---
>  builtin/submodule--helper.c | 34 +++++++++++++++++++++++-----------
>  1 file changed, 23 insertions(+), 11 deletions(-)

The above covers a lot of stuff, because this change does a lot of
things ;-)

The commit could be split into 3 logically distinct phases (two
independent, the third depends on the other two):

 - extract the part that uses the run-command() API to run
   "submodule--helper print-default-remote" from sync_submodule()
   and create get_default_remote_submodule() function out of it.

 - move bulk of get_default_remote() into repo_get_default_remote()
   and reimplement the former as a thin wrapper of the latter.

 - using the repo_get_default_remote() created in the second step,
   update the get_default_remote_submodule() created in the first
   step to work in-process without a subprocess.

but a bit larger granularity used here is probably OK.

> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 97512ccf0b..f6c4fc349b 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -29,11 +29,10 @@
>  typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
>  				  void *cb_data);
>  
> -static char *get_default_remote(void)
> +static char *repo_get_default_remote(struct repository *repo, const char *refname)
>  {
>  	char *dest = NULL, *ret;
>  	struct strbuf sb = STRBUF_INIT;
> -	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
>  
>  	if (!refname)
>  		die(_("No such ref: %s"), "HEAD");
> @@ -46,7 +45,7 @@ static char *get_default_remote(void)
>  		die(_("Expecting a full ref name, got %s"), refname);
>  
>  	strbuf_addf(&sb, "branch.%s.remote", refname);
> -	if (git_config_get_string(sb.buf, &dest))
> +	if (repo_config_get_string(repo, sb.buf, &dest))
>  		ret = xstrdup("origin");
>  	else
>  		ret = dest;
> @@ -55,6 +54,25 @@ static char *get_default_remote(void)
>  	return ret;
>  }
>  
> +static char *get_default_remote_submodule(const char *module_path)
> +{
> +	const char *refname;
> +	const struct submodule *sub;
> +	struct repository subrepo;
> +
> +	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
> +					  "HEAD", 0, NULL, NULL);
> +	sub = submodule_from_path(the_repository, null_oid(), module_path);
> +	repo_submodule_init(&subrepo, the_repository, sub);
> +	return repo_get_default_remote(&subrepo, refname);
> +}
> +
> +static char *get_default_remote(void)
> +{
> +	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
> +	return repo_get_default_remote(the_repository, refname);
> +}
> +
>  static int print_default_remote(int argc, const char **argv, const char *prefix)
>  {
>  	char *remote;
> @@ -1369,7 +1387,6 @@ static void sync_submodule(const char *path, const char *prefix,
>  	char *remote_key = NULL;
>  	char *sub_origin_url, *super_config_url, *displaypath;
>  	struct strbuf sb = STRBUF_INIT;
> -	struct child_process cp = CHILD_PROCESS_INIT;
>  	char *sub_config_path = NULL;
>  
>  	if (!is_submodule_active(the_repository, path))
> @@ -1418,14 +1435,9 @@ static void sync_submodule(const char *path, const char *prefix,
>  	if (!is_submodule_populated_gently(path, NULL))
>  		goto cleanup;
>  
> -	prepare_submodule_repo_env(&cp.env_array);
> -	cp.git_cmd = 1;
> -	cp.dir = path;
> -	strvec_pushl(&cp.args, "submodule--helper",
> -		     "print-default-remote", NULL);
> -
>  	strbuf_reset(&sb);
> -	if (capture_command(&cp, &sb, 0))
> +	strbuf_addstr(&sb, get_default_remote_submodule(path));
> +	if (!sb.buf)
>  		die(_("failed to get the default remote for submodule '%s'"),
>  		      path);

There is this line after the post context presented here:

        strbuf_strip_suffix(&sb, "\n");
        remote_key = xstrfmt("remote.%s.url", sb.buf);

The LF was expected to come from the capture_command(), but it no
longer is needed after get_default_remote_submodule() switches to
use the in-process method.  In fact, the use of sb for the purpose
of forming remote_key is not needed.

    tmp = get_default_remote_submodule(path);
    if (!tmp)
	die(_("failed to get..."));
    remote_key = xstrfmt("remote.%s.url", tmp);
    free(tmp);

Yes, I think the new code leaks, and makes it impossible not to
leak, the returned value from get_default_remote_submodule() by
passing the call as an argument to strbuf_addstr().

Both of the two bugs pointed out here would have been easier to spot
if the commits were smaller, I would think, but as I said, a bit
larger granularity used here was still manageable.

Thanks.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C
  2021-09-16 10:32   ` [PATCH v2 5/8] submodule: move core cmd_update() logic to C Atharva Raykar
@ 2021-09-20 17:13     ` Junio C Hamano
  2021-10-03 10:38       ` Atharva Raykar
  2021-09-20 19:58     ` Junio C Hamano
  2021-09-20 21:28     ` Junio C Hamano
  2 siblings, 1 reply; 56+ messages in thread
From: Junio C Hamano @ 2021-09-20 17:13 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> This patch completes the conversion past the flag parsing of
> `submodule update` by introducing a helper subcommand called
> `submodule--helper update`. The behaviour of `submodule update` should
> remain the same after this patch.
>
> We add more fields to the `struct update_data` that are required by
> `struct submodule_update_clone` to be able to perform a clone, when that
> is needed to be done.
>
> Recursing on a submodule is done by calling a subprocess that launches
> `submodule--helper update`, with a modified `--recursive-prefix` and
> `--prefix` parameter.
>
> We also introduce `update_submodules()` and `update_submodule()` which
> are quite similar to `update_clone_submodules()` and
> `update_clone_submodule()`, and will supersede them.
>
> When the `--init` flag is passed to the subcommand, we do not spawn a
> new subprocess and call `submodule--helper init` on the submodule paths,
> because the Git machinery is not able to pick up the configuration
> changes introduced by that init call[1]. So we instead run the
> `init_submodule_cb()` callback over each submodule directly.
>
> This introduces another problem, because there is no mechanism to pass
> the superproject path prefix (ie, `--super-prefix`) without starting a
> new git process. This field is required for obtaining the display path
> for that is used by the command's output messages. So let's add a field
> into the `init_cb` struct that lets us pass this information to
> `init_submodule()`, which will now also take an explicit 'superprefix'
> argument.
>
> While we are at it, we also remove the fetch_in_submodule() shell
> function since it is no longer used anywhere.
>
> [1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Shourya Shukla <periperidip@gmail.com>
> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
> ---
>  builtin/submodule--helper.c | 505 ++++++++++++++++++++++++++++++------
>  git-submodule.sh            | 145 +----------
>  2 files changed, 433 insertions(+), 217 deletions(-)

It seems that this step does too many things in one step and makes
it harder than necessary for readers to understand what is going on.

For example, as far as I can see, the change to optionally allow
passing superprefix to init_submodule() can be made without anything
else in this step (i.e. "we allow superprefix from the parameter to
override what get_super_prefix() would give us, but at this step,
everybody passes NULL and the behaviour is unchanged" would be one
such step), later to be followed by a change that involves passing a
non-NULL value there, and it would become a lot easier to see who
passes a non-NULL super prefix, what value is passed and for what
purpose, with such an organization.

A 650+ lines single patch like this buries the details and forces
the readers to disect them out.  The change that teaches
run_update_command() to instead use capture_command() and gives the
error message to its callers may be another example of what may be
better done as an independent step before tying the whole thing
together.

It is larger than what I comfortably can spend my time on while
tending patches from other topics, so I'll skip reviewing this step
for now.

Thanks.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 7/8] submodule--helper: remove unused helpers
  2021-09-16 10:32   ` [PATCH v2 7/8] submodule--helper: remove unused helpers Atharva Raykar
@ 2021-09-20 17:19     ` Junio C Hamano
  0 siblings, 0 replies; 56+ messages in thread
From: Junio C Hamano @ 2021-09-20 17:19 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> These helpers were useful back when 'submodule update' had most of its
> logic in shell. Now that they will never be invoked, let us remove them.
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Shourya Shukla <periperidip@gmail.com>
> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
> ---
>  builtin/submodule--helper.c | 135 ------------------------------------
>  1 file changed, 135 deletions(-)

Makes sense.  I briefly hoped that print-default-remote could go
after 2/8 but there is another user that is in the cmd_update() that
is not removed until 5/8 and removing them in a separate step after
we are all done like this patch does makes sense.  I am not sure
where and how the line to separate the two "remove" patches is
drawn, though.  Is there a reason why they need to be two patches?

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 8/8] submodule--helper: rename helper functions
  2021-09-16 10:32   ` [PATCH v2 8/8] submodule--helper: rename helper functions Atharva Raykar
@ 2021-09-20 17:19     ` Junio C Hamano
  0 siblings, 0 replies; 56+ messages in thread
From: Junio C Hamano @ 2021-09-20 17:19 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> These two functions were prefixed with 'do' before the shell-to-C
> conversion because they were utility functions meant to be called by
> their non-prefixed counterpart.
>
> Since those callers don't exist anymore, and these functions can now be
> used directly, let's rename them to signal this fact.
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Shourya Shukla <periperidip@gmail.com>
> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
> ---
>  builtin/submodule--helper.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)

Nice.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C
  2021-09-16 10:32   ` [PATCH v2 5/8] submodule: move core cmd_update() logic to C Atharva Raykar
  2021-09-20 17:13     ` Junio C Hamano
@ 2021-09-20 19:58     ` Junio C Hamano
  2021-09-20 21:28     ` Junio C Hamano
  2 siblings, 0 replies; 56+ messages in thread
From: Junio C Hamano @ 2021-09-20 19:58 UTC (permalink / raw)
  To: Atharva Raykar, Emily Shaffer
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> This patch completes the conversion past the flag parsing of
> `submodule update` by introducing a helper subcommand called
> `submodule--helper update`. The behaviour of `submodule update` should
> remain the same after this patch.
> ...
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Shourya Shukla <periperidip@gmail.com>
> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
> ---

This seems to overlap with Emily's 242655f2 (submodule: record
superproject gitdir during 'update', 2021-08-19) that came in
<20210819200953.2105230-5-emilyshaffer@google.com>.

Should I expect there probably needs a few more iterations for this
topic?  Depending, the "a submodule knows which superproject it is
part of" topic may have to be done in C on top of this topic.

I'll eject the 'es/superproject-aware-submodules' topic for now,
just to get today's integration going.

Thanks.


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C
  2021-09-16 10:32   ` [PATCH v2 5/8] submodule: move core cmd_update() logic to C Atharva Raykar
  2021-09-20 17:13     ` Junio C Hamano
  2021-09-20 19:58     ` Junio C Hamano
@ 2021-09-20 21:28     ` Junio C Hamano
  2 siblings, 0 replies; 56+ messages in thread
From: Junio C Hamano @ 2021-09-20 21:28 UTC (permalink / raw)
  To: Atharva Raykar, Ævar Arnfjörð Bjarmason
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> +static int update_submodules(struct update_data *update_data)
> +{
> +	int i, res = 0;
> +	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
> +
> +	update_clone_from_update_data(&suc, update_data);
> +	run_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,
> +				   update_clone_start_failure,
> +				   update_clone_task_finished, &suc, "submodule",
> +				   "parallel/update");
> + ...

As ab/config-based-hooks-base topic from Ævar changes the way this
helper function gets called at 73367f2f (run-command: add stdin
callback for parallelization, 2021-09-02) and then again in 2aba2f5f
(run-command: allow capturing of collated output, 2021-09-02), this
part needs to be adjusted when the topics collide in 'seen'.

I _think_ I've resolved conflict correctly, but please double-check
the result when today's integration result is pushed out later, both
of you.

Thanks.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository
  2021-09-16 10:32   ` [PATCH v2 2/8] submodule--helper: get remote names from any repository Atharva Raykar
  2021-09-20 16:52     ` Junio C Hamano
@ 2021-09-20 21:28     ` Junio C Hamano
  2021-09-21 16:33       ` Jonathan Tan
  1 sibling, 1 reply; 56+ messages in thread
From: Junio C Hamano @ 2021-09-20 21:28 UTC (permalink / raw)
  To: Atharva Raykar, Jonathan Tan
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> +static char *get_default_remote_submodule(const char *module_path)
> +{
> +	const char *refname;
> +	const struct submodule *sub;
> +	struct repository subrepo;
> +
> +	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
> +					  "HEAD", 0, NULL, NULL);
> +	sub = submodule_from_path(the_repository, null_oid(), module_path);
> +	repo_submodule_init(&subrepo, the_repository, sub);
> +	return repo_get_default_remote(&subrepo, refname);
> +}

This call (and I think there is another call in this file) to
repo_submodule_init() is affected by what Jonathan's 8eb8dcf9
(repository: support unabsorbed in repo_submodule_init, 2021-09-09)
wants to do, namely to lose "struct submodule sub" as a parameter
and instead take the path to the module and the treeish name as
parameters to repo_submodule_init().

I _think_ I resolved the conflict correctly, but please double check
the result when it is pushed out later today, both of you.

Thanks.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository
  2021-09-20 21:28     ` Junio C Hamano
@ 2021-09-21 16:33       ` Jonathan Tan
  0 siblings, 0 replies; 56+ messages in thread
From: Jonathan Tan @ 2021-09-21 16:33 UTC (permalink / raw)
  To: gitster; +Cc: raykar.ath, jonathantanmy, git

> Atharva Raykar <raykar.ath@gmail.com> writes:
> 
> > +static char *get_default_remote_submodule(const char *module_path)
> > +{
> > +	const char *refname;
> > +	const struct submodule *sub;
> > +	struct repository subrepo;
> > +
> > +	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
> > +					  "HEAD", 0, NULL, NULL);
> > +	sub = submodule_from_path(the_repository, null_oid(), module_path);
> > +	repo_submodule_init(&subrepo, the_repository, sub);
> > +	return repo_get_default_remote(&subrepo, refname);
> > +}
> 
> This call (and I think there is another call in this file) to
> repo_submodule_init() is affected by what Jonathan's 8eb8dcf9
> (repository: support unabsorbed in repo_submodule_init, 2021-09-09)
> wants to do, namely to lose "struct submodule sub" as a parameter
> and instead take the path to the module and the treeish name as
> parameters to repo_submodule_init().
> 
> I _think_ I resolved the conflict correctly, but please double check
> the result when it is pushed out later today, both of you.
> 
> Thanks.

Thanks for calling this out. There are indeed 2 such calls in 33cfc43433
("Merge branch 'ar/submodule-update' into seen", 2021-09-20) and both
look correct.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C
  2021-09-20 17:13     ` Junio C Hamano
@ 2021-10-03 10:38       ` Atharva Raykar
  0 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-03 10:38 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


Junio C Hamano <gitster@pobox.com> writes:
>
> It seems that this step does too many things in one step and makes
> it harder than necessary for readers to understand what is going on.
>
> For example, as far as I can see, the change to optionally allow
> passing superprefix to init_submodule() can be made without anything
> else in this step (i.e. "we allow superprefix from the parameter to
> override what get_super_prefix() would give us, but at this step,
> everybody passes NULL and the behaviour is unchanged" would be one
> such step), later to be followed by a change that involves passing a
> non-NULL value there, and it would become a lot easier to see who
> passes a non-NULL super prefix, what value is passed and for what
> purpose, with such an organization.
>
> A 650+ lines single patch like this buries the details and forces
> the readers to disect them out.  The change that teaches
> run_update_command() to instead use capture_command() and gives the
> error message to its callers may be another example of what may be
> better done as an independent step before tying the whole thing
> together.
>
> It is larger than what I comfortably can spend my time on while
> tending patches from other topics, so I'll skip reviewing this step
> for now.
>
> Thanks.

Understood. Apologies for the lack of updates on this topic, I will work
on organising this patch (and this series) better. I've taken a note of
the conflicts with other topics as well.

I don't mind the other topics being prioritized over this one. At the
moment I am not too confident about being able to quickly iterate over
this series. I'll try my best anyway.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository
  2021-09-20 16:52     ` Junio C Hamano
@ 2021-10-03 13:22       ` Atharva Raykar
  0 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-03 13:22 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


Junio C Hamano <gitster@pobox.com> writes:

> Atharva Raykar <raykar.ath@gmail.com> writes:
>
>> `get_default_remote()` retrieves the name of a remote by resolving the
>> refs from of the current repository's ref store.
>>
>> Thus in order to use it for retrieving the remote name of a submodule,
>> we have to start a new subprocess which runs from the submodule
>> directory.
>>
>> Let's instead introduce a function called `repo_get_default_remote()`
>> which takes any repository object and retrieves the remote accordingly.
>>
>> `get_default_remote()` is then defined as a call to
>> `repo_get_default_remote()` with 'the_repository' passed to it.
>>
>> Now that we have `repo_get_default_remote()`, we no longer have to start
>> a subprocess that called `submodule--helper get-default-remote` from
>> within the submodule directory.
>>
>> So let's make a function called `get_default_remote_submodule()` which
>> takes a submodule path, and returns the default remote for that
>> submodule, all within the same process.
>>
>> We can now use this function to save an unnecessary subprocess spawn in
>> `sync_submodule()`, and also in the next patch, which will require this
>> functionality.
>>
>> Mentored-by: Christian Couder <christian.couder@gmail.com>
>> Mentored-by: Shourya Shukla <periperidip@gmail.com>
>> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
>> ---
>>  builtin/submodule--helper.c | 34 +++++++++++++++++++++++-----------
>>  1 file changed, 23 insertions(+), 11 deletions(-)
>
> The above covers a lot of stuff, because this change does a lot of
> things ;-)
>
> The commit could be split into 3 logically distinct phases (two
> independent, the third depends on the other two):
>
>  - extract the part that uses the run-command() API to run
>    "submodule--helper print-default-remote" from sync_submodule()
>    and create get_default_remote_submodule() function out of it.
>
>  - move bulk of get_default_remote() into repo_get_default_remote()
>    and reimplement the former as a thin wrapper of the latter.
>
>  - using the repo_get_default_remote() created in the second step,
>    update the get_default_remote_submodule() created in the first
>    step to work in-process without a subprocess.
>
> but a bit larger granularity used here is probably OK.
>
[...]
>>  	strbuf_reset(&sb);
>> -	if (capture_command(&cp, &sb, 0))
>> +	strbuf_addstr(&sb, get_default_remote_submodule(path));
>> +	if (!sb.buf)
>>  		die(_("failed to get the default remote for submodule '%s'"),
>>  		      path);
>
> There is this line after the post context presented here:
>
>         strbuf_strip_suffix(&sb, "\n");
>         remote_key = xstrfmt("remote.%s.url", sb.buf);
>
> The LF was expected to come from the capture_command(), but it no
> longer is needed after get_default_remote_submodule() switches to
> use the in-process method.  In fact, the use of sb for the purpose
> of forming remote_key is not needed.
>
>     tmp = get_default_remote_submodule(path);
>     if (!tmp)
> 	die(_("failed to get..."));
>     remote_key = xstrfmt("remote.%s.url", tmp);
>     free(tmp);
>
> Yes, I think the new code leaks, and makes it impossible not to
> leak, the returned value from get_default_remote_submodule() by
> passing the call as an argument to strbuf_addstr().

Thanks, this was a good catch.

> Both of the two bugs pointed out here would have been easier to spot
> if the commits were smaller, I would think, but as I said, a bit
> larger granularity used here was still manageable.

My initial series had this patch split up similar to what you suggested,
but I ultimately chose to favour the larger granularity to make the
whole series a bit shorter. This patch definitely towed the line a bit.

> Thanks.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 0/9] submodule: convert the rest of 'update' to C
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
                     ` (7 preceding siblings ...)
  2021-09-16 10:32   ` [PATCH v2 8/8] submodule--helper: rename helper functions Atharva Raykar
@ 2021-10-13  5:17   ` Atharva Raykar
  2021-10-13  5:17     ` [PATCH v3 1/9] submodule--helper: split up ensure_core_worktree() Atharva Raykar
                       ` (9 more replies)
  8 siblings, 10 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:17 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Since v2:
 - Rebased this series on top of a more up-to-date master branch.

 - Reorganized this series to (hopefully) make it easier to review, as per
   Junio's suggestions. I split up the patch that converts the rest of the
   update shell script to C into multiple steps. I also squashed the patches
   that removed unused helpers, as there was not clear criteria for it being two
   patches.

 - Plugged a memory leak while refactoring sync_submodule() to use my new
   helper.

Note on conflicting series:
--------------------------

This series currently conflicts with the work being done by Emily in
'es/superproject-aware-submodules' [1], mainly in the part where they cache the
superproject gitdir in the shell script that gets removed during conversion in
this series.

I have attempted to make a version of this series that is based on that topic [2],
and added the superproject gitdir caching code in C [3]. It passes the tests,
but I am not too confident about its correctness. I hope that branch can be
helpful in some way.

[1] https://lore.kernel.org/git/20210819200953.2105230-1-emilyshaffer@google.com/
[2] https://github.com/tfidfwastaken/git/commits/submodule-update-on-es-superproject-aware
    (fetch-it-via: git fetch https://github.com/tfidfwastaken/git submodule-update-on-es-superproject-aware)
[3] https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930

Fetch-it-Via:
git fetch https://github.com/tfidfwastaken/git submodule-update-list-3

Atharva Raykar (9):
  submodule--helper: split up ensure_core_worktree()
  submodule--helper: get remote names from any repository
  submodule--helper: rename helpers for update-clone
  submodule--helper: refactor get_submodule_displaypath()
  submodule--helper: allow setting superprefix for init_submodule()
  submodule--helper: run update using child process struct
  submodule: move core cmd_update() logic to C
  submodule--helper: remove unused helpers
  submodule--helper: rename helper functions

 builtin/submodule--helper.c | 771 +++++++++++++++++++++---------------
 git-submodule.sh            | 145 +------
 2 files changed, 458 insertions(+), 458 deletions(-)

Range diff against the previous version:

 1:  f83a5b7f34 !  1:  d057ba04bd submodule--helper: split up ensure_core_worktree()
    @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv,
     -static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
     +static void do_ensure_core_worktree(const char *path)
      {
    - 	const struct submodule *sub;
     -	const char *path;
      	const char *cw;
      	struct repository subrepo;
    @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv,
     -
     -	path = argv[1];
     -
    - 	sub = submodule_from_path(the_repository, null_oid(), path);
    - 	if (!sub)
    - 		BUG("We could get the submodule handle before?");
    + 	if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
    + 		die(_("could not get a repository handle for submodule '%s'"), path);
    +
     @@ builtin/submodule--helper.c: static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
      		free(abs_path);
      		strbuf_release(&sb);
 2:  7f4e24ce25 !  2:  895cc10b97 submodule--helper: get remote names from any repository
    @@ builtin/submodule--helper.c: static char *get_default_remote(void)
     +static char *get_default_remote_submodule(const char *module_path)
     +{
     +	const char *refname;
    -+	const struct submodule *sub;
     +	struct repository subrepo;
     +
     +	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
     +					  "HEAD", 0, NULL, NULL);
    -+	sub = submodule_from_path(the_repository, null_oid(), module_path);
    -+	repo_submodule_init(&subrepo, the_repository, sub);
    ++	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
     +	return repo_get_default_remote(&subrepo, refname);
     +}
     +
    @@ builtin/submodule--helper.c: static char *get_default_remote(void)
      {
      	char *remote;
     @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const char *prefix,
    + {
    + 	const struct submodule *sub;
      	char *remote_key = NULL;
    - 	char *sub_origin_url, *super_config_url, *displaypath;
    +-	char *sub_origin_url, *super_config_url, *displaypath;
    ++	char *sub_origin_url, *super_config_url, *displaypath, *default_remote;
      	struct strbuf sb = STRBUF_INIT;
     -	struct child_process cp = CHILD_PROCESS_INIT;
      	char *sub_config_path = NULL;
    @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const
     -
      	strbuf_reset(&sb);
     -	if (capture_command(&cp, &sb, 0))
    -+	strbuf_addstr(&sb, get_default_remote_submodule(path));
    -+	if (!sb.buf)
    ++	default_remote = get_default_remote_submodule(path);
    ++	if (!default_remote)
      		die(_("failed to get the default remote for submodule '%s'"),
      		      path);

    +-	strbuf_strip_suffix(&sb, "\n");
    +-	remote_key = xstrfmt("remote.%s.url", sb.buf);
    ++	remote_key = xstrfmt("remote.%s.url", default_remote);
    ++	free(default_remote);
    +
    +-	strbuf_reset(&sb);
    + 	submodule_to_gitdir(&sb, path);
    + 	strbuf_addstr(&sb, "/config");
    +
 3:  390596ee7c =  3:  1defe3e0ca submodule--helper: rename helpers for update-clone
 4:  2a2ddcac91 =  4:  693b23772a submodule--helper: refactor get_submodule_displaypath()
 -:  ---------- >  5:  d1fd902a2a submodule--helper: allow setting superprefix for init_submodule()
 -:  ---------- >  6:  19c6c4e81a submodule--helper: run update using child process struct
 5:  832020a290 !  7:  7cc32ad6f9 submodule: move core cmd_update() logic to C
    @@ Commit message
         new subprocess and call `submodule--helper init` on the submodule paths,
         because the Git machinery is not able to pick up the configuration
         changes introduced by that init call[1]. So we instead run the
    -    `init_submodule_cb()` callback over each submodule directly.
    -
    -    This introduces another problem, because there is no mechanism to pass
    -    the superproject path prefix (ie, `--super-prefix`) without starting a
    -    new git process. This field is required for obtaining the display path
    -    for that is used by the command's output messages. So let's add a field
    -    into the `init_cb` struct that lets us pass this information to
    -    `init_submodule()`, which will now also take an explicit 'superprefix'
    -    argument.
    +    `init_submodule_cb()` callback over each submodule in the same process.

         While we are at it, we also remove the fetch_in_submodule() shell
         function since it is no longer used anywhere.
    @@ Commit message
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>

      ## builtin/submodule--helper.c ##
    -@@ builtin/submodule--helper.c: static char *compute_submodule_clone_url(const char *rel_url)
    -
    - struct init_cb {
    - 	const char *prefix;
    -+	const char *superprefix;
    - 	unsigned int flags;
    - };
    --#define INIT_CB_INIT { NULL, 0 }
    -+#define INIT_CB_INIT { 0 }
    -
    - static void init_submodule(const char *path, const char *prefix,
    --			   unsigned int flags)
    -+			   const char *superprefix, unsigned int flags)
    - {
    - 	const struct submodule *sub;
    - 	struct strbuf sb = STRBUF_INIT;
    - 	char *upd = NULL, *url = NULL, *displaypath;
    -
    --	displaypath = get_submodule_displaypath(path, prefix);
    -+	/* try superprefix from the environment, if it is not passed explicitly */
    -+	if (!superprefix)
    -+		superprefix = get_super_prefix();
    -+	displaypath = do_get_submodule_displaypath(path, prefix, superprefix);
    -
    - 	sub = submodule_from_path(the_repository, null_oid(), path);
    -
    -@@ builtin/submodule--helper.c: static void init_submodule(const char *path, const char *prefix,
    - static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
    - {
    - 	struct init_cb *info = cb_data;
    --	init_submodule(list_item->name, info->prefix, info->flags);
    -+	init_submodule(list_item->name, info->prefix, info->superprefix, info->flags);
    - }
    -
    - static int module_init(int argc, const char **argv, const char *prefix)
     @@ builtin/submodule--helper.c: struct submodule_update_clone {
      	const char *prefix;
      	int single_branch;
    @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_pa
     -static int run_update_command(struct update_data *ud, int subforce)
     +static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)
      {
    --	struct strvec args = STRVEC_INIT;
    --	struct strvec child_env = STRVEC_INIT;
    -+	struct child_process cp = CHILD_PROCESS_INIT;
    + 	struct child_process cp = CHILD_PROCESS_INIT;
      	char *oid = oid_to_hex(&ud->oid);
     +	struct strbuf out = STRBUF_INIT;
      	int must_die_on_failure = 0;
    --	int git_cmd;
     +	struct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;
    -+
    +
    +-	switch (ud->update_strategy.type) {
     +	if (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)
     +		determine_submodule_update_strategy(the_repository, ud->just_cloned,
     +						    ud->sm_path, NULL, &strategy);
     +	else
     +		strategy = ud->update_strategy;
    -
    --	switch (ud->update_strategy.type) {
    -+	cp.dir = xstrdup(ud->sm_path);
    ++
     +	switch (strategy.type) {
      	case SM_UPDATE_CHECKOUT:
    --		git_cmd = 1;
    --		strvec_pushl(&args, "checkout", "-q", NULL);
    -+		cp.git_cmd = 1;
    -+		strvec_pushl(&cp.args, "checkout", "-q", NULL);
    - 		if (subforce)
    --			strvec_push(&args, "-f");
    -+			strvec_push(&cp.args, "-f");
    - 		break;
    - 	case SM_UPDATE_REBASE:
    --		git_cmd = 1;
    --		strvec_push(&args, "rebase");
    -+		cp.git_cmd = 1;
    -+		strvec_push(&cp.args, "rebase");
    - 		if (ud->quiet)
    --			strvec_push(&args, "--quiet");
    -+			strvec_push(&cp.args, "--quiet");
    - 		must_die_on_failure = 1;
    - 		break;
    - 	case SM_UPDATE_MERGE:
    --		git_cmd = 1;
    --		strvec_push(&args, "merge");
    -+		cp.git_cmd = 1;
    -+		strvec_push(&cp.args, "merge");
    - 		if (ud->quiet)
    --			strvec_push(&args, "--quiet");
    -+			strvec_push(&cp.args, "--quiet");
    - 		must_die_on_failure = 1;
    + 		cp.git_cmd = 1;
    + 		strvec_pushl(&cp.args, "checkout", "-q", NULL);
    +@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)
      		break;
      	case SM_UPDATE_COMMAND:
    --		git_cmd = 0;
    --		strvec_push(&args, ud->update_strategy.command);
    -+		cp.git_cmd = 0;
    -+		cp.use_shell = 1;
    + 		cp.use_shell = 1;
    +-		strvec_push(&cp.args, ud->update_strategy.command);
     +		strvec_push(&cp.args, strategy.command);
      		must_die_on_failure = 1;
      		break;
    @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_pa
     -		    submodule_strategy_to_string(&ud->update_strategy));
     +		    submodule_strategy_to_string(&strategy));
      	}
    --	strvec_push(&args, oid);
    -+	strvec_push(&cp.args, oid);
    + 	strvec_push(&cp.args, oid);

    --	prepare_submodule_repo_env(&child_env);
    --	if (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,
    --				     ud->sm_path, child_env.v)) {
    + 	cp.dir = xstrdup(ud->sm_path);
    + 	prepare_submodule_repo_env(&cp.env_array);
    +-	if (run_command(&cp)) {
     -		switch (ud->update_strategy.type) {
    -+	prepare_submodule_repo_env(&cp.env_array);
     +	if (capture_command(&cp, &out, 0)) {
     +		if (must_die_on_failure) {
     +			switch (strategy.type) {
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
      struct add_data {
      	const char *prefix;
      	const char *branch;
    -@@ builtin/submodule--helper.c: static int add_clone(int argc, const char **argv, const char *prefix)
    +@@ builtin/submodule--helper.c: static int module_add(int argc, const char **argv, const char *prefix)
      	return 0;
      }

    @@ builtin/submodule--helper.c: static int add_clone(int argc, const char **argv, c
     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {
      	{"name", module_name, 0},
      	{"clone", module_clone, 0},
    - 	{"add-clone", add_clone, 0},
    + 	{"add", module_add, SUPPORT_SUPER_PREFIX},
     +	{"update", module_update, 0},
      	{"update-module-mode", module_update_module_mode, 0},
      	{"update-clone", update_clone, 0},
 6:  fb3fa8174a <  -:  ---------- submodule--helper: remove update-clone subcommand
 7:  364f72f870 !  8:  486f9d0a0e submodule--helper: remove unused helpers
    @@ Commit message
         These helpers were useful back when 'submodule update' had most of its
         logic in shell. Now that they will never be invoked, let us remove them.

    +    We also no longer need the 'update_clone_submodules()' and
    +    'update_clone_submodule()' functions, so we remove those as well.
    +
         Mentored-by: Christian Couder <christian.couder@gmail.com>
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
      	return run_update_command(ud, subforce, err);
      }

    +-static void update_clone_submodule(struct update_clone_data *ucd)
    +-{
    +-	fprintf(stdout, "dummy %s %d\t%s\n",
    +-		oid_to_hex(&ucd->oid),
    +-		ucd->just_cloned,
    +-		ucd->sub->path);
    +-}
    +-
    +-static int update_clone_submodules(struct submodule_update_clone *suc)
    +-{
    +-	int i;
    +-
    +-	run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
    +-				   update_clone_start_failure,
    +-				   update_clone_task_finished, suc, "submodule",
    +-				   "parallel/update");
    +-
    +-	/*
    +-	 * We saved the output and put it out all at once now.
    +-	 * That means:
    +-	 * - the listener does not have to interleave their (checkout)
    +-	 *   work with our fetching.  The writes involved in a
    +-	 *   checkout involve more straightforward sequential I/O.
    +-	 * - the listener can avoid doing any work if fetching failed.
    +-	 */
    +-	if (suc->quickstop)
    +-		return 1;
    +-
    +-	for (i = 0; i < suc->update_clone_nr; i++)
    +-		update_clone_submodule(&suc->update_clone[i]);
    +-
    +-	return 0;
    +-}
    +-
    +-static int update_clone(int argc, const char **argv, const char *prefix)
    +-{
    +-	const char *update = NULL;
    +-	struct pathspec pathspec;
    +-	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
    +-
    +-	struct option module_update_clone_options[] = {
    +-		OPT_STRING(0, "prefix", &prefix,
    +-			   N_("path"),
    +-			   N_("path into the working tree")),
    +-		OPT_STRING(0, "recursive-prefix", &suc.recursive_prefix,
    +-			   N_("path"),
    +-			   N_("path into the working tree, across nested "
    +-			      "submodule boundaries")),
    +-		OPT_STRING(0, "update", &update,
    +-			   N_("string"),
    +-			   N_("rebase, merge, checkout or none")),
    +-		OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
    +-			   N_("reference repository")),
    +-		OPT_BOOL(0, "dissociate", &suc.dissociate,
    +-			   N_("use --reference only while cloning")),
    +-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
    +-			   N_("create a shallow clone truncated to the "
    +-			      "specified number of revisions")),
    +-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
    +-			    N_("parallel jobs")),
    +-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
    +-			    N_("whether the initial clone should follow the shallow recommendation")),
    +-		OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
    +-		OPT_BOOL(0, "progress", &suc.progress,
    +-			    N_("force cloning progress")),
    +-		OPT_BOOL(0, "require-init", &suc.require_init,
    +-			   N_("disallow cloning into non-empty directory")),
    +-		OPT_BOOL(0, "single-branch", &suc.single_branch,
    +-			 N_("clone only one branch, HEAD or --branch")),
    +-		OPT_END()
    +-	};
    +-
    +-	const char *const git_submodule_helper_usage[] = {
    +-		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
    +-		NULL
    +-	};
    +-	suc.prefix = prefix;
    +-
    +-	update_clone_config_from_gitmodules(&suc.max_jobs);
    +-	git_config(git_update_clone_config, &suc.max_jobs);
    +-
    +-	argc = parse_options(argc, argv, prefix, module_update_clone_options,
    +-			     git_submodule_helper_usage, 0);
    +-
    +-	if (update)
    +-		if (parse_submodule_update_strategy(update, &suc.update) < 0)
    +-			die(_("bad value for update parameter"));
    +-
    +-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
    +-		return 1;
    +-
    +-	if (pathspec.nr)
    +-		suc.warn_if_uninitialized = 1;
    +-
    +-	return update_clone_submodules(&suc);
    +-}
    +-
     -static int run_update_procedure(int argc, const char **argv, const char *prefix)
     -{
     -	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
    @@ builtin/submodule--helper.c: static void do_ensure_core_worktree(const char *pat
      	int i;
     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {
      	{"clone", module_clone, 0},
    - 	{"add-clone", add_clone, 0},
    + 	{"add", module_add, SUPPORT_SUPER_PREFIX},
      	{"update", module_update, 0},
     -	{"update-module-mode", module_update_module_mode, 0},
    +-	{"update-clone", update_clone, 0},
     -	{"run-update-procedure", run_update_procedure, 0},
     -	{"ensure-core-worktree", ensure_core_worktree, 0},
     -	{"relative-path", resolve_relative_path, 0},
    - 	{"resolve-relative-url", resolve_relative_url, 0},
      	{"resolve-relative-url-test", resolve_relative_url_test, 0},
      	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
      	{"init", module_init, SUPPORT_SUPER_PREFIX},
 8:  ca48dd452c !  9:  7b5b2be1a0 submodule--helper: rename helper functions
    @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv,
     -static void do_ensure_core_worktree(const char *path)
     +static void ensure_core_worktree(const char *path)
      {
    - 	const struct submodule *sub;
      	const char *cw;
    + 	struct repository subrepo;
     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)
      	char *prefixed_path;
      	struct string_list err = STRING_LIST_INIT_DUP;

-- 
2.32.0

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 1/9] submodule--helper: split up ensure_core_worktree()
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
@ 2021-10-13  5:17     ` Atharva Raykar
  2021-10-13  5:17     ` [PATCH v3 2/9] submodule--helper: get remote names from any repository Atharva Raykar
                       ` (8 subsequent siblings)
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:17 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Let's split up `ensure_core_worktree()` so that we can call it from C
code without needing to deal with command line arguments.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 88ce6be69c..764fcb7dba 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2764,17 +2764,11 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
+static void do_ensure_core_worktree(const char *path)
 {
-	const char *path;
 	const char *cw;
 	struct repository subrepo;
 
-	if (argc != 2)
-		BUG("submodule--helper ensure-core-worktree <path>");
-
-	path = argv[1];
-
 	if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
 		die(_("could not get a repository handle for submodule '%s'"), path);
 
@@ -2794,6 +2788,17 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 		free(abs_path);
 		strbuf_release(&sb);
 	}
+}
+
+static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
+{
+	const char *path;
+
+	if (argc != 2)
+		BUG("submodule--helper ensure-core-worktree <path>");
+
+	path = argv[1];
+	do_ensure_core_worktree(path);
 
 	return 0;
 }
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 2/9] submodule--helper: get remote names from any repository
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
  2021-10-13  5:17     ` [PATCH v3 1/9] submodule--helper: split up ensure_core_worktree() Atharva Raykar
@ 2021-10-13  5:17     ` Atharva Raykar
  2021-10-13  5:17     ` [PATCH v3 3/9] submodule--helper: rename helpers for update-clone Atharva Raykar
                       ` (7 subsequent siblings)
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:17 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

`get_default_remote()` retrieves the name of a remote by resolving the
refs from of the current repository's ref store.

Thus in order to use it for retrieving the remote name of a submodule,
we have to start a new subprocess which runs from the submodule
directory.

Let's instead introduce a function called `repo_get_default_remote()`
which takes any repository object and retrieves the remote accordingly.

`get_default_remote()` is then defined as a call to
`repo_get_default_remote()` with 'the_repository' passed to it.

Now that we have `repo_get_default_remote()`, we no longer have to start
a subprocess that called `submodule--helper get-default-remote` from
within the submodule directory.

So let's make a function called `get_default_remote_submodule()` which
takes a submodule path, and returns the default remote for that
submodule, all within the same process.

We can now use this function to save an unnecessary subprocess spawn in
`sync_submodule()`, and also in the next patch, which will require this
functionality.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 39 +++++++++++++++++++++++--------------
 1 file changed, 24 insertions(+), 15 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 764fcb7dba..bbab43230b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -29,11 +29,10 @@
 typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
 				  void *cb_data);
 
-static char *get_default_remote(void)
+static char *repo_get_default_remote(struct repository *repo, const char *refname)
 {
 	char *dest = NULL, *ret;
 	struct strbuf sb = STRBUF_INIT;
-	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 
 	if (!refname)
 		die(_("No such ref: %s"), "HEAD");
@@ -46,7 +45,7 @@ static char *get_default_remote(void)
 		die(_("Expecting a full ref name, got %s"), refname);
 
 	strbuf_addf(&sb, "branch.%s.remote", refname);
-	if (git_config_get_string(sb.buf, &dest))
+	if (repo_config_get_string(repo, sb.buf, &dest))
 		ret = xstrdup("origin");
 	else
 		ret = dest;
@@ -55,6 +54,23 @@ static char *get_default_remote(void)
 	return ret;
 }
 
+static char *get_default_remote_submodule(const char *module_path)
+{
+	const char *refname;
+	struct repository subrepo;
+
+	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
+					  "HEAD", 0, NULL, NULL);
+	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
+	return repo_get_default_remote(&subrepo, refname);
+}
+
+static char *get_default_remote(void)
+{
+	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+	return repo_get_default_remote(the_repository, refname);
+}
+
 static int print_default_remote(int argc, const char **argv, const char *prefix)
 {
 	char *remote;
@@ -1341,9 +1357,8 @@ static void sync_submodule(const char *path, const char *prefix,
 {
 	const struct submodule *sub;
 	char *remote_key = NULL;
-	char *sub_origin_url, *super_config_url, *displaypath;
+	char *sub_origin_url, *super_config_url, *displaypath, *default_remote;
 	struct strbuf sb = STRBUF_INIT;
-	struct child_process cp = CHILD_PROCESS_INIT;
 	char *sub_config_path = NULL;
 
 	if (!is_submodule_active(the_repository, path))
@@ -1382,21 +1397,15 @@ static void sync_submodule(const char *path, const char *prefix,
 	if (!is_submodule_populated_gently(path, NULL))
 		goto cleanup;
 
-	prepare_submodule_repo_env(&cp.env_array);
-	cp.git_cmd = 1;
-	cp.dir = path;
-	strvec_pushl(&cp.args, "submodule--helper",
-		     "print-default-remote", NULL);
-
 	strbuf_reset(&sb);
-	if (capture_command(&cp, &sb, 0))
+	default_remote = get_default_remote_submodule(path);
+	if (!default_remote)
 		die(_("failed to get the default remote for submodule '%s'"),
 		      path);
 
-	strbuf_strip_suffix(&sb, "\n");
-	remote_key = xstrfmt("remote.%s.url", sb.buf);
+	remote_key = xstrfmt("remote.%s.url", default_remote);
+	free(default_remote);
 
-	strbuf_reset(&sb);
 	submodule_to_gitdir(&sb, path);
 	strbuf_addstr(&sb, "/config");
 
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 3/9] submodule--helper: rename helpers for update-clone
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
  2021-10-13  5:17     ` [PATCH v3 1/9] submodule--helper: split up ensure_core_worktree() Atharva Raykar
  2021-10-13  5:17     ` [PATCH v3 2/9] submodule--helper: get remote names from any repository Atharva Raykar
@ 2021-10-13  5:17     ` Atharva Raykar
  2021-10-13  5:18     ` [PATCH v3 4/9] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
                       ` (6 subsequent siblings)
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:17 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

The `update-clone` subcommand helpers that perform the parallel clone
and printing to stdout for shell script consumption, are renamed.

This lets us use the names `update_submodules()` and
`update_submodule()` for the helpers in the next patch, when we create
an `update` subcommand that does a full conversion.

We will get rid of these helpers in a cleanup patch at the end of this
series, when the `update-clone` command is no longer useful to us.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index bbab43230b..f60db966ea 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2466,7 +2466,7 @@ static int do_run_update_procedure(struct update_data *ud)
 	return run_update_command(ud, subforce);
 }
 
-static void update_submodule(struct update_clone_data *ucd)
+static void update_clone_submodule(struct update_clone_data *ucd)
 {
 	fprintf(stdout, "dummy %s %d\t%s\n",
 		oid_to_hex(&ucd->oid),
@@ -2474,7 +2474,7 @@ static void update_submodule(struct update_clone_data *ucd)
 		ucd->sub->path);
 }
 
-static int update_submodules(struct submodule_update_clone *suc)
+static int update_clone_submodules(struct submodule_update_clone *suc)
 {
 	int i;
 
@@ -2495,7 +2495,7 @@ static int update_submodules(struct submodule_update_clone *suc)
 		return 1;
 
 	for (i = 0; i < suc->update_clone_nr; i++)
-		update_submodule(&suc->update_clone[i]);
+		update_clone_submodule(&suc->update_clone[i]);
 
 	return 0;
 }
@@ -2560,7 +2560,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	if (pathspec.nr)
 		suc.warn_if_uninitialized = 1;
 
-	return update_submodules(&suc);
+	return update_clone_submodules(&suc);
 }
 
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 4/9] submodule--helper: refactor get_submodule_displaypath()
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
                       ` (2 preceding siblings ...)
  2021-10-13  5:17     ` [PATCH v3 3/9] submodule--helper: rename helpers for update-clone Atharva Raykar
@ 2021-10-13  5:18     ` Atharva Raykar
  2021-10-13  5:18     ` [PATCH v3 5/9] submodule--helper: allow setting superprefix for init_submodule() Atharva Raykar
                       ` (5 subsequent siblings)
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:18 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

We create a function called `do_get_submodule_displaypath()` that
generates the display path required by several submodule functions, and
takes a custom superprefix parameter, instead of reading it from the
environment.

We then redefine the existing `get_submodule_displaypath()` function
as a call to this new function, where the superprefix is obtained from
the environment.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f60db966ea..5b4f1dbcbd 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -261,11 +261,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
 	return 0;
 }
 
-/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *do_get_submodule_displaypath(const char *path, const char *prefix, const char *super_prefix)
 {
-	const char *super_prefix = get_super_prefix();
-
 	if (prefix && super_prefix) {
 		BUG("cannot have prefix '%s' and superprefix '%s'",
 		    prefix, super_prefix);
@@ -281,6 +278,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)
 	}
 }
 
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+	const char *super_prefix = get_super_prefix();
+	return do_get_submodule_displaypath(path, prefix, super_prefix);
+}
+
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
 	struct strbuf sb = STRBUF_INIT;
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 5/9] submodule--helper: allow setting superprefix for init_submodule()
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
                       ` (3 preceding siblings ...)
  2021-10-13  5:18     ` [PATCH v3 4/9] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
@ 2021-10-13  5:18     ` Atharva Raykar
  2021-10-13  5:18     ` [PATCH v3 6/9] submodule--helper: run update using child process struct Atharva Raykar
                       ` (4 subsequent siblings)
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:18 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

We allow callers of the `init_submodule()` function to optionally
override the superprefix from the environment.

We need to enable this option because in our conversion of the update
command that will follow, the '--init' option will be handled through
this API. We will need to change the superprefix at that time to ensure
the display paths show correctly in the output messages.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5b4f1dbcbd..74f084a9c9 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -606,18 +606,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 
 struct init_cb {
 	const char *prefix;
+	const char *superprefix;
 	unsigned int flags;
 };
-#define INIT_CB_INIT { NULL, 0 }
+#define INIT_CB_INIT { 0 }
 
 static void init_submodule(const char *path, const char *prefix,
-			   unsigned int flags)
+			   const char *superprefix, unsigned int flags)
 {
 	const struct submodule *sub;
 	struct strbuf sb = STRBUF_INIT;
 	char *upd = NULL, *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	/* try superprefix from the environment, if it is not passed explicitly */
+	if (!superprefix)
+		superprefix = get_super_prefix();
+	displaypath = do_get_submodule_displaypath(path, prefix, superprefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -691,7 +695,7 @@ static void init_submodule(const char *path, const char *prefix,
 static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 {
 	struct init_cb *info = cb_data;
-	init_submodule(list_item->name, info->prefix, info->flags);
+	init_submodule(list_item->name, info->prefix, info->superprefix, info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 6/9] submodule--helper: run update using child process struct
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
                       ` (4 preceding siblings ...)
  2021-10-13  5:18     ` [PATCH v3 5/9] submodule--helper: allow setting superprefix for init_submodule() Atharva Raykar
@ 2021-10-13  5:18     ` Atharva Raykar
  2021-10-13  5:18     ` [PATCH v3 7/9] submodule: move core cmd_update() logic to C Atharva Raykar
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:18 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

We switch to using the run-command API function that takes a
'struct child process', since we are using a lot of the options. This
will also make it simple to switch over to using 'capture_command()'
when we start handling the output of the command completely in C.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 34 ++++++++++++++++------------------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 74f084a9c9..640b3bd220 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2342,47 +2342,45 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
 
 static int run_update_command(struct update_data *ud, int subforce)
 {
-	struct strvec args = STRVEC_INIT;
-	struct strvec child_env = STRVEC_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
 	char *oid = oid_to_hex(&ud->oid);
 	int must_die_on_failure = 0;
-	int git_cmd;
 
 	switch (ud->update_strategy.type) {
 	case SM_UPDATE_CHECKOUT:
-		git_cmd = 1;
-		strvec_pushl(&args, "checkout", "-q", NULL);
+		cp.git_cmd = 1;
+		strvec_pushl(&cp.args, "checkout", "-q", NULL);
 		if (subforce)
-			strvec_push(&args, "-f");
+			strvec_push(&cp.args, "-f");
 		break;
 	case SM_UPDATE_REBASE:
-		git_cmd = 1;
-		strvec_push(&args, "rebase");
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "rebase");
 		if (ud->quiet)
-			strvec_push(&args, "--quiet");
+			strvec_push(&cp.args, "--quiet");
 		must_die_on_failure = 1;
 		break;
 	case SM_UPDATE_MERGE:
-		git_cmd = 1;
-		strvec_push(&args, "merge");
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "merge");
 		if (ud->quiet)
-			strvec_push(&args, "--quiet");
+			strvec_push(&cp.args, "--quiet");
 		must_die_on_failure = 1;
 		break;
 	case SM_UPDATE_COMMAND:
-		git_cmd = 0;
-		strvec_push(&args, ud->update_strategy.command);
+		cp.use_shell = 1;
+		strvec_push(&cp.args, ud->update_strategy.command);
 		must_die_on_failure = 1;
 		break;
 	default:
 		BUG("unexpected update strategy type: %s",
 		    submodule_strategy_to_string(&ud->update_strategy));
 	}
-	strvec_push(&args, oid);
+	strvec_push(&cp.args, oid);
 
-	prepare_submodule_repo_env(&child_env);
-	if (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,
-				     ud->sm_path, child_env.v)) {
+	cp.dir = xstrdup(ud->sm_path);
+	prepare_submodule_repo_env(&cp.env_array);
+	if (run_command(&cp)) {
 		switch (ud->update_strategy.type) {
 		case SM_UPDATE_CHECKOUT:
 			printf(_("Unable to checkout '%s' in submodule path '%s'"),
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 7/9] submodule: move core cmd_update() logic to C
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
                       ` (5 preceding siblings ...)
  2021-10-13  5:18     ` [PATCH v3 6/9] submodule--helper: run update using child process struct Atharva Raykar
@ 2021-10-13  5:18     ` Atharva Raykar
  2021-10-13  5:18     ` [PATCH v3 8/9] submodule--helper: remove unused helpers Atharva Raykar
                       ` (2 subsequent siblings)
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:18 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

This patch completes the conversion past the flag parsing of
`submodule update` by introducing a helper subcommand called
`submodule--helper update`. The behaviour of `submodule update` should
remain the same after this patch.

We add more fields to the `struct update_data` that are required by
`struct submodule_update_clone` to be able to perform a clone, when that
is needed to be done.

Recursing on a submodule is done by calling a subprocess that launches
`submodule--helper update`, with a modified `--recursive-prefix` and
`--prefix` parameter.

We also introduce `update_submodules()` and `update_submodule()` which
are quite similar to `update_clone_submodules()` and
`update_clone_submodule()`, and will supersede them.

When the `--init` flag is passed to the subcommand, we do not spawn a
new subprocess and call `submodule--helper init` on the submodule paths,
because the Git machinery is not able to pick up the configuration
changes introduced by that init call[1]. So we instead run the
`init_submodule_cb()` callback over each submodule in the same process.

While we are at it, we also remove the fetch_in_submodule() shell
function since it is no longer used anywhere.

[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 462 +++++++++++++++++++++++++++++++-----
 git-submodule.sh            | 145 +----------
 2 files changed, 410 insertions(+), 197 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 640b3bd220..3049628f88 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2010,7 +2010,6 @@ struct submodule_update_clone {
 	const char *prefix;
 	int single_branch;
 
-	/* to be consumed by git-submodule.sh */
 	struct update_clone_data *update_clone;
 	int update_clone_nr; int update_clone_alloc;
 
@@ -2033,19 +2032,63 @@ struct submodule_update_clone {
 }
 
 struct update_data {
+	const char *prefix;
 	const char *recursive_prefix;
 	const char *sm_path;
 	const char *displaypath;
 	struct object_id oid;
 	struct object_id suboid;
-	struct submodule_update_strategy update_strategy;
+	int max_jobs;
 	int depth;
+	int recommend_shallow;
+	int single_branch;
+	unsigned int init: 1;
 	unsigned int force: 1;
 	unsigned int quiet: 1;
 	unsigned int nofetch: 1;
-	unsigned int just_cloned: 1;
+	unsigned int remote: 1;
+	unsigned int recursive: 1;
+	unsigned int progress: 1;
+	unsigned int dissociate: 1;
+	unsigned int require_init: 1;
+	unsigned warn_if_uninitialized : 1;
+	unsigned int just_cloned : 1;
+	struct submodule_update_strategy update_strategy;
+	struct string_list references;
+	struct module_list list;
 };
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+	.list = MODULE_LIST_INIT, \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+	.recommend_shallow = -1, \
+	.references = STRING_LIST_INIT_DUP, \
+	.single_branch = -1, \
+	.max_jobs = 1, \
+}
+
+static void update_clone_from_update_data(struct submodule_update_clone *suc,
+					  struct update_data *update_data)
+{
+	suc->prefix = update_data->prefix;
+	suc->recursive_prefix = update_data->recursive_prefix;
+	suc->max_jobs = update_data->max_jobs;
+	suc->progress = update_data->progress;
+	suc->quiet = update_data->quiet;
+	suc->dissociate = update_data->dissociate;
+	suc->require_init = update_data->require_init;
+	suc->single_branch = update_data->single_branch;
+	suc->warn_if_uninitialized = update_data->warn_if_uninitialized;
+	suc->list = update_data->list;
+	suc->update = update_data->update_strategy;
+	suc->recommend_shallow = update_data->recommend_shallow;
+	if (update_data->depth)
+		suc->depth = xstrfmt("--depth=%d", update_data->depth);
+	if (update_data->references.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &update_data->references)
+			string_list_append(&suc->references, item->string);
+	}
+}
 
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
 		struct strbuf *out, const char *displaypath)
@@ -2340,13 +2383,21 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
 	return run_command(&cp);
 }
 
-static int run_update_command(struct update_data *ud, int subforce)
+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 	char *oid = oid_to_hex(&ud->oid);
+	struct strbuf out = STRBUF_INIT;
 	int must_die_on_failure = 0;
+	struct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;
 
-	switch (ud->update_strategy.type) {
+	if (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)
+		determine_submodule_update_strategy(the_repository, ud->just_cloned,
+						    ud->sm_path, NULL, &strategy);
+	else
+		strategy = ud->update_strategy;
+
+	switch (strategy.type) {
 	case SM_UPDATE_CHECKOUT:
 		cp.git_cmd = 1;
 		strvec_pushl(&cp.args, "checkout", "-q", NULL);
@@ -2369,80 +2420,75 @@ static int run_update_command(struct update_data *ud, int subforce)
 		break;
 	case SM_UPDATE_COMMAND:
 		cp.use_shell = 1;
-		strvec_push(&cp.args, ud->update_strategy.command);
+		strvec_push(&cp.args, strategy.command);
 		must_die_on_failure = 1;
 		break;
 	default:
 		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+		    submodule_strategy_to_string(&strategy));
 	}
 	strvec_push(&cp.args, oid);
 
 	cp.dir = xstrdup(ud->sm_path);
 	prepare_submodule_repo_env(&cp.env_array);
-	if (run_command(&cp)) {
-		switch (ud->update_strategy.type) {
-		case SM_UPDATE_CHECKOUT:
-			printf(_("Unable to checkout '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_REBASE:
-			printf(_("Unable to rebase '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_MERGE:
-			printf(_("Unable to merge '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
-			break;
-		case SM_UPDATE_COMMAND:
-			printf(_("Execution of '%s %s' failed in submodule path '%s'"),
-			       ud->update_strategy.command, oid, ud->displaypath);
-			break;
-		default:
-			BUG("unexpected update strategy type: %s",
-			    submodule_strategy_to_string(&ud->update_strategy));
+	if (capture_command(&cp, &out, 0)) {
+		if (must_die_on_failure) {
+			switch (strategy.type) {
+			case SM_UPDATE_CHECKOUT:
+				die(_("Unable to checkout '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_REBASE:
+				die(_("Unable to rebase '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_MERGE:
+				die(_("Unable to merge '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+				break;
+			case SM_UPDATE_COMMAND:
+				die(_("Execution of '%s %s' failed in submodule path '%s'"),
+				    strategy.command, oid, ud->displaypath);
+				break;
+			default:
+				BUG("unexpected update strategy type: %s",
+				    submodule_strategy_to_string(&strategy));
+			}
 		}
-		/*
-		 * NEEDSWORK: We are currently printing to stdout with error
-		 * return so that the shell caller handles the error output
-		 * properly. Once we start handling the error messages within
-		 * C, we should use die() instead.
-		 */
-		if (must_die_on_failure)
-			return 2;
-		/*
-		 * This signifies to the caller in shell that the command
-		 * failed without dying
-		 */
+
+		/* the command failed, but update must continue */
+		string_list_append(err, out.buf);
 		return 1;
 	}
 
-	switch (ud->update_strategy.type) {
-	case SM_UPDATE_CHECKOUT:
-		printf(_("Submodule path '%s': checked out '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_REBASE:
-		printf(_("Submodule path '%s': rebased into '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_MERGE:
-		printf(_("Submodule path '%s': merged in '%s'\n"),
-		       ud->displaypath, oid);
-		break;
-	case SM_UPDATE_COMMAND:
-		printf(_("Submodule path '%s': '%s %s'\n"),
-		       ud->displaypath, ud->update_strategy.command, oid);
-		break;
-	default:
-		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+	if (!ud->quiet) {
+		switch (strategy.type) {
+		case SM_UPDATE_CHECKOUT:
+			printf(_("Submodule path '%s': checked out '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_REBASE:
+			printf(_("Submodule path '%s': rebased into '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_MERGE:
+			printf(_("Submodule path '%s': merged in '%s'\n"),
+			       ud->displaypath, oid);
+			break;
+		case SM_UPDATE_COMMAND:
+			printf(_("Submodule path '%s': '%s %s'\n"),
+			       ud->displaypath, strategy.command, oid);
+			break;
+		default:
+			BUG("unexpected update strategy type: %s",
+			    submodule_strategy_to_string(&strategy));
+		}
 	}
 
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud)
+static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2469,7 +2515,7 @@ static int do_run_update_procedure(struct update_data *ud)
 			    ud->displaypath, oid_to_hex(&ud->oid));
 	}
 
-	return run_update_command(ud, subforce);
+	return run_update_command(ud, subforce, err);
 }
 
 static void update_clone_submodule(struct update_clone_data *ucd)
@@ -2574,6 +2620,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
 	char *prefixed_path, *update = NULL;
 	struct update_data update_data = UPDATE_DATA_INIT;
+	struct string_list err = STRING_LIST_INIT_DUP;
 
 	struct option options[] = {
 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
@@ -2631,7 +2678,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	free(prefixed_path);
 
 	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data);
+		return do_run_update_procedure(&update_data, &err);
 
 	return 3;
 }
@@ -3002,6 +3049,291 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 	return !!ret;
 }
 
+static void update_data_to_args(struct update_data *update_data, struct strvec *args)
+{
+	const char *update = submodule_strategy_to_string(&update_data->update_strategy);
+
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
+	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
+	if (update_data->prefix)
+		strvec_pushl(args, "--prefix", update_data->prefix, NULL);
+	if (update_data->recursive_prefix)
+		strvec_pushl(args, "--recursive-prefix",
+			     update_data->recursive_prefix, NULL);
+	if (update_data->quiet)
+		strvec_push(args, "--quiet");
+	if (update_data->force)
+		strvec_push(args, "--force");
+	if (update_data->init)
+		strvec_push(args, "--init");
+	if (update_data->remote)
+		strvec_push(args, "--remote");
+	if (update_data->nofetch)
+		strvec_push(args, "--no-fetch");
+	if (update_data->dissociate)
+		strvec_push(args, "--dissociate");
+	if (update_data->progress)
+		strvec_push(args, "--progress");
+	if (update_data->require_init)
+		strvec_push(args, "--require-init");
+	if (update_data->depth)
+		strvec_pushf(args, "--depth=%d", update_data->depth);
+	if (update)
+		strvec_pushl(args, "--update", update, NULL);
+	if (update_data->references.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &update_data->references)
+			strvec_pushl(args, "--reference", item->string, NULL);
+	}
+	if (update_data->recommend_shallow == 0)
+		strvec_push(args, "--no-recommend-shallow");
+	else if (update_data->recommend_shallow == 1)
+		strvec_push(args, "--recommend-shallow");
+	if (update_data->single_branch >= 0)
+		strvec_push(args, "--single-branch");
+}
+
+static int update_submodule(struct update_data *update_data)
+{
+	char *prefixed_path;
+	struct string_list err = STRING_LIST_INIT_DUP;
+
+	do_ensure_core_worktree(update_data->sm_path);
+
+	if (update_data->recursive_prefix)
+		prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
+					update_data->sm_path);
+	else
+		prefixed_path = xstrdup(update_data->sm_path);
+
+	update_data->displaypath = get_submodule_displaypath(prefixed_path,
+							     update_data->prefix);
+	free(prefixed_path);
+
+	if (update_data->just_cloned) {
+		oidcpy(&update_data->suboid, null_oid());
+	} else {
+		if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
+			die(_("Unable to find current revision in submodule path '%s'"),
+			    update_data->displaypath);
+	}
+
+	if (update_data->remote) {
+		char *remote_name = get_default_remote_submodule(update_data->sm_path);
+		const char *branch = remote_submodule_branch(update_data->sm_path);
+		char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+
+		if (!update_data->nofetch) {
+			if(fetch_in_submodule(update_data->sm_path, update_data->depth,
+					      0, NULL))
+				die(_("Unable to fetch in submodule path '%s'"),
+				    update_data->sm_path);
+		}
+
+		if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
+			die(_("Unable to find %s revision in submodule path '%s'"),
+			    remote_ref, update_data->sm_path);
+
+		free(remote_ref);
+	}
+
+	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
+		if (do_run_update_procedure(update_data, &err))
+			return 1;
+
+	if (update_data->recursive) {
+		int res;
+		struct child_process cp = CHILD_PROCESS_INIT;
+		struct update_data next = *update_data;
+		char *die_msg = xstrfmt(_("Failed to recurse into submodule path '%s'"),
+					update_data->displaypath);
+
+		if (update_data->recursive_prefix)
+			prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
+						update_data->sm_path);
+		else
+			prefixed_path = xstrfmt("%s/", update_data->sm_path);
+
+		next.recursive_prefix = get_submodule_displaypath(prefixed_path,
+								  update_data->prefix);
+		next.prefix = NULL;
+		oidcpy(&next.oid, null_oid());
+		oidcpy(&next.suboid, null_oid());
+
+		cp.dir = update_data->sm_path;
+		cp.git_cmd = 1;
+		prepare_submodule_repo_env(&cp.env_array);
+		update_data_to_args(&next, &cp.args);
+
+		/* die() if child process die()'d */
+		if ((res = run_command(&cp)) == 128)
+			die("%s", die_msg);
+		if (res)
+			string_list_append(&err, die_msg);
+
+		free(die_msg);
+	}
+
+	if (err.nr) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, &err)
+			fputs(item->string, stderr);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int update_submodules(struct update_data *update_data)
+{
+	int i, res = 0;
+	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+
+	update_clone_from_update_data(&suc, update_data);
+	run_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,
+				   update_clone_start_failure,
+				   update_clone_task_finished, &suc, "submodule",
+				   "parallel/update");
+
+	/*
+	 * We saved the output and put it out all at once now.
+	 * That means:
+	 * - the listener does not have to interleave their (checkout)
+	 *   work with our fetching.  The writes involved in a
+	 *   checkout involve more straightforward sequential I/O.
+	 * - the listener can avoid doing any work if fetching failed.
+	 */
+	if (suc.quickstop) {
+		string_list_clear(&update_data->references, 0);
+		return 1;
+	}
+
+	for (i = 0; i < suc.update_clone_nr; i++) {
+		struct update_clone_data ucd = suc.update_clone[i];
+
+		oidcpy(&update_data->oid, &ucd.oid);
+		update_data->just_cloned = ucd.just_cloned;
+		update_data->sm_path = ucd.sub->path;
+
+		if (update_submodule(update_data))
+			res = 1;
+	}
+
+	string_list_clear(&update_data->references, 0);
+	return res;
+}
+
+static int module_update(int argc, const char **argv, const char *prefix)
+{
+	int init = 0, force = 0, quiet = 0, nofetch = 0;
+	int remote = 0, recursive = 0, dissociate = 0;
+	int progress = 0, require_init = 0;
+	const char *update = NULL;
+	struct pathspec pathspec;
+	struct update_data update_data = UPDATE_DATA_INIT;
+
+	struct option module_update_clone_options[] = {
+		OPT__FORCE(&force, N_("force checkout updates"), 0),
+		OPT_BOOL(0, "init", &init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_BOOL(0, "remote", &remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_STRING(0, "prefix", &prefix,
+			   N_("path"),
+			   N_("path into the working tree")),
+		OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix,
+			   N_("path"),
+			   N_("path into the working tree, across nested "
+			      "submodule boundaries")),
+		OPT_STRING(0, "update", &update,
+			   N_("string"),
+			   N_("rebase, merge, checkout or none")),
+		OPT_STRING_LIST(0, "reference", &update_data.references, N_("repo"),
+				N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &dissociate,
+			 N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &update_data.depth,
+			    N_("create a shallow clone truncated to the "
+			       "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &update_data.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &update_data.recommend_shallow,
+			 N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &progress,
+			 N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &require_init,
+			 N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &update_data.single_branch,
+			 N_("clone only one branch, HEAD or --branch")),
+		OPT_END()
+	};
+
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
+		NULL
+	};
+
+	update_clone_config_from_gitmodules(&update_data.max_jobs);
+	git_config(git_update_clone_config, &update_data.max_jobs);
+
+	argc = parse_options(argc, argv, prefix, module_update_clone_options,
+			     git_submodule_helper_usage, 0);
+	update_data.prefix = prefix;
+
+	update_data.force = !!force;
+	update_data.quiet = !!quiet;
+	update_data.nofetch = !!nofetch;
+	update_data.init = !!init;
+	update_data.require_init = !!require_init;
+	update_data.remote = !!remote;
+	update_data.recursive = !!recursive;
+	update_data.progress = !!progress;
+	update_data.dissociate = !!dissociate;
+	oidcpy(&update_data.oid, null_oid());
+	oidcpy(&update_data.suboid, null_oid());
+
+	if (update)
+		if (parse_submodule_update_strategy(update,
+						    &update_data.update_strategy) < 0)
+			die(_("bad value for update parameter"));
+
+	if (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)
+		return 1;
+
+	if (pathspec.nr)
+		update_data.warn_if_uninitialized = 1;
+
+	if (update_data.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, update_data.prefix,
+					&pathspec, &list) < 0)
+			return 1;
+
+		/*
+		 * If there are no path args and submodule.active is set then,
+		 * by default, only initialize 'active' modules.
+		 */
+		if (!argc && git_config_get_value_multi("submodule.active"))
+			module_list_active(&list);
+
+		info.prefix = update_data.prefix;
+		info.superprefix = update_data.recursive_prefix;
+		if (update_data.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
+	return update_submodules(&update_data);
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
@@ -3360,6 +3692,7 @@ static int module_add(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
+
 #define SUPPORT_SUPER_PREFIX (1<<0)
 
 struct cmd_struct {
@@ -3373,6 +3706,7 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
+	{"update", module_update, 0},
 	{"update-module-mode", module_update_module_mode, 0},
 	{"update-clone", update_clone, 0},
 	{"run-update-procedure", run_update_procedure, 0},
diff --git a/git-submodule.sh b/git-submodule.sh
index 652861aa66..bcd8b92aab 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -246,20 +246,6 @@ cmd_deinit()
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
 }
 
-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]
-# Because arguments are positional, use an empty string to omit <depth>
-# but include <sha1>.
-fetch_in_submodule () (
-	sanitize_submodule_env &&
-	cd "$1" &&
-	if test $# -eq 3
-	then
-		echo "$3" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+"$2"}
-	else
-		git fetch ${GIT_QUIET:+--quiet} ${2:+"$2"}
-	fi
-)
-
 #
 # Update each submodule path to correct revision, using clone and checkout as needed
 #
@@ -361,133 +347,26 @@ cmd_update()
 		shift
 	done
 
-	if test -n "$init"
-	then
-		cmd_init "--" "$@" || return
-	fi
-
-	{
-	git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
-		${progress:+"--progress"} \
+	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
+		${GIT_QUIET:+--quiet} \
+		${force:+--force} \
+		${progress:+--progress} \
+		${dissociate:+--dissociate} \
+		${remote:+--remote} \
+		${recursive:+--recursive} \
+		${init:+--init} \
+		${require_init:+--require-init} \
+		${nofetch:+--no-fetch} \
 		${wt_prefix:+--prefix "$wt_prefix"} \
 		${prefix:+--recursive-prefix "$prefix"} \
 		${update:+--update "$update"} \
 		${reference:+"$reference"} \
-		${dissociate:+"--dissociate"} \
-		${depth:+--depth "$depth"} \
-		${require_init:+--require-init} \
+		${depth:+"$depth"} \
 		$single_branch \
 		$recommend_shallow \
 		$jobs \
 		-- \
-		"$@" || echo "#unmatched" $?
-	} | {
-	err=
-	while read -r quickabort sha1 just_cloned sm_path
-	do
-		die_if_unmatched "$quickabort" "$sha1"
-
-		git submodule--helper ensure-core-worktree "$sm_path" || exit 1
-
-		displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
-
-		if test $just_cloned -eq 1
-		then
-			subsha1=
-		else
-			just_cloned=
-			subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
-				git rev-parse --verify HEAD) ||
-			die "fatal: $(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
-		fi
-
-		if test -n "$remote"
-		then
-			branch=$(git submodule--helper remote-branch "$sm_path")
-			if test -z "$nofetch"
-			then
-				# Fetch remote before determining tracking $sha1
-				fetch_in_submodule "$sm_path" $depth ||
-				die "fatal: $(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
-			fi
-			remote_name=$(sanitize_submodule_env; cd "$sm_path" && git submodule--helper print-default-remote)
-			sha1=$(sanitize_submodule_env; cd "$sm_path" &&
-				git rev-parse --verify "${remote_name}/${branch}") ||
-			die "fatal: $(eval_gettext "Unable to find current \${remote_name}/\${branch} revision in submodule path '\$sm_path'")"
-		fi
-
-		out=$(git submodule--helper run-update-procedure \
-			  ${wt_prefix:+--prefix "$wt_prefix"} \
-			  ${GIT_QUIET:+--quiet} \
-			  ${force:+--force} \
-			  ${just_cloned:+--just-cloned} \
-			  ${nofetch:+--no-fetch} \
-			  ${depth:+"$depth"} \
-			  ${update:+--update "$update"} \
-			  ${prefix:+--recursive-prefix "$prefix"} \
-			  ${sha1:+--oid "$sha1"} \
-			  ${subsha1:+--suboid "$subsha1"} \
-			  "--" \
-			  "$sm_path")
-
-		# exit codes for run-update-procedure:
-		# 0: update was successful, say command output
-		# 1: update procedure failed, but should not die
-		# 2 or 128: subcommand died during execution
-		# 3: no update procedure was run
-		res="$?"
-		case $res in
-		0)
-			say "$out"
-			;;
-		1)
-			err="${err};fatal: $out"
-			continue
-			;;
-		2|128)
-			die_with_status $res "fatal: $out"
-			;;
-		esac
-
-		if test -n "$recursive"
-		then
-			(
-				prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
-				wt_prefix=
-				sanitize_submodule_env
-				cd "$sm_path" &&
-				eval cmd_update
-			)
-			res=$?
-			if test $res -gt 0
-			then
-				die_msg="fatal: $(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
-				if test $res -ne 2
-				then
-					err="${err};$die_msg"
-					continue
-				else
-					die_with_status $res "$die_msg"
-				fi
-			fi
-		fi
-	done
-
-	if test -n "$err"
-	then
-		OIFS=$IFS
-		IFS=';'
-		for e in $err
-		do
-			if test -n "$e"
-			then
-				echo >&2 "$e"
-			fi
-		done
-		IFS=$OIFS
-		exit 1
-	fi
-	}
+		"$@"
 }
 
 #
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 8/9] submodule--helper: remove unused helpers
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
                       ` (6 preceding siblings ...)
  2021-10-13  5:18     ` [PATCH v3 7/9] submodule: move core cmd_update() logic to C Atharva Raykar
@ 2021-10-13  5:18     ` Atharva Raykar
  2021-10-13  5:18     ` [PATCH v3 9/9] submodule--helper: rename helper functions Atharva Raykar
  2021-10-14  0:05     ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Junio C Hamano
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:18 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

These helpers were useful back when 'submodule update' had most of its
logic in shell. Now that they will never be invoked, let us remove them.

We also no longer need the 'update_clone_submodules()' and
'update_clone_submodule()' functions, so we remove those as well.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 233 ------------------------------------
 1 file changed, 233 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 3049628f88..0d6e65bd6c 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -71,21 +71,6 @@ static char *get_default_remote(void)
 	return repo_get_default_remote(the_repository, refname);
 }
 
-static int print_default_remote(int argc, const char **argv, const char *prefix)
-{
-	char *remote;
-
-	if (argc != 1)
-		die(_("submodule--helper print-default-remote takes no arguments"));
-
-	remote = get_default_remote();
-	if (remote)
-		printf("%s\n", remote);
-
-	free(remote);
-	return 0;
-}
-
 static int starts_with_dot_slash(const char *str)
 {
 	return str[0] == '.' && is_dir_sep(str[1]);
@@ -1960,29 +1945,6 @@ static void determine_submodule_update_strategy(struct repository *r,
 	free(key);
 }
 
-static int module_update_module_mode(int argc, const char **argv, const char *prefix)
-{
-	const char *path, *update = NULL;
-	int just_cloned;
-	struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
-
-	if (argc < 3 || argc > 4)
-		die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
-
-	just_cloned = git_config_int("just_cloned", argv[1]);
-	path = argv[2];
-
-	if (argc == 4)
-		update = argv[3];
-
-	determine_submodule_update_strategy(the_repository,
-					    just_cloned, path, update,
-					    &update_strategy);
-	fputs(submodule_strategy_to_string(&update_strategy), stdout);
-
-	return 0;
-}
-
 struct update_clone_data {
 	const struct submodule *sub;
 	struct object_id oid;
@@ -2518,182 +2480,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e
 	return run_update_command(ud, subforce, err);
 }
 
-static void update_clone_submodule(struct update_clone_data *ucd)
-{
-	fprintf(stdout, "dummy %s %d\t%s\n",
-		oid_to_hex(&ucd->oid),
-		ucd->just_cloned,
-		ucd->sub->path);
-}
-
-static int update_clone_submodules(struct submodule_update_clone *suc)
-{
-	int i;
-
-	run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
-				   update_clone_start_failure,
-				   update_clone_task_finished, suc, "submodule",
-				   "parallel/update");
-
-	/*
-	 * We saved the output and put it out all at once now.
-	 * That means:
-	 * - the listener does not have to interleave their (checkout)
-	 *   work with our fetching.  The writes involved in a
-	 *   checkout involve more straightforward sequential I/O.
-	 * - the listener can avoid doing any work if fetching failed.
-	 */
-	if (suc->quickstop)
-		return 1;
-
-	for (i = 0; i < suc->update_clone_nr; i++)
-		update_clone_submodule(&suc->update_clone[i]);
-
-	return 0;
-}
-
-static int update_clone(int argc, const char **argv, const char *prefix)
-{
-	const char *update = NULL;
-	struct pathspec pathspec;
-	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
-
-	struct option module_update_clone_options[] = {
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "recursive-prefix", &suc.recursive_prefix,
-			   N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_STRING(0, "update", &update,
-			   N_("string"),
-			   N_("rebase, merge, checkout or none")),
-		OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
-			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &suc.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
-			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
-		OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
-		OPT_BOOL(0, "progress", &suc.progress,
-			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &suc.require_init,
-			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &suc.single_branch,
-			 N_("clone only one branch, HEAD or --branch")),
-		OPT_END()
-	};
-
-	const char *const git_submodule_helper_usage[] = {
-		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
-		NULL
-	};
-	suc.prefix = prefix;
-
-	update_clone_config_from_gitmodules(&suc.max_jobs);
-	git_config(git_update_clone_config, &suc.max_jobs);
-
-	argc = parse_options(argc, argv, prefix, module_update_clone_options,
-			     git_submodule_helper_usage, 0);
-
-	if (update)
-		if (parse_submodule_update_strategy(update, &suc.update) < 0)
-			die(_("bad value for update parameter"));
-
-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
-		return 1;
-
-	if (pathspec.nr)
-		suc.warn_if_uninitialized = 1;
-
-	return update_clone_submodules(&suc);
-}
-
-static int run_update_procedure(int argc, const char **argv, const char *prefix)
-{
-	int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
-	char *prefixed_path, *update = NULL;
-	struct update_data update_data = UPDATE_DATA_INIT;
-	struct string_list err = STRING_LIST_INIT_DUP;
-
-	struct option options[] = {
-		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
-		OPT__FORCE(&force, N_("force checkout updates"), 0),
-		OPT_BOOL('N', "no-fetch", &nofetch,
-			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &just_cloned,
-			 N_("overrides update mode in case the repository is a fresh clone")),
-		OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")),
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "update", &update,
-			   N_("string"),
-			   N_("rebase, merge, checkout or none")),
-		OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix, N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
-			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_CALLBACK_F(0, "suboid", &update_data.suboid, N_("subsha1"),
-			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_END()
-	};
-
-	const char *const usage[] = {
-		N_("git submodule--helper run-update-procedure [<options>] <path>"),
-		NULL
-	};
-
-	argc = parse_options(argc, argv, prefix, options, usage, 0);
-
-	if (argc != 1)
-		usage_with_options(usage, options);
-
-	update_data.force = !!force;
-	update_data.quiet = !!quiet;
-	update_data.nofetch = !!nofetch;
-	update_data.just_cloned = !!just_cloned;
-	update_data.sm_path = argv[0];
-
-	if (update_data.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
-	else
-		prefixed_path = xstrdup(update_data.sm_path);
-
-	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
-
-	determine_submodule_update_strategy(the_repository, update_data.just_cloned,
-					    update_data.sm_path, update,
-					    &update_data.update_strategy);
-
-	free(prefixed_path);
-
-	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data, &err);
-
-	return 3;
-}
-
-static int resolve_relative_path(int argc, const char **argv, const char *prefix)
-{
-	struct strbuf sb = STRBUF_INIT;
-	if (argc != 3)
-		die("submodule--helper relative-path takes exactly 2 arguments, got %d", argc);
-
-	printf("%s", relative_path(argv[1], argv[2], &sb));
-	strbuf_release(&sb);
-	return 0;
-}
-
 static const char *remote_submodule_branch(const char *path)
 {
 	const struct submodule *sub;
@@ -2852,19 +2638,6 @@ static void do_ensure_core_worktree(const char *path)
 	}
 }
 
-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
-{
-	const char *path;
-
-	if (argc != 2)
-		BUG("submodule--helper ensure-core-worktree <path>");
-
-	path = argv[1];
-	do_ensure_core_worktree(path);
-
-	return 0;
-}
-
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -3707,16 +3480,10 @@ static struct cmd_struct commands[] = {
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
 	{"update", module_update, 0},
-	{"update-module-mode", module_update_module_mode, 0},
-	{"update-clone", update_clone, 0},
-	{"run-update-procedure", run_update_procedure, 0},
-	{"ensure-core-worktree", ensure_core_worktree, 0},
-	{"relative-path", resolve_relative_path, 0},
 	{"resolve-relative-url-test", resolve_relative_url_test, 0},
 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
 	{"init", module_init, SUPPORT_SUPER_PREFIX},
 	{"status", module_status, SUPPORT_SUPER_PREFIX},
-	{"print-default-remote", print_default_remote, 0},
 	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
 	{"deinit", module_deinit, 0},
 	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 9/9] submodule--helper: rename helper functions
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
                       ` (7 preceding siblings ...)
  2021-10-13  5:18     ` [PATCH v3 8/9] submodule--helper: remove unused helpers Atharva Raykar
@ 2021-10-13  5:18     ` Atharva Raykar
  2021-10-14  0:05     ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Junio C Hamano
  9 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-13  5:18 UTC (permalink / raw)
  To: raykar.ath
  Cc: avarab, christian.couder, emilyshaffer, git, gitster, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

These two functions were prefixed with 'do' before the shell-to-C
conversion because they were utility functions meant to be called by
their non-prefixed counterpart.

Since those callers don't exist anymore, and these functions can now be
used directly, let's rename them to signal this fact.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
---
 builtin/submodule--helper.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0d6e65bd6c..82d68650e8 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2450,7 +2450,7 @@ static int run_update_command(struct update_data *ud, int subforce, struct strin
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud, struct string_list *err)
+static int run_update_procedure(struct update_data *ud, struct string_list *err)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2612,7 +2612,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
-static void do_ensure_core_worktree(const char *path)
+static void ensure_core_worktree(const char *path)
 {
 	const char *cw;
 	struct repository subrepo;
@@ -2871,7 +2871,7 @@ static int update_submodule(struct update_data *update_data)
 	char *prefixed_path;
 	struct string_list err = STRING_LIST_INIT_DUP;
 
-	do_ensure_core_worktree(update_data->sm_path);
+	ensure_core_worktree(update_data->sm_path);
 
 	if (update_data->recursive_prefix)
 		prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
@@ -2911,7 +2911,7 @@ static int update_submodule(struct update_data *update_data)
 	}
 
 	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
-		if (do_run_update_procedure(update_data, &err))
+		if (run_update_procedure(update_data, &err))
 			return 1;
 
 	if (update_data->recursive) {
-- 
2.32.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C
  2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
                       ` (8 preceding siblings ...)
  2021-10-13  5:18     ` [PATCH v3 9/9] submodule--helper: rename helper functions Atharva Raykar
@ 2021-10-14  0:05     ` Junio C Hamano
  2021-10-14 20:46       ` Emily Shaffer
  9 siblings, 1 reply; 56+ messages in thread
From: Junio C Hamano @ 2021-10-14  0:05 UTC (permalink / raw)
  To: Atharva Raykar
  Cc: avarab, christian.couder, emilyshaffer, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

Atharva Raykar <raykar.ath@gmail.com> writes:

> I have attempted to make a version of this series that is based on that topic [2],
> and added the superproject gitdir caching code in C [3]. It passes the tests,
> but I am not too confident about its correctness. I hope that branch can be
> helpful in some way.
>
> [1] https://lore.kernel.org/git/20210819200953.2105230-1-emilyshaffer@google.com/
> [2] https://github.com/tfidfwastaken/git/commits/submodule-update-on-es-superproject-aware
>     (fetch-it-via: git fetch https://github.com/tfidfwastaken/git submodule-update-on-es-superproject-aware)
> [3] https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930

The "C rewrite" of the code [3] that unconditionally sets of the
submodule.superprojectgitdir varible seems straightforward enough.

Emily, how solid do you think your "superproject aware submodule"
topic already is?  Would it be stable enough to build other things
on top, or is it a bit too premature?

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C
  2021-10-14  0:05     ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Junio C Hamano
@ 2021-10-14 20:46       ` Emily Shaffer
  0 siblings, 0 replies; 56+ messages in thread
From: Emily Shaffer @ 2021-10-14 20:46 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Atharva Raykar, avarab, christian.couder, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip

On Wed, Oct 13, 2021 at 05:05:58PM -0700, Junio C Hamano wrote:
> 
> Atharva Raykar <raykar.ath@gmail.com> writes:
> 
> > I have attempted to make a version of this series that is based on that topic [2],
> > and added the superproject gitdir caching code in C [3]. It passes the tests,
> > but I am not too confident about its correctness. I hope that branch can be
> > helpful in some way.
> >
> > [1] https://lore.kernel.org/git/20210819200953.2105230-1-emilyshaffer@google.com/
> > [2] https://github.com/tfidfwastaken/git/commits/submodule-update-on-es-superproject-aware
> >     (fetch-it-via: git fetch https://github.com/tfidfwastaken/git submodule-update-on-es-superproject-aware)
> > [3] https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930
> 
> The "C rewrite" of the code [3] that unconditionally sets of the
> submodule.superprojectgitdir varible seems straightforward enough.
> 
> Emily, how solid do you think your "superproject aware submodule"
> topic already is?  Would it be stable enough to build other things
> on top, or is it a bit too premature?

As of the version I sent today
(https://lore.kernel.org/git/20211014203416.2802639-1-emilyshaffer%40google.com)
I think it is stable enough to build on top of. There was general
consensus on the semantics of submodule.superprojectgitdir as it's sent
in v4.

 - Emily

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/13] submodule: convert the rest of 'update' to C
  2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
                   ` (14 preceding siblings ...)
  2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
@ 2021-10-14 21:50 ` Glen Choo
  2021-10-15  9:13   ` Atharva Raykar
  15 siblings, 1 reply; 56+ messages in thread
From: Glen Choo @ 2021-10-14 21:50 UTC (permalink / raw)
  To: Atharva Raykar, git

> This series builds upon the previous conversion work on 'submodule update' and
> moves out all of that shell logic in 'git-submodule.sh' into
> 'builtin/submodule--helper.c'.

Hey Atharva! I'm working on a series that will teach "git branch" how to
handle "--recurse-submodules". I plan to do this in-process because I
think this will take less overall effort than using child processes, and
to make it happen, I'm planning to add a helper function like
"for_each_submodule()", which would call a C callback function on each
submodule.

This is conceptually similar to "git submodule foreach" and
for_each_listed_submodule() (though not exactly equivalent), so I'm
reaching out to you in case this work is already on your radar. If so,
and if it is coming soon, it might be easier to for me to base my work
off yours instead of duplicating our efforts :)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/13] submodule: convert the rest of 'update' to C
  2021-10-14 21:50 ` [PATCH 00/13] " Glen Choo
@ 2021-10-15  9:13   ` Atharva Raykar
  0 siblings, 0 replies; 56+ messages in thread
From: Atharva Raykar @ 2021-10-15  9:13 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


Glen Choo <chooglen@google.com> writes:

>> This series builds upon the previous conversion work on 'submodule update' and
>> moves out all of that shell logic in 'git-submodule.sh' into
>> 'builtin/submodule--helper.c'.
>
> Hey Atharva! I'm working on a series that will teach "git branch" how to
> handle "--recurse-submodules". I plan to do this in-process because I
> think this will take less overall effort than using child processes, and
> to make it happen, I'm planning to add a helper function like
> "for_each_submodule()", which would call a C callback function on each
> submodule.
>
> This is conceptually similar to "git submodule foreach" and
> for_each_listed_submodule() (though not exactly equivalent), so I'm
> reaching out to you in case this work is already on your radar. If so,
> and if it is coming soon, it might be easier to for me to base my work
> off yours instead of duplicating our efforts :)

Thanks for reaching out. I don't have anything like this on my radar, so
feel free to go ahead with your plan :)

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2021-10-15  9:25 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-07 11:59 [PATCH 00/13] submodule: convert the rest of 'update' to C Atharva Raykar
2021-09-07 11:59 ` [PATCH 01/13] submodule--helper: split up ensure_core_worktree() Atharva Raykar
2021-09-07 11:59 ` [PATCH 02/13] submodule--helper: get remote names from any repository Atharva Raykar
2021-09-07 12:37   ` Ævar Arnfjörð Bjarmason
2021-09-07 13:33     ` Atharva Raykar
2021-09-07 11:59 ` [PATCH 03/13] submodule--helper: introduce get_default_remote_submodule() Atharva Raykar
2021-09-07 11:59 ` [PATCH 04/13] submodule--helper: rename helpers for update-clone Atharva Raykar
2021-09-07 11:59 ` [PATCH 05/13] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
2021-09-07 11:59 ` [PATCH 06/13] submodule: move core cmd_update() logic to C Atharva Raykar
2021-09-07 12:40   ` Ævar Arnfjörð Bjarmason
2021-09-07 11:59 ` [PATCH 07/13] submodule: remove fetch_in_submodule shell function Atharva Raykar
2021-09-07 12:44   ` Ævar Arnfjörð Bjarmason
2021-09-07 11:59 ` [PATCH 08/13] submodule--helper: remove update-clone subcommand Atharva Raykar
2021-09-07 12:46   ` Ævar Arnfjörð Bjarmason
2021-09-07 11:59 ` [PATCH 09/13] submodule--helper: remove update-module-mode subcommand Atharva Raykar
2021-09-07 12:49   ` Ævar Arnfjörð Bjarmason
2021-09-07 13:50     ` Atharva Raykar
2021-09-07 11:59 ` [PATCH 10/13] submodule--helper: remove shell interface to ensure_core_worktree() Atharva Raykar
2021-09-07 11:59 ` [PATCH 11/13] submodule--helper: remove print-default-remote subcommand Atharva Raykar
2021-09-07 11:59 ` [PATCH 12/13] submodule--helper: remove relative-path subcommand Atharva Raykar
2021-09-07 11:59 ` [PATCH 13/13] submodule--helper: remove run-update-procedure subcommand Atharva Raykar
2021-09-07 12:34 ` [PATCH 00/13] submodule: convert the rest of 'update' to C Ævar Arnfjörð Bjarmason
2021-09-07 12:53   ` Atharva Raykar
2021-09-16 10:32 ` [PATCH v2 0/8] " Atharva Raykar
2021-09-16 10:32   ` [PATCH v2 1/8] submodule--helper: split up ensure_core_worktree() Atharva Raykar
2021-09-16 10:32   ` [PATCH v2 2/8] submodule--helper: get remote names from any repository Atharva Raykar
2021-09-20 16:52     ` Junio C Hamano
2021-10-03 13:22       ` Atharva Raykar
2021-09-20 21:28     ` Junio C Hamano
2021-09-21 16:33       ` Jonathan Tan
2021-09-16 10:32   ` [PATCH v2 3/8] submodule--helper: rename helpers for update-clone Atharva Raykar
2021-09-16 10:32   ` [PATCH v2 4/8] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
2021-09-16 10:32   ` [PATCH v2 5/8] submodule: move core cmd_update() logic to C Atharva Raykar
2021-09-20 17:13     ` Junio C Hamano
2021-10-03 10:38       ` Atharva Raykar
2021-09-20 19:58     ` Junio C Hamano
2021-09-20 21:28     ` Junio C Hamano
2021-09-16 10:32   ` [PATCH v2 6/8] submodule--helper: remove update-clone subcommand Atharva Raykar
2021-09-16 10:32   ` [PATCH v2 7/8] submodule--helper: remove unused helpers Atharva Raykar
2021-09-20 17:19     ` Junio C Hamano
2021-09-16 10:32   ` [PATCH v2 8/8] submodule--helper: rename helper functions Atharva Raykar
2021-09-20 17:19     ` Junio C Hamano
2021-10-13  5:17   ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Atharva Raykar
2021-10-13  5:17     ` [PATCH v3 1/9] submodule--helper: split up ensure_core_worktree() Atharva Raykar
2021-10-13  5:17     ` [PATCH v3 2/9] submodule--helper: get remote names from any repository Atharva Raykar
2021-10-13  5:17     ` [PATCH v3 3/9] submodule--helper: rename helpers for update-clone Atharva Raykar
2021-10-13  5:18     ` [PATCH v3 4/9] submodule--helper: refactor get_submodule_displaypath() Atharva Raykar
2021-10-13  5:18     ` [PATCH v3 5/9] submodule--helper: allow setting superprefix for init_submodule() Atharva Raykar
2021-10-13  5:18     ` [PATCH v3 6/9] submodule--helper: run update using child process struct Atharva Raykar
2021-10-13  5:18     ` [PATCH v3 7/9] submodule: move core cmd_update() logic to C Atharva Raykar
2021-10-13  5:18     ` [PATCH v3 8/9] submodule--helper: remove unused helpers Atharva Raykar
2021-10-13  5:18     ` [PATCH v3 9/9] submodule--helper: rename helper functions Atharva Raykar
2021-10-14  0:05     ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Junio C Hamano
2021-10-14 20:46       ` Emily Shaffer
2021-10-14 21:50 ` [PATCH 00/13] " Glen Choo
2021-10-15  9:13   ` Atharva Raykar

Code repositories for project(s) associated with this inbox:

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).