git@vger.kernel.org mailing list mirror (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; 142+ 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] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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 related	[flat|nested] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ 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
                       ` (10 more replies)
  8 siblings, 11 replies; 142+ 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] 142+ 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
                       ` (9 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
                       ` (8 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
                       ` (7 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
                       ` (6 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
                       ` (5 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
                       ` (4 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
                       ` (3 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
                       ` (2 subsequent siblings)
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
  10 siblings, 0 replies; 142+ 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 related	[flat|nested] 142+ 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
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
  10 siblings, 1 reply; 142+ 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] 142+ 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
  2021-12-03 19:00         ` Junio C Hamano
  0 siblings, 1 reply; 142+ 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] 142+ 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; 142+ 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] 142+ 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; 142+ 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] 142+ messages in thread

* Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C
  2021-10-14 20:46       ` Emily Shaffer
@ 2021-12-03 19:00         ` Junio C Hamano
  2021-12-03 20:15           ` Ævar Arnfjörð Bjarmason
  2021-12-04 10:38           ` Atharva Raykar
  0 siblings, 2 replies; 142+ messages in thread
From: Junio C Hamano @ 2021-12-03 19:00 UTC (permalink / raw)
  To: Atharva Raykar, Emily Shaffer
  Cc: avarab, christian.couder, git, jrnieder, kaartic.sivaraam,
	pc44800, periperidip

Emily Shaffer <emilyshaffer@google.com> writes:

> 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.
>> ..
>> 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.

Does the above statement still hold true today?

And more importantly, Atharva, are you on board with the plan Emily
suggested to have this one built on top of her series?

Thanks.

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

* Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C
  2021-12-03 19:00         ` Junio C Hamano
@ 2021-12-03 20:15           ` Ævar Arnfjörð Bjarmason
  2021-12-04 10:38           ` Atharva Raykar
  1 sibling, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-03 20:15 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Atharva Raykar, Emily Shaffer, christian.couder, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


On Fri, Dec 03 2021, Junio C Hamano wrote:

> Emily Shaffer <emilyshaffer@google.com> writes:
>
>> 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.
>>> ..
>>> 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.
>
> Does the above statement still hold true today?
>
> And more importantly, Atharva, are you on board with the plan Emily
> suggested to have this one built on top of her series?

I think the current state of it is that Emily & I were having a
discussion about the semantics of that series. See [1] and [2].

That's still outstanding. I.e. I haven't been able to reproduce cases
where we actually need this caching for performance reasons (which is
the reason it exists), but even if we end up keeping it I'd think we'd
want something picked from the RFC patches I sent[1] to test the
"caching" v.s. "non-caching" behavior, and assert that they're the same.

1. https://lore.kernel.org/git/RFC-cover-0.2-00000000000-20211117T113134Z-avarab@gmail.com/
2. https://lore.kernel.org/git/211124.86a6hue2wk.gmgdl@evledraar.gmail.com/

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

* Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C
  2021-12-03 19:00         ` Junio C Hamano
  2021-12-03 20:15           ` Ævar Arnfjörð Bjarmason
@ 2021-12-04 10:38           ` Atharva Raykar
  1 sibling, 0 replies; 142+ messages in thread
From: Atharva Raykar @ 2021-12-04 10:38 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Emily Shaffer, avarab, christian.couder, git, jrnieder,
	kaartic.sivaraam, pc44800, periperidip


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

> Emily Shaffer <emilyshaffer@google.com> writes:
>
>> 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.
>>> ..
>>> 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.
>
> Does the above statement still hold true today?
>
> And more importantly, Atharva, are you on board with the plan Emily
> suggested to have this one built on top of her series?

Yes, I am on board with that. I have not been closely following their
series, but the places where it clashes with this series are minimal,
and look quite easy to port later to C. So I'm totally fine with it.

> Thanks.

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

* [PATCH v4 0/7] 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
                       ` (9 preceding siblings ...)
  2021-10-14  0:05     ` [PATCH v3 0/9] submodule: convert the rest of 'update' to C Junio C Hamano
@ 2022-01-27 16:22     ` Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 1/7] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
                         ` (7 more replies)
  10 siblings, 8 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

This series rewrites "git submodule update" in C. It's a rebased and
re-rolled version of v3[1] submitted back in October. Per [2] the
author doesn't have time to push it forward now.

There was discussion in the thread at [2] about the interaction
between this and es/superproject-aware-submodules.

Per [3] I think it would be better to get this in first, as the big
outstanding question about the superproject aware submodules[3] was
whether it was an optimization or not. It's currently an optimization,
but whether it's needed is muddied by "git-submodule.sh" being a
shellscript and invoking "git rev-parse" in a loop, which a version
rebased on this could do in C.

Per the v3 CL of this series[1] there is a C version of the required
code for es/superproject-aware-submodules, but when I tried to rebase
it it failed because it's based on an older version of
es/superproject-aware-submodules which linked to the .git dir rather
than the working tree.

I.e. the C code[4] produces "../.git" in the tests, but we're
expecting "../..". I couldn't find the right API to get that path from
path.c et al, but it's presumably easy for someone more familiar with
it.

As for changes in this v4:

 * Rebased on master, it didn't compile due to my changes to the
   refs_resolve_ref_unsafe() API.

 * There was some back & forth about large patches v.s. split-up
   commits in previous iterations. This version squashes several
   patches together, because I thought a rename/add/removal of code
   that's all related (and really can only be done as one logical step
   without a major rewrite) was easier to look at than having to jump
   back and forth in the series.

   The resulting diff is large, but I think it's better than looking
   at it piecemeal. You can see what new code replaces what old code.

 * There's new formatting-only changes in [56]/7 that I added to make
   the 7/7 diff a tad smaller.

   The gitster/ar/submodule-update~3..gitster/ar/submodule-update diff
   (the real meat of the series) is "402 insertions(+), 422
   deletions(-)", and 7/7 here is "389 insertions(+), 418
   deletions(-)".

   So it's not much, but thaht churn before 7/7 makes the big change a
   bit logical change at the end easier to reason about.

 * I fixed a strbuf and string_list memory leak in the new code, and
   simplified one codepath that freed correctly, but could use a "goto
   cleanup" pattern to do away with duplication.

   There's still a *lot* of memory leaks in
   builtin/submodule--helper.c, but they're all (well, to the extent
   that I can extract signal from the noise) in existing code, or in
   generic APIs that uses which leak.

1. https://lore.kernel.org/git/20211013051805.45662-1-raykar.ath@gmail.com/
2. https://lore.kernel.org/git/CADi-XoThCqfvPnBd0p6yAhrtotK_3z2pQQMugWPsYpHLbXge7w@mail.gmail.com/
3. https://lore.kernel.org/git/211203.86o85xqw7o.gmgdl@evledraar.gmail.com/
4. https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930

Atharva Raykar (6):
  submodule--helper: get remote names from any repository
  submodule--helper: refactor get_submodule_displaypath()
  submodule--helper: allow setting superprefix for init_submodule()
  submodule--helper: run update using child process struct
  builtin/submodule--helper.c: reformat designated initializers
  submodule: move core cmd_update() logic to C

Ævar Arnfjörð Bjarmason (1):
  builtin/submodule--helper.c: rename "suc" variable to "opt"

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

Range-diff against v3:
 1:  775f7c01ddb <  -:  ----------- submodule--helper: split up ensure_core_worktree()
 2:  fe3d30c1160 !  1:  1a0b1323cd7 submodule--helper: get remote names from any repository
    @@ Commit message
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
         Signed-off-by: Junio C Hamano <gitster@pobox.com>
    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/submodule--helper.c ##
     @@
    @@ builtin/submodule--helper.c: static char *get_default_remote(void)
     +{
     +	const char *refname;
     +	struct repository subrepo;
    ++	int ignore_errno;
     +
     +	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
    -+					  "HEAD", 0, NULL, NULL);
    ++					  "HEAD", 0, NULL, NULL,
    ++					  &ignore_errno);
     +	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
     +	return repo_get_default_remote(&subrepo, refname);
     +}
 3:  8085571a7cb <  -:  ----------- submodule--helper: rename helpers for update-clone
 4:  18c551543ed !  2:  7e2df3ff220 submodule--helper: refactor get_submodule_displaypath()
    @@ Commit message
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
         Signed-off-by: Junio C Hamano <gitster@pobox.com>
    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/submodule--helper.c ##
     @@ builtin/submodule--helper.c: static int resolve_relative_url_test(int argc, const char **argv, const char *pr
 5:  2be0453750a !  3:  f31fd72fba2 submodule--helper: allow setting superprefix for init_submodule()
    @@ Commit message
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
         Signed-off-by: Junio C Hamano <gitster@pobox.com>
    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/submodule--helper.c ##
     @@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **argv, const char *prefix)
    @@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **ar
     +	const char *superprefix;
      	unsigned int flags;
      };
    --#define INIT_CB_INIT { NULL, 0 }
    -+#define INIT_CB_INIT { 0 }
    + #define INIT_CB_INIT { 0 }
      
      static void init_submodule(const char *path, const char *prefix,
     -			   unsigned int flags)
 6:  a882b53177d !  4:  76c5a826a80 submodule--helper: run update using child process struct
    @@ Commit message
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
         Signed-off-by: Junio C Hamano <gitster@pobox.com>
    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/submodule--helper.c ##
     @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
 -:  ----------- >  5:  29aa2fc0851 builtin/submodule--helper.c: reformat designated initializers
 -:  ----------- >  6:  d3ad6e7a351 builtin/submodule--helper.c: rename "suc" variable to "opt"
 7:  3092469f380 !  7:  02954603763 submodule: move core cmd_update() logic to C
    @@ Commit message
         `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.
    +    We also introduce `update_submodules2()` and `update_submodule2()`
    +    which will supersede `update_submodules()` and `update_submodule()`.
     
         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,
    @@ Commit message
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
         Signed-off-by: Junio C Hamano <gitster@pobox.com>
    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/submodule--helper.c ##
    +@@ builtin/submodule--helper.c: 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]);
    +@@ 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: struct submodule_update_clone {
      	const char *prefix;
      	int single_branch;
    @@ builtin/submodule--helper.c: struct submodule_update_clone {
      	const char *displaypath;
      	struct object_id oid;
      	struct object_id suboid;
    --	struct submodule_update_strategy update_strategy;
    + 	struct submodule_update_strategy update_strategy;
     +	int max_jobs;
      	int depth;
    +-	unsigned int force: 1;
    +-	unsigned int quiet: 1;
    +-	unsigned int nofetch: 1;
    +-	unsigned int just_cloned: 1;
     +	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;
    ++	unsigned int init;
    ++	unsigned int force;
    ++	unsigned int quiet;
    ++	unsigned int nofetch;
    ++	unsigned int remote;
    ++	unsigned int recursive;
    ++	unsigned int progress;
    ++	unsigned int dissociate;
    ++	unsigned int require_init;
    ++	unsigned warn_if_uninitialized ;
    ++	unsigned int just_cloned ;
     +	struct string_list references;
     +	struct module_list list;
      };
    --#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
    -+#define UPDATE_DATA_INIT { \
    + #define UPDATE_DATA_INIT { \
     +	.list = MODULE_LIST_INIT, \
    -+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
    + 	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
     +	.recommend_shallow = -1, \
     +	.references = STRING_LIST_INIT_DUP, \
     +	.single_branch = -1, \
    @@ builtin/submodule--helper.c: struct submodule_update_clone {
     +		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)
     @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
      	return run_command(&cp);
      }
    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u
     +		}
     +
     +		/* the command failed, but update must continue */
    -+		string_list_append(err, out.buf);
    ++		string_list_append_nodup(err, strbuf_detach(&out, NULL));
     +		return 1;
     +	}
     +
    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u
     -		    submodule_strategy_to_string(&ud->update_strategy));
      	}
      
    ++	strbuf_release(&out);
      	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)
    ++static int run_update_procedure(struct update_data *ud, struct string_list *err)
      {
      	int subforce = is_null_oid(&ud->suboid) || ud->force;
      
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
      	}
      
     -	return run_update_command(ud, subforce);
    +-}
    +-
    +-static void update_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_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_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 opt = 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", &opt.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", &opt.references, N_("repo"),
    +-			   N_("reference repository")),
    +-		OPT_BOOL(0, "dissociate", &opt.dissociate,
    +-			   N_("use --reference only while cloning")),
    +-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
    +-			   N_("create a shallow clone truncated to the "
    +-			      "specified number of revisions")),
    +-		OPT_INTEGER('j', "jobs", &opt.max_jobs,
    +-			    N_("parallel jobs")),
    +-		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
    +-			    N_("whether the initial clone should follow the shallow recommendation")),
    +-		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
    +-		OPT_BOOL(0, "progress", &opt.progress,
    +-			    N_("force cloning progress")),
    +-		OPT_BOOL(0, "require-init", &opt.require_init,
    +-			   N_("disallow cloning into non-empty directory")),
    +-		OPT_BOOL(0, "single-branch", &opt.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
    +-	};
    +-	opt.prefix = prefix;
    +-
    +-	update_clone_config_from_gitmodules(&opt.max_jobs);
    +-	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
    +-			die(_("bad value for update parameter"));
    +-
    +-	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
    +-		return 1;
    +-
    +-	if (pathspec.nr)
    +-		opt.warn_if_uninitialized = 1;
    +-
    +-	return update_submodules(&opt);
    +-}
    +-
    +-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 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);
    +-
    +-	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;
     +	return run_update_command(ud, subforce, err);
      }
      
    - static void update_clone_submodule(struct update_clone_data *ucd)
    -@@ builtin/submodule--helper.c: 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;
    + static const char *remote_submodule_branch(const char *path)
    +@@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv, const char *prefix)
    + 	return 0;
    + }
      
    - 	struct option options[] = {
    - 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
    -@@ builtin/submodule--helper.c: static int run_update_procedure(int argc, const char **argv, const char *prefix)
    - 	free(prefixed_path);
    +-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
    ++static void ensure_core_worktree(const char *path)
    + {
    +-	const char *path;
    + 	const char *cw;
    + 	struct repository subrepo;
      
    - 	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);
    +-	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);
      
    - 	return 3;
    +@@ builtin/submodule--helper.c: static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
    + 		free(abs_path);
    + 		strbuf_release(&sb);
    + 	}
    +-
    +-	return 0;
      }
    + 
    + static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
     @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char **argv, const char *prefix)
      	return !!ret;
      }
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +	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,
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +		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,
    ++			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);
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +	}
     +
     +	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) {
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +		struct string_list_item *item;
     +		for_each_string_list_item(item, &err)
     +			fputs(item->string, stderr);
    ++		string_list_clear(&err, 0);
     +		return 1;
     +	}
     +
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +	 * - the listener can avoid doing any work if fetching failed.
     +	 */
     +	if (suc.quickstop) {
    -+		string_list_clear(&update_data->references, 0);
    -+		return 1;
    ++		res = 1;
    ++		goto cleanup;
     +	}
     +
     +	for (i = 0; i < suc.update_clone_nr; i++) {
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +			res = 1;
     +	}
     +
    ++cleanup:
     +	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 update_data opt = UPDATE_DATA_INIT;
     +
     +	struct option module_update_clone_options[] = {
    -+		OPT__FORCE(&force, N_("force checkout updates"), 0),
    -+		OPT_BOOL(0, "init", &init,
    ++		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
    ++		OPT_BOOL(0, "init", &opt.init,
     +			 N_("initialize uninitialized submodules before update")),
    -+		OPT_BOOL(0, "remote", &remote,
    ++		OPT_BOOL(0, "remote", &opt.remote,
     +			 N_("use SHA-1 of submodule's remote tracking branch")),
    -+		OPT_BOOL(0, "recursive", &recursive,
    ++		OPT_BOOL(0, "recursive", &opt.recursive,
     +			 N_("traverse submodules recursively")),
    -+		OPT_BOOL('N', "no-fetch", &nofetch,
    ++		OPT_BOOL('N', "no-fetch", &opt.nofetch,
     +			 N_("don't fetch new objects from the remote site")),
    -+		OPT_STRING(0, "prefix", &prefix,
    ++		OPT_STRING(0, "prefix", &opt.prefix,
     +			   N_("path"),
     +			   N_("path into the working tree")),
    -+		OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix,
    ++		OPT_STRING(0, "recursive-prefix", &opt.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"),
    ++		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
     +				N_("reference repository")),
    -+		OPT_BOOL(0, "dissociate", &dissociate,
    ++		OPT_BOOL(0, "dissociate", &opt.dissociate,
     +			 N_("use --reference only while cloning")),
    -+		OPT_INTEGER(0, "depth", &update_data.depth,
    ++		OPT_INTEGER(0, "depth", &opt.depth,
     +			    N_("create a shallow clone truncated to the "
     +			       "specified number of revisions")),
    -+		OPT_INTEGER('j', "jobs", &update_data.max_jobs,
    ++		OPT_INTEGER('j', "jobs", &opt.max_jobs,
     +			    N_("parallel jobs")),
    -+		OPT_BOOL(0, "recommend-shallow", &update_data.recommend_shallow,
    ++		OPT_BOOL(0, "recommend-shallow", &opt.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,
    ++		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
    ++		OPT_BOOL(0, "progress", &opt.progress,
     +			 N_("force cloning progress")),
    -+		OPT_BOOL(0, "require-init", &require_init,
    ++		OPT_BOOL(0, "require-init", &opt.require_init,
     +			 N_("disallow cloning into non-empty directory")),
    -+		OPT_BOOL(0, "single-branch", &update_data.single_branch,
    ++		OPT_BOOL(0, "single-branch", &opt.single_branch,
     +			 N_("clone only one branch, HEAD or --branch")),
     +		OPT_END()
     +	};
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +		NULL
     +	};
     +
    -+	update_clone_config_from_gitmodules(&update_data.max_jobs);
    -+	git_config(git_update_clone_config, &update_data.max_jobs);
    ++	update_clone_config_from_gitmodules(&opt.max_jobs);
    ++	git_config(git_update_clone_config, &opt.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());
    ++	oidcpy(&opt.oid, null_oid());
    ++	oidcpy(&opt.suboid, null_oid());
     +
     +	if (update)
     +		if (parse_submodule_update_strategy(update,
    -+						    &update_data.update_strategy) < 0)
    ++						    &opt.update_strategy) < 0)
     +			die(_("bad value for update parameter"));
     +
    -+	if (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)
    ++	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
     +		return 1;
     +
     +	if (pathspec.nr)
    -+		update_data.warn_if_uninitialized = 1;
    ++		opt.warn_if_uninitialized = 1;
     +
    -+	if (update_data.init) {
    ++	if (opt.init) {
     +		struct module_list list = MODULE_LIST_INIT;
     +		struct init_cb info = INIT_CB_INIT;
     +
    -+		if (module_list_compute(argc, argv, update_data.prefix,
    ++		if (module_list_compute(argc, argv, opt.prefix,
     +					&pathspec, &list) < 0)
     +			return 1;
     +
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +		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.prefix = opt.prefix;
    ++		info.superprefix = opt.recursive_prefix;
    ++		if (opt.quiet)
     +			info.flags |= OPT_QUIET;
     +
     +		for_each_listed_submodule(&list, init_submodule_cb, &info);
     +	}
     +
    -+	return update_submodules(&update_data);
    ++	return update_submodules(&opt);
     +}
     +
      struct add_data {
      	const char *prefix;
      	const char *branch;
    -@@ builtin/submodule--helper.c: static int module_add(int argc, const char **argv, const char *prefix)
    - 	return 0;
    - }
    - 
    -+
    - #define SUPPORT_SUPER_PREFIX (1<<0)
    - 
    - struct cmd_struct {
     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {
      	{"name", module_name, 0},
      	{"clone", module_clone, 0},
      	{"add", module_add, SUPPORT_SUPER_PREFIX},
    +-	{"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},
     +	{"update", module_update, 0},
    - 	{"update-module-mode", module_update_module_mode, 0},
    - 	{"update-clone", update_clone, 0},
    - 	{"run-update-procedure", run_update_procedure, 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},
     
      ## git-submodule.sh ##
     @@ git-submodule.sh: cmd_deinit()
 8:  cee4beb7abe <  -:  ----------- submodule--helper: remove unused helpers
 9:  2194c1729f1 <  -:  ----------- submodule--helper: rename helper functions
-- 
2.35.0.894.g563b84683b9


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

* [PATCH v4 1/7] submodule--helper: get remote names from any repository
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
@ 2022-01-27 16:22       ` Ævar Arnfjörð Bjarmason
  2022-01-27 18:45         ` Glen Choo
  2022-01-27 16:22       ` [PATCH v4 2/7] submodule--helper: refactor get_submodule_displaypath() Ævar Arnfjörð Bjarmason
                         ` (6 subsequent siblings)
  7 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

`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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 41 +++++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c5d3fc3817f..965260edb22 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;
+	struct repository subrepo;
+	int ignore_errno;
+
+	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
+					  "HEAD", 0, NULL, NULL,
+					  &ignore_errno);
+	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 +1359,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 +1399,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.35.0.894.g563b84683b9


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

* [PATCH v4 2/7] submodule--helper: refactor get_submodule_displaypath()
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 1/7] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
@ 2022-01-27 16:22       ` Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 3/7] submodule--helper: allow setting superprefix for init_submodule() Ævar Arnfjörð Bjarmason
                         ` (5 subsequent siblings)
  7 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@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 965260edb22..d38a64c7b7d 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -263,11 +263,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);
@@ -283,6 +280,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.35.0.894.g563b84683b9


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

* [PATCH v4 3/7] submodule--helper: allow setting superprefix for init_submodule()
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 1/7] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 2/7] submodule--helper: refactor get_submodule_displaypath() Ævar Arnfjörð Bjarmason
@ 2022-01-27 16:22       ` Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 4/7] submodule--helper: run update using child process struct Ævar Arnfjörð Bjarmason
                         ` (4 subsequent siblings)
  7 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index d38a64c7b7d..f8e18820ace 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -608,18 +608,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 { 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);
 
@@ -693,7 +697,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.35.0.894.g563b84683b9


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

* [PATCH v4 4/7] submodule--helper: run update using child process struct
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
                         ` (2 preceding siblings ...)
  2022-01-27 16:22       ` [PATCH v4 3/7] submodule--helper: allow setting superprefix for init_submodule() Ævar Arnfjörð Bjarmason
@ 2022-01-27 16:22       ` Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 5/7] builtin/submodule--helper.c: reformat designated initializers Ævar Arnfjörð Bjarmason
                         ` (3 subsequent siblings)
  7 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@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 f8e18820ace..328c6cc87cd 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2346,47 +2346,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.35.0.894.g563b84683b9


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

* [PATCH v4 5/7] builtin/submodule--helper.c: reformat designated initializers
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
                         ` (3 preceding siblings ...)
  2022-01-27 16:22       ` [PATCH v4 4/7] submodule--helper: run update using child process struct Ævar Arnfjörð Bjarmason
@ 2022-01-27 16:22       ` Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 6/7] builtin/submodule--helper.c: rename "suc" variable to "opt" Ævar Arnfjörð Bjarmason
                         ` (2 subsequent siblings)
  7 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

The second hunk here will make a subsequent commit's diff smaller, and
let's do the first and third hunks while we're at it so that we
consistently format all of these.

Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 328c6cc87cd..1553b318cc7 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1656,7 +1656,10 @@ struct module_clone_data {
 	unsigned int require_init: 1;
 	int single_branch;
 };
-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
+#define MODULE_CLONE_DATA_INIT { \
+	.reference = STRING_LIST_INIT_NODUP, \
+	.single_branch = -1, \
+}
 
 struct submodule_alternate_setup {
 	const char *submodule_name;
@@ -2049,7 +2052,9 @@ struct update_data {
 	unsigned int nofetch: 1;
 	unsigned int just_cloned: 1;
 };
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+}
 
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
 		struct strbuf *out, const char *displaypath)
@@ -3015,7 +3020,9 @@ struct add_data {
 	unsigned int progress: 1;
 	unsigned int dissociate: 1;
 };
-#define ADD_DATA_INIT { .depth = -1 }
+#define ADD_DATA_INIT { \
+	.depth = -1, \
+}
 
 static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
 {
-- 
2.35.0.894.g563b84683b9


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

* [PATCH v4 6/7] builtin/submodule--helper.c: rename "suc" variable to "opt"
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
                         ` (4 preceding siblings ...)
  2022-01-27 16:22       ` [PATCH v4 5/7] builtin/submodule--helper.c: reformat designated initializers Ævar Arnfjörð Bjarmason
@ 2022-01-27 16:22       ` Ævar Arnfjörð Bjarmason
  2022-01-27 16:22       ` [PATCH v4 7/7] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
  7 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

Rename the "suc" variable in "builtin/submodule--helper.c" to
"opt". The only reason for this change is to make the subsequent
commit's diff smaller, by doing this rename we can "anchor" the diff
better, as it "borrow" most of the options declared here as-is as far
as the diff rename detection is concerned.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1553b318cc7..a96976b1772 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2519,36 +2519,36 @@ 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 submodule_update_clone opt = 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,
+		OPT_STRING(0, "recursive-prefix", &opt.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"),
+		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
 			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &suc.dissociate,
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
 			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
+		OPT_STRING(0, "depth", &opt.depth, "<depth>",
 			   N_("create a shallow clone truncated to the "
 			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
 			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
+		OPT_BOOL(0, "recommend-shallow", &opt.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,
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
 			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &suc.require_init,
+		OPT_BOOL(0, "require-init", &opt.require_init,
 			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &suc.single_branch,
+		OPT_BOOL(0, "single-branch", &opt.single_branch,
 			 N_("clone only one branch, HEAD or --branch")),
 		OPT_END()
 	};
@@ -2557,25 +2557,25 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
 		NULL
 	};
-	suc.prefix = prefix;
+	opt.prefix = prefix;
 
-	update_clone_config_from_gitmodules(&suc.max_jobs);
-	git_config(git_update_clone_config, &suc.max_jobs);
+	update_clone_config_from_gitmodules(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.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)
+		if (parse_submodule_update_strategy(update, &opt.update) < 0)
 			die(_("bad value for update parameter"));
 
-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
 		return 1;
 
 	if (pathspec.nr)
-		suc.warn_if_uninitialized = 1;
+		opt.warn_if_uninitialized = 1;
 
-	return update_submodules(&suc);
+	return update_submodules(&opt);
 }
 
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
-- 
2.35.0.894.g563b84683b9


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

* [PATCH v4 7/7] submodule: move core cmd_update() logic to C
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
                         ` (5 preceding siblings ...)
  2022-01-27 16:22       ` [PATCH v4 6/7] builtin/submodule--helper.c: rename "suc" variable to "opt" Ævar Arnfjörð Bjarmason
@ 2022-01-27 16:22       ` Ævar Arnfjörð Bjarmason
  2022-01-27 21:55         ` Glen Choo
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
  7 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-27 16:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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_submodules2()` and `update_submodule2()`
which will supersede `update_submodules()` and `update_submodule()`.

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 662 ++++++++++++++++++++----------------
 git-submodule.sh            | 145 +-------
 2 files changed, 389 insertions(+), 418 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a96976b1772..916df6d9947 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]);
@@ -1967,29 +1952,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;
@@ -2017,7 +1979,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;
 
@@ -2040,20 +2001,62 @@ 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;
-	unsigned int force: 1;
-	unsigned int quiet: 1;
-	unsigned int nofetch: 1;
-	unsigned int just_cloned: 1;
+	int recommend_shallow;
+	int single_branch;
+	unsigned int init;
+	unsigned int force;
+	unsigned int quiet;
+	unsigned int nofetch;
+	unsigned int remote;
+	unsigned int recursive;
+	unsigned int progress;
+	unsigned int dissociate;
+	unsigned int require_init;
+	unsigned warn_if_uninitialized ;
+	unsigned int just_cloned ;
+	struct string_list references;
+	struct module_list list;
 };
 #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,
@@ -2349,13 +2352,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);
@@ -2378,80 +2389,76 @@ 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) {
+	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));
+			}
+		}
+
+		/* the command failed, but update must continue */
+		string_list_append_nodup(err, strbuf_detach(&out, NULL));
+		return 1;
+	}
+
+	if (!ud->quiet) {
+		switch (strategy.type) {
 		case SM_UPDATE_CHECKOUT:
-			printf(_("Unable to checkout '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
+			printf(_("Submodule path '%s': checked out '%s'\n"),
+			       ud->displaypath, oid);
 			break;
 		case SM_UPDATE_REBASE:
-			printf(_("Unable to rebase '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
+			printf(_("Submodule path '%s': rebased into '%s'\n"),
+			       ud->displaypath, oid);
 			break;
 		case SM_UPDATE_MERGE:
-			printf(_("Unable to merge '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
+			printf(_("Submodule path '%s': merged in '%s'\n"),
+			       ud->displaypath, oid);
 			break;
 		case SM_UPDATE_COMMAND:
-			printf(_("Execution of '%s %s' failed in submodule path '%s'"),
-			       ud->update_strategy.command, oid, ud->displaypath);
+			printf(_("Submodule path '%s': '%s %s'\n"),
+			       ud->displaypath, strategy.command, oid);
 			break;
 		default:
 			BUG("unexpected update strategy type: %s",
-			    submodule_strategy_to_string(&ud->update_strategy));
+			    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
-		 */
-		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));
 	}
 
+	strbuf_release(&out);
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud)
+static int run_update_procedure(struct update_data *ud, struct string_list *err)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2478,182 +2485,7 @@ static int do_run_update_procedure(struct update_data *ud)
 			    ud->displaypath, oid_to_hex(&ud->oid));
 	}
 
-	return run_update_command(ud, subforce);
-}
-
-static void update_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_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_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 opt = 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", &opt.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", &opt.references, N_("repo"),
-			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &opt.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &opt.max_jobs,
-			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
-		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
-		OPT_BOOL(0, "progress", &opt.progress,
-			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &opt.require_init,
-			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &opt.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
-	};
-	opt.prefix = prefix;
-
-	update_clone_config_from_gitmodules(&opt.max_jobs);
-	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
-			die(_("bad value for update parameter"));
-
-	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
-		return 1;
-
-	if (pathspec.nr)
-		opt.warn_if_uninitialized = 1;
-
-	return update_submodules(&opt);
-}
-
-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 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);
-
-	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;
+	return run_update_command(ud, subforce, err);
 }
 
 static const char *remote_submodule_branch(const char *path)
@@ -2788,17 +2620,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 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);
 
@@ -2818,8 +2644,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 		free(abs_path);
 		strbuf_release(&sb);
 	}
-
-	return 0;
 }
 
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
@@ -3006,6 +2830,279 @@ 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;
+
+	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 (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);
+		string_list_clear(&err, 0);
+		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) {
+		res = 1;
+		goto cleanup;
+	}
+
+	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;
+	}
+
+cleanup:
+	string_list_clear(&update_data->references, 0);
+	return res;
+}
+
+static int module_update(int argc, const char **argv, const char *prefix)
+{
+	const char *update = NULL;
+	struct pathspec pathspec;
+	struct update_data opt = UPDATE_DATA_INIT;
+
+	struct option module_update_clone_options[] = {
+		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
+		OPT_BOOL(0, "init", &opt.init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_BOOL(0, "remote", &opt.remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &opt.recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_STRING(0, "prefix", &opt.prefix,
+			   N_("path"),
+			   N_("path into the working tree")),
+		OPT_STRING(0, "recursive-prefix", &opt.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", &opt.references, N_("repo"),
+				N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
+			 N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &opt.depth,
+			    N_("create a shallow clone truncated to the "
+			       "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
+			 N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
+			 N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &opt.require_init,
+			 N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &opt.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(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.max_jobs);
+
+	argc = parse_options(argc, argv, prefix, module_update_clone_options,
+			     git_submodule_helper_usage, 0);
+	oidcpy(&opt.oid, null_oid());
+	oidcpy(&opt.suboid, null_oid());
+
+	if (update)
+		if (parse_submodule_update_strategy(update,
+						    &opt.update_strategy) < 0)
+			die(_("bad value for update parameter"));
+
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
+		return 1;
+
+	if (pathspec.nr)
+		opt.warn_if_uninitialized = 1;
+
+	if (opt.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
+		info.superprefix = opt.recursive_prefix;
+		if (opt.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
+	return update_submodules(&opt);
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
@@ -3393,16 +3490,11 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
-	{"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},
+	{"update", module_update, 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},
diff --git a/git-submodule.sh b/git-submodule.sh
index 652861aa66a..bcd8b92aabd 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.35.0.894.g563b84683b9


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

* Re: [PATCH v4 1/7] submodule--helper: get remote names from any repository
  2022-01-27 16:22       ` [PATCH v4 1/7] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
@ 2022-01-27 18:45         ` Glen Choo
  0 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-01-27 18:45 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

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

This wasn't introduced by you (it was introduced in v1 [1]), but I think
it's worth pointing out.

> 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.

We say this, suggesting that repo_get_default_remote()'s signature is
just get_default_remote()'s plus a "struct repository *" (like most
repo_*). But..

> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index c5d3fc3817f..965260edb22 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;
> +	struct repository subrepo;
> +	int ignore_errno;
> +
> +	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
> +					  "HEAD", 0, NULL, NULL,
> +					  &ignore_errno);
> +	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);
> +}
> +

repo_get_default_remote() actually take yet another argument - refname.

It looks to me that repo_get_default_remote() shouldn't take the
refname argument at all and that we should be using
refs_resolve_ref_unsafe() instead, like:

  +static char *repo_get_default_remote(struct repository *repo)
    {
    char *dest = NULL, *ret;
    struct strbuf sb = STRBUF_INIT;
  -	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
  +	const char *refname = refs_resolve_ref_unsafe(
  +   get_main_ref_store(repo), "HEAD", 0, NULL, NULL /*, errno? */);

this makes the rest of the code a lot cleaner..

  +static char *get_default_remote_submodule(const char *module_path)
  +{
  +	struct repository subrepo;
  +
  +	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
  +	return repo_get_default_remote(&subrepo);
  +}
  +
  +static char *get_default_remote(void)
  +{
  +  return repo_get_default_remote(the_repository);
  +}

And because it's quite idiomatic to initialize the subrepo struct in
order to can call repo_* functions, we could even drop
get_default_remote_submodule() altogether.

As for why this wasn't the original approach, the only reason I can
think of is that we didn't realize get_main_ref_store(subrepo) was an
option.

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


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

* Re: [PATCH v4 7/7] submodule: move core cmd_update() logic to C
  2022-01-27 16:22       ` [PATCH v4 7/7] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
@ 2022-01-27 21:55         ` Glen Choo
  0 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-01-27 21:55 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

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

> From: Atharva Raykar <raykar.ath@gmail.com>
>
> 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_submodules2()` and `update_submodule2()`
> which will supersede `update_submodules()` and `update_submodule()`.
>
> 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>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---

I've read through all of the patches besides this one - I hope to get
through this one soon.

The diff is quite large, but I can't think of any way to shrink it down
at the moment.

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

* [PATCH v5 0/9] submodule: convert the rest of 'update' to C
  2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
                         ` (6 preceding siblings ...)
  2022-01-27 16:22       ` [PATCH v4 7/7] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56       ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 1/9] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
                           ` (9 more replies)
  7 siblings, 10 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

A rewrite of "git submodule" in C, except the trivial pass-through
wrapping code (basically getopt etc.) in git-submodule.sh. For a
greater summary & context see v4's CL:
https://lore.kernel.org/git/cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com/

Changes in v5:

 * Took Glen Choo's suggestion for a code change in 1/8, thanks!

 * A bit more mid-series churn to make the large commit at the end
   have a smaller diff. The result is that in v4/v5 we have in that
   last commit (but see below).

   - 2 files changed, 389 insertions(+), 418 deletions(-)
   + 2 files changed, 357 insertions(+), 388 deletions(-)

 * There were some logic errors in v4 around how we handled error
   reporting. A new 8/9 adds tests for the existing behavior, and
   we're now bug-for-bug compatible.

   It turned out that we were passing around string lists of errors
   etc. in a way that wasn't needed, i.e. the initial code can just
   report the error.

   Much of this was also simplified with my recently added
   die_message() function. I.e. sometimes we want to have a "fatal: "
   message, but exit non-128.

Atharva Raykar (6):
  submodule--helper: get remote names from any repository
  submodule--helper: refactor get_submodule_displaypath()
  submodule--helper: allow setting superprefix for init_submodule()
  submodule--helper: run update using child process struct
  builtin/submodule--helper.c: reformat designated initializers
  submodule: move core cmd_update() logic to C

Ævar Arnfjörð Bjarmason (3):
  builtin/submodule--helper.c: rename option variables to "opt"
  submodule--helper: don't use bitfield indirection for parse_options()
  submodule tests: test for init and update failure output

 builtin/submodule--helper.c    | 706 +++++++++++++++++++--------------
 git-submodule.sh               | 145 +------
 t/t7406-submodule-update.sh    |  14 +-
 t/t7408-submodule-reference.sh |  14 +-
 4 files changed, 444 insertions(+), 435 deletions(-)

Range-diff against v4:
 1:  1a0b1323cd7 !  1:  088c7236a16 submodule--helper: get remote names from any repository
    @@ Commit message
     
         Mentored-by: Christian Couder <christian.couder@gmail.com>
         Mentored-by: Shourya Shukla <periperidip@gmail.com>
    +    Helped-by: Glen Choo <chooglen@google.com>
         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
         Signed-off-by: Junio C Hamano <gitster@pobox.com>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
    @@ builtin/submodule--helper.c
      				  void *cb_data);
      
     -static char *get_default_remote(void)
    -+static char *repo_get_default_remote(struct repository *repo, const char *refname)
    ++static char *repo_get_default_remote(struct repository *repo)
      {
      	char *dest = NULL, *ret;
      	struct strbuf sb = STRBUF_INIT;
     -	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
    ++	struct ref_store *store = get_main_ref_store(repo);
    ++	int ignore_errno;
    ++	const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
    ++						      NULL, &ignore_errno);
      
      	if (!refname)
      		die(_("No such ref: %s"), "HEAD");
    @@ builtin/submodule--helper.c: static char *get_default_remote(void)
      
     +static char *get_default_remote_submodule(const char *module_path)
     +{
    -+	const char *refname;
     +	struct repository subrepo;
    -+	int ignore_errno;
     +
    -+	refname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),
    -+					  "HEAD", 0, NULL, NULL,
    -+					  &ignore_errno);
     +	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
    -+	return repo_get_default_remote(&subrepo, refname);
    ++	return repo_get_default_remote(&subrepo);
     +}
     +
     +static char *get_default_remote(void)
     +{
    -+	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
    -+	return repo_get_default_remote(the_repository, refname);
    ++	return repo_get_default_remote(the_repository);
     +}
     +
      static int print_default_remote(int argc, const char **argv, const char *prefix)
 2:  7e2df3ff220 =  2:  bc694987893 submodule--helper: refactor get_submodule_displaypath()
 3:  f31fd72fba2 =  3:  e2cc7f0e23b submodule--helper: allow setting superprefix for init_submodule()
 4:  76c5a826a80 =  4:  e1df2dd4457 submodule--helper: run update using child process struct
 5:  29aa2fc0851 =  5:  fa815e37f9f builtin/submodule--helper.c: reformat designated initializers
 6:  d3ad6e7a351 !  6:  ef097f7ea51 builtin/submodule--helper.c: rename "suc" variable to "opt"
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    builtin/submodule--helper.c: rename "suc" variable to "opt"
    +    builtin/submodule--helper.c: rename option variables to "opt"
     
    -    Rename the "suc" variable in "builtin/submodule--helper.c" to
    -    "opt". The only reason for this change is to make the subsequent
    -    commit's diff smaller, by doing this rename we can "anchor" the diff
    -    better, as it "borrow" most of the options declared here as-is as far
    -    as the diff rename detection is concerned.
    +    Rename the "suc" variable in update_clone() to "opt", and do the same
    +    for the "update_data" variable in run_update_procedure().
    +
    +    The only reason for this change is to make the subsequent commit's
    +    diff smaller, by doing this rename we can "anchor" the diff better, as
    +    it "borrow" most of the options declared here as-is as far as the diff
    +    rename detection is concerned.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    @@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv
      }
      
      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 update_data opt = UPDATE_DATA_INIT;
    + 
    + 	struct option options[] = {
    + 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
    +@@ builtin/submodule--helper.c: static int run_update_procedure(int argc, const char **argv, const char *prefix)
    + 			 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_INTEGER(0, "depth", &opt.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"),
    ++		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
    + 			   N_("path into the working tree, across nested "
    + 			      "submodule boundaries")),
    +-		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
    ++		OPT_CALLBACK_F(0, "oid", &opt.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"),
    ++		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
    + 			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
    + 			       parse_opt_object_id),
    + 		OPT_END()
    +@@ builtin/submodule--helper.c: static int run_update_procedure(int argc, const char **argv, const char *prefix)
    + 	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];
    ++	opt.force = !!force;
    ++	opt.quiet = !!quiet;
    ++	opt.nofetch = !!nofetch;
    ++	opt.just_cloned = !!just_cloned;
    ++	opt.sm_path = argv[0];
    + 
    +-	if (update_data.recursive_prefix)
    +-		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
    ++	if (opt.recursive_prefix)
    ++		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
    + 	else
    +-		prefixed_path = xstrdup(update_data.sm_path);
    ++		prefixed_path = xstrdup(opt.sm_path);
    + 
    +-	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
    ++	opt.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);
    ++	determine_submodule_update_strategy(the_repository, opt.just_cloned,
    ++					    opt.sm_path, update,
    ++					    &opt.update_strategy);
    + 
    + 	free(prefixed_path);
    + 
    +-	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
    +-		return do_run_update_procedure(&update_data);
    ++	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
    ++		return do_run_update_procedure(&opt);
    + 
    + 	return 3;
    + }
 -:  ----------- >  7:  6b038f558c1 submodule--helper: don't use bitfield indirection for parse_options()
 -:  ----------- >  8:  b4f84132201 submodule tests: test for init and update failure output
 7:  02954603763 !  9:  e8e57606ee9 submodule: move core cmd_update() logic to C
    @@ Commit message
     
      ## builtin/submodule--helper.c ##
     @@ builtin/submodule--helper.c: static char *get_default_remote(void)
    - 	return repo_get_default_remote(the_repository, refname);
    + 	return repo_get_default_remote(the_repository);
      }
      
     -static int print_default_remote(int argc, const char **argv, const char *prefix)
    @@ builtin/submodule--helper.c: struct submodule_update_clone {
      	const char *recursive_prefix;
      	const char *sm_path;
      	const char *displaypath;
    - 	struct object_id oid;
    +@@ builtin/submodule--helper.c: struct update_data {
      	struct object_id suboid;
      	struct submodule_update_strategy update_strategy;
    -+	int max_jobs;
      	int depth;
    --	unsigned int force: 1;
    --	unsigned int quiet: 1;
    --	unsigned int nofetch: 1;
    --	unsigned int just_cloned: 1;
     +	int recommend_shallow;
     +	int single_branch;
    ++	int max_jobs;
     +	unsigned int init;
    -+	unsigned int force;
    -+	unsigned int quiet;
    -+	unsigned int nofetch;
    + 	unsigned int force;
    + 	unsigned int quiet;
    + 	unsigned int nofetch;
    + 	unsigned int just_cloned;
     +	unsigned int remote;
     +	unsigned int recursive;
     +	unsigned int progress;
     +	unsigned int dissociate;
     +	unsigned int require_init;
     +	unsigned warn_if_uninitialized ;
    -+	unsigned int just_cloned ;
     +	struct string_list references;
     +	struct module_list list;
      };
    @@ builtin/submodule--helper.c: struct submodule_update_clone {
      }
      
      static void next_submodule_warn_missing(struct submodule_update_clone *suc,
    -@@ builtin/submodule--helper.c: 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)
    - {
    +@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)
      	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;
      
    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u
      
      	cp.dir = xstrdup(ud->sm_path);
      	prepare_submodule_repo_env(&cp.env_array);
    --	if (run_command(&cp)) {
    + 	if (run_command(&cp)) {
     -		switch (ud->update_strategy.type) {
    -+	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));
    -+			}
    -+		}
    -+
    -+		/* the command failed, but update must continue */
    -+		string_list_append_nodup(err, strbuf_detach(&out, NULL));
    -+		return 1;
    -+	}
    -+
    -+	if (!ud->quiet) {
     +		switch (strategy.type) {
      		case SM_UPDATE_CHECKOUT:
     -			printf(_("Unable to checkout '%s' in submodule path '%s'"),
     -			       oid, ud->displaypath);
    -+			printf(_("Submodule path '%s': checked out '%s'\n"),
    -+			       ud->displaypath, oid);
    ++			die_message(_("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);
    -+			printf(_("Submodule path '%s': rebased into '%s'\n"),
    -+			       ud->displaypath, oid);
    ++			if (!must_die_on_failure)
    ++				break;
    ++			die(_("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);
    -+			printf(_("Submodule path '%s': merged in '%s'\n"),
    -+			       ud->displaypath, oid);
    ++			if (!must_die_on_failure)
    ++				break;
    ++			die(_("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);
    -+			printf(_("Submodule path '%s': '%s %s'\n"),
    -+			       ud->displaypath, strategy.command, oid);
    ++			if (!must_die_on_failure)
    ++				break;
    ++			die(_("Execution of '%s %s' failed in submodule path '%s'"),
    ++			    strategy.command, oid, ud->displaypath);
      			break;
      		default:
      			BUG("unexpected update strategy type: %s",
    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u
     -		 * This signifies to the caller in shell that the command
     -		 * failed without dying
     -		 */
    --		return 1;
    --	}
    --
    ++
    ++		/* the command failed, but update must continue */
    + 		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"),
    ++	if (ud->quiet)
    ++		return 0;
    ++
    ++	switch (strategy.type) {
    + 	case SM_UPDATE_CHECKOUT:
    + 		printf(_("Submodule path '%s': checked out '%s'\n"),
    + 		       ud->displaypath, oid);
    +@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)
    + 		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",
    ++		       ud->displaypath, strategy.command, oid);
    + 		break;
    + 	default:
    + 		BUG("unexpected update strategy type: %s",
     -		    submodule_strategy_to_string(&ud->update_strategy));
    ++		    submodule_strategy_to_string(&strategy));
      	}
      
    -+	strbuf_release(&out);
      	return 0;
      }
      
     -static int do_run_update_procedure(struct update_data *ud)
    -+static int run_update_procedure(struct update_data *ud, struct string_list *err)
    ++static int run_update_procedure(struct update_data *ud)
      {
      	int subforce = is_null_oid(&ud->suboid) || ud->force;
      
     @@ builtin/submodule--helper.c: 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);
    --}
    --
     -static void update_submodule(struct update_clone_data *ucd)
     -{
     -	fprintf(stdout, "dummy %s %d\t%s\n",
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -
     -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 update_data opt = UPDATE_DATA_INIT;
     -
     -	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,
    +-		OPT__QUIET(&opt.quiet,
    +-			   N_("suppress output for update by rebase or merge")),
    +-		OPT__FORCE(&opt.force, N_("force checkout updates"),
    +-			   0),
    +-		OPT_BOOL('N', "no-fetch", &opt.nofetch,
     -			 N_("don't fetch new objects from the remote site")),
    --		OPT_BOOL(0, "just-cloned", &just_cloned,
    +-		OPT_BOOL(0, "just-cloned", &opt.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_INTEGER(0, "depth", &opt.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"),
    +-		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
     -			   N_("path into the working tree, across nested "
     -			      "submodule boundaries")),
    --		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
    +-		OPT_CALLBACK_F(0, "oid", &opt.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"),
    +-		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
     -			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
     -			       parse_opt_object_id),
     -		OPT_END()
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -	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];
    +-	opt.sm_path = argv[0];
     -
    --	if (update_data.recursive_prefix)
    --		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
    +-	if (opt.recursive_prefix)
    +-		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
     -	else
    --		prefixed_path = xstrdup(update_data.sm_path);
    +-		prefixed_path = xstrdup(opt.sm_path);
     -
    --	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
    +-	opt.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);
    +-	determine_submodule_update_strategy(the_repository, opt.just_cloned,
    +-					    opt.sm_path, update,
    +-					    &opt.update_strategy);
     -
     -	free(prefixed_path);
     -
    --	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
    --		return do_run_update_procedure(&update_data);
    +-	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
    +-		return do_run_update_procedure(&opt);
     -
     -	return 3;
     -}
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -	printf("%s", relative_path(argv[1], argv[2], &sb));
     -	strbuf_release(&sb);
     -	return 0;
    -+	return run_update_command(ud, subforce, err);
    - }
    - 
    +-}
    +-
      static const char *remote_submodule_branch(const char *path)
    + {
    + 	const struct submodule *sub;
     @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv, const char *prefix)
      	return 0;
      }
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +static int update_submodule(struct update_data *update_data)
     +{
     +	char *prefixed_path;
    -+	struct string_list err = STRING_LIST_INIT_DUP;
     +
     +	ensure_core_worktree(update_data->sm_path);
     +
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +	}
     +
     +	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
    -+		if (run_update_procedure(update_data, &err))
    ++		if (run_update_procedure(update_data))
     +			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);
    ++		int res;
     +
     +		if (update_data->recursive_prefix)
     +			prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +		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);
    -+		string_list_clear(&err, 0);
    -+		return 1;
    ++		res = run_command(&cp);
    ++		if (!res)
    ++			return 0;
    ++		die_message(_("Failed to recurse into submodule path '%s'"),
    ++			    update_data->displaypath);
    ++		if (res == 128)
    ++			exit(res);
    ++		else if (res)
    ++			return 1;
     +	}
     +
     +	return 0;
-- 
2.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 1/9] submodule--helper: get remote names from any repository
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 2/9] submodule--helper: refactor get_submodule_displaypath() Ævar Arnfjörð Bjarmason
                           ` (8 subsequent siblings)
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

`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>
Helped-by: Glen Choo <chooglen@google.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@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 c5d3fc3817f..4c7c1e1432d 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -29,11 +29,14 @@
 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)
 {
 	char *dest = NULL, *ret;
 	struct strbuf sb = STRBUF_INIT;
-	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+	struct ref_store *store = get_main_ref_store(repo);
+	int ignore_errno;
+	const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
+						      NULL, &ignore_errno);
 
 	if (!refname)
 		die(_("No such ref: %s"), "HEAD");
@@ -46,7 +49,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 +58,19 @@ static char *get_default_remote(void)
 	return ret;
 }
 
+static char *get_default_remote_submodule(const char *module_path)
+{
+	struct repository subrepo;
+
+	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
+	return repo_get_default_remote(&subrepo);
+}
+
+static char *get_default_remote(void)
+{
+	return repo_get_default_remote(the_repository);
+}
+
 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.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 2/9] submodule--helper: refactor get_submodule_displaypath()
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 1/9] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 3/9] submodule--helper: allow setting superprefix for init_submodule() Ævar Arnfjörð Bjarmason
                           ` (7 subsequent siblings)
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@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 4c7c1e1432d..5efceb9d46c 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.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 3/9] submodule--helper: allow setting superprefix for init_submodule()
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 1/9] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 2/9] submodule--helper: refactor get_submodule_displaypath() Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 4/9] submodule--helper: run update using child process struct Ævar Arnfjörð Bjarmason
                           ` (6 subsequent siblings)
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5efceb9d46c..09cda67c1ea 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 { 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.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 4/9] submodule--helper: run update using child process struct
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
                           ` (2 preceding siblings ...)
  2022-01-28 12:56         ` [PATCH v5 3/9] submodule--helper: allow setting superprefix for init_submodule() Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 5/9] builtin/submodule--helper.c: reformat designated initializers Ævar Arnfjörð Bjarmason
                           ` (5 subsequent siblings)
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@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 09cda67c1ea..db71e6f4ec8 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2344,47 +2344,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.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 5/9] builtin/submodule--helper.c: reformat designated initializers
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
                           ` (3 preceding siblings ...)
  2022-01-28 12:56         ` [PATCH v5 4/9] submodule--helper: run update using child process struct Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 6/9] builtin/submodule--helper.c: rename option variables to "opt" Ævar Arnfjörð Bjarmason
                           ` (4 subsequent siblings)
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

The second hunk here will make a subsequent commit's diff smaller, and
let's do the first and third hunks while we're at it so that we
consistently format all of these.

Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index db71e6f4ec8..9f79bdf4d51 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1654,7 +1654,10 @@ struct module_clone_data {
 	unsigned int require_init: 1;
 	int single_branch;
 };
-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
+#define MODULE_CLONE_DATA_INIT { \
+	.reference = STRING_LIST_INIT_NODUP, \
+	.single_branch = -1, \
+}
 
 struct submodule_alternate_setup {
 	const char *submodule_name;
@@ -2047,7 +2050,9 @@ struct update_data {
 	unsigned int nofetch: 1;
 	unsigned int just_cloned: 1;
 };
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+}
 
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
 		struct strbuf *out, const char *displaypath)
@@ -3013,7 +3018,9 @@ struct add_data {
 	unsigned int progress: 1;
 	unsigned int dissociate: 1;
 };
-#define ADD_DATA_INIT { .depth = -1 }
+#define ADD_DATA_INIT { \
+	.depth = -1, \
+}
 
 static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
 {
-- 
2.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 6/9] builtin/submodule--helper.c: rename option variables to "opt"
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
                           ` (4 preceding siblings ...)
  2022-01-28 12:56         ` [PATCH v5 5/9] builtin/submodule--helper.c: reformat designated initializers Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 7/9] submodule--helper: don't use bitfield indirection for parse_options() Ævar Arnfjörð Bjarmason
                           ` (3 subsequent siblings)
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

Rename the "suc" variable in update_clone() to "opt", and do the same
for the "update_data" variable in run_update_procedure().

The only reason for this change is to make the subsequent commit's
diff smaller, by doing this rename we can "anchor" the diff better, as
it "borrow" most of the options declared here as-is as far as the diff
rename detection is concerned.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 74 ++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9f79bdf4d51..c2d4fd0347a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2517,36 +2517,36 @@ 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 submodule_update_clone opt = 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,
+		OPT_STRING(0, "recursive-prefix", &opt.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"),
+		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
 			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &suc.dissociate,
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
 			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
+		OPT_STRING(0, "depth", &opt.depth, "<depth>",
 			   N_("create a shallow clone truncated to the "
 			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
 			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
+		OPT_BOOL(0, "recommend-shallow", &opt.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,
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
 			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &suc.require_init,
+		OPT_BOOL(0, "require-init", &opt.require_init,
 			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &suc.single_branch,
+		OPT_BOOL(0, "single-branch", &opt.single_branch,
 			 N_("clone only one branch, HEAD or --branch")),
 		OPT_END()
 	};
@@ -2555,32 +2555,32 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
 		NULL
 	};
-	suc.prefix = prefix;
+	opt.prefix = prefix;
 
-	update_clone_config_from_gitmodules(&suc.max_jobs);
-	git_config(git_update_clone_config, &suc.max_jobs);
+	update_clone_config_from_gitmodules(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.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)
+		if (parse_submodule_update_strategy(update, &opt.update) < 0)
 			die(_("bad value for update parameter"));
 
-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
 		return 1;
 
 	if (pathspec.nr)
-		suc.warn_if_uninitialized = 1;
+		opt.warn_if_uninitialized = 1;
 
-	return update_submodules(&suc);
+	return update_submodules(&opt);
 }
 
 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 update_data opt = UPDATE_DATA_INIT;
 
 	struct option options[] = {
 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
@@ -2589,20 +2589,20 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 			 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_INTEGER(0, "depth", &opt.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"),
+		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
 			   N_("path into the working tree, across nested "
 			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
+		OPT_CALLBACK_F(0, "oid", &opt.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"),
+		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
 			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
 			       parse_opt_object_id),
 		OPT_END()
@@ -2618,27 +2618,27 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	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];
+	opt.force = !!force;
+	opt.quiet = !!quiet;
+	opt.nofetch = !!nofetch;
+	opt.just_cloned = !!just_cloned;
+	opt.sm_path = argv[0];
 
-	if (update_data.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
+	if (opt.recursive_prefix)
+		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
 	else
-		prefixed_path = xstrdup(update_data.sm_path);
+		prefixed_path = xstrdup(opt.sm_path);
 
-	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
+	opt.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);
+	determine_submodule_update_strategy(the_repository, opt.just_cloned,
+					    opt.sm_path, update,
+					    &opt.update_strategy);
 
 	free(prefixed_path);
 
-	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data);
+	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
+		return do_run_update_procedure(&opt);
 
 	return 3;
 }
-- 
2.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 7/9] submodule--helper: don't use bitfield indirection for parse_options()
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
                           ` (5 preceding siblings ...)
  2022-01-28 12:56         ` [PATCH v5 6/9] builtin/submodule--helper.c: rename option variables to "opt" Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 8/9] submodule tests: test for init and update failure output Ævar Arnfjörð Bjarmason
                           ` (2 subsequent siblings)
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

Do away with the indirection of local variables added in
c51f8f94e5b (submodule--helper: run update procedures from C,
2021-08-24).

These were only needed because in C you can't get a pointer to a
single bit, so we were using intermediate variables instead.

This will also make a subsequent large commit's diff smaller.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c2d4fd0347a..4a0890954e9 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2045,10 +2045,10 @@ struct update_data {
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
 	int depth;
-	unsigned int force: 1;
-	unsigned int quiet: 1;
-	unsigned int nofetch: 1;
-	unsigned int just_cloned: 1;
+	unsigned int force;
+	unsigned int quiet;
+	unsigned int nofetch;
+	unsigned int just_cloned;
 };
 #define UPDATE_DATA_INIT { \
 	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
@@ -2578,16 +2578,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 
 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 opt = UPDATE_DATA_INIT;
 
 	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,
+		OPT__QUIET(&opt.quiet,
+			   N_("suppress output for update by rebase or merge")),
+		OPT__FORCE(&opt.force, N_("force checkout updates"),
+			   0),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
 			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &just_cloned,
+		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
 			 N_("overrides update mode in case the repository is a fresh clone")),
 		OPT_INTEGER(0, "depth", &opt.depth, N_("depth for shallow fetch")),
 		OPT_STRING(0, "prefix", &prefix,
@@ -2618,10 +2619,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	if (argc != 1)
 		usage_with_options(usage, options);
 
-	opt.force = !!force;
-	opt.quiet = !!quiet;
-	opt.nofetch = !!nofetch;
-	opt.just_cloned = !!just_cloned;
 	opt.sm_path = argv[0];
 
 	if (opt.recursive_prefix)
-- 
2.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 8/9] submodule tests: test for init and update failure output
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
                           ` (6 preceding siblings ...)
  2022-01-28 12:56         ` [PATCH v5 7/9] submodule--helper: don't use bitfield indirection for parse_options() Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-01-28 12:56         ` [PATCH v5 9/9] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
  9 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

Amend some submodule tests to test for the failure output of "git
submodule [update|init]". The lack of such tests hid a regression in
an earlier version of a subsequent commit.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t7406-submodule-update.sh    | 14 ++++++++++++--
 t/t7408-submodule-reference.sh | 14 +++++++++++++-
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 11cccbb333b..7764c1c3cb6 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -205,8 +205,18 @@ test_expect_success 'submodule update should fail due to local changes' '
 	 (cd submodule &&
 	  compare_head
 	 ) &&
-	 test_must_fail git submodule update submodule
-	)
+	 test_must_fail git submodule update submodule 2>../actual.raw
+	) &&
+	sed "s/^> //" >expect <<-\EOF &&
+	> error: Your local changes to the following files would be overwritten by checkout:
+	> 	file
+	> Please commit your changes or stash them before you switch branches.
+	> Aborting
+	> fatal: Unable to checkout OID in submodule path '\''submodule'\''
+	EOF
+	sed -e "s/checkout $SQ[^$SQ]*$SQ/checkout OID/" <actual.raw >actual &&
+	test_cmp expect actual
+
 '
 test_expect_success 'submodule update should throw away changes with --force ' '
 	(cd super &&
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index a3892f494b6..c3a45455106 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -193,7 +193,19 @@ test_expect_success 'missing nested submodule alternate fails clone and submodul
 		cd supersuper-clone &&
 		check_that_two_of_three_alternates_are_used &&
 		# update of the submodule fails
-		test_must_fail git submodule update --init --recursive
+		cat >expect <<-\EOF &&
+		fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub'\''. Retry scheduled
+		fatal: submodule '\''sub-dissociate'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub-dissociate'\''. Retry scheduled
+		fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub'\'' a second time, aborting
+		fatal: Failed to recurse into submodule path ...
+		EOF
+		test_must_fail git submodule update --init --recursive 2>err &&
+		grep -e fatal: -e ^Failed err >actual.raw &&
+		sed -e "s/path $SQ[^$SQ]*$SQ/path .../" <actual.raw >actual &&
+		test_cmp expect actual
 	)
 '
 
-- 
2.35.0.914.ge5c8aab0d5b


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

* [PATCH v5 9/9] submodule: move core cmd_update() logic to C
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
                           ` (7 preceding siblings ...)
  2022-01-28 12:56         ` [PATCH v5 8/9] submodule tests: test for init and update failure output Ævar Arnfjörð Bjarmason
@ 2022-01-28 12:56         ` Ævar Arnfjörð Bjarmason
  2022-02-03  0:18           ` Glen Choo
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
  9 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-28 12:56 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Glen Choo, Ævar Arnfjörð Bjarmason

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

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_submodules2()` and `update_submodule2()`
which will supersede `update_submodules()` and `update_submodule()`.

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 599 +++++++++++++++++++++---------------
 git-submodule.sh            | 145 +--------
 2 files changed, 356 insertions(+), 388 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 4a0890954e9..1c28b6f479c 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);
 }
 
-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]);
@@ -1965,29 +1950,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;
@@ -2015,7 +1977,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;
 
@@ -2038,6 +1999,7 @@ struct submodule_update_clone {
 }
 
 struct update_data {
+	const char *prefix;
 	const char *recursive_prefix;
 	const char *sm_path;
 	const char *displaypath;
@@ -2045,13 +2007,54 @@ struct update_data {
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
 	int depth;
+	int recommend_shallow;
+	int single_branch;
+	int max_jobs;
+	unsigned int init;
 	unsigned int force;
 	unsigned int quiet;
 	unsigned int nofetch;
 	unsigned int just_cloned;
+	unsigned int remote;
+	unsigned int recursive;
+	unsigned int progress;
+	unsigned int dissociate;
+	unsigned int require_init;
+	unsigned warn_if_uninitialized ;
+	struct string_list references;
+	struct module_list list;
 };
 #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,
@@ -2352,8 +2355,15 @@ static int run_update_command(struct update_data *ud, int subforce)
 	struct child_process cp = CHILD_PROCESS_INIT;
 	char *oid = oid_to_hex(&ud->oid);
 	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);
@@ -2376,55 +2386,54 @@ 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) {
+		switch (strategy.type) {
 		case SM_UPDATE_CHECKOUT:
-			printf(_("Unable to checkout '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
+			die_message(_("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);
+			if (!must_die_on_failure)
+				break;
+			die(_("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);
+			if (!must_die_on_failure)
+				break;
+			die(_("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);
+			if (!must_die_on_failure)
+				break;
+			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(&ud->update_strategy));
+			    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 */
 		return 1;
 	}
 
-	switch (ud->update_strategy.type) {
+	if (ud->quiet)
+		return 0;
+
+	switch (strategy.type) {
 	case SM_UPDATE_CHECKOUT:
 		printf(_("Submodule path '%s': checked out '%s'\n"),
 		       ud->displaypath, oid);
@@ -2439,17 +2448,17 @@ static int run_update_command(struct update_data *ud, int subforce)
 		break;
 	case SM_UPDATE_COMMAND:
 		printf(_("Submodule path '%s': '%s %s'\n"),
-		       ud->displaypath, ud->update_strategy.command, oid);
+		       ud->displaypath, strategy.command, oid);
 		break;
 	default:
 		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+		    submodule_strategy_to_string(&strategy));
 	}
 
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud)
+static int run_update_procedure(struct update_data *ud)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2479,178 +2488,6 @@ 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)
-{
-	fprintf(stdout, "dummy %s %d\t%s\n",
-		oid_to_hex(&ucd->oid),
-		ucd->just_cloned,
-		ucd->sub->path);
-}
-
-static int update_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_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 opt = 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", &opt.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", &opt.references, N_("repo"),
-			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &opt.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &opt.max_jobs,
-			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
-		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
-		OPT_BOOL(0, "progress", &opt.progress,
-			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &opt.require_init,
-			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &opt.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
-	};
-	opt.prefix = prefix;
-
-	update_clone_config_from_gitmodules(&opt.max_jobs);
-	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
-			die(_("bad value for update parameter"));
-
-	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
-		return 1;
-
-	if (pathspec.nr)
-		opt.warn_if_uninitialized = 1;
-
-	return update_submodules(&opt);
-}
-
-static int run_update_procedure(int argc, const char **argv, const char *prefix)
-{
-	char *prefixed_path, *update = NULL;
-	struct update_data opt = UPDATE_DATA_INIT;
-
-	struct option options[] = {
-		OPT__QUIET(&opt.quiet,
-			   N_("suppress output for update by rebase or merge")),
-		OPT__FORCE(&opt.force, N_("force checkout updates"),
-			   0),
-		OPT_BOOL('N', "no-fetch", &opt.nofetch,
-			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
-			 N_("overrides update mode in case the repository is a fresh clone")),
-		OPT_INTEGER(0, "depth", &opt.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", &opt.recursive_prefix, N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
-			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_CALLBACK_F(0, "suboid", &opt.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);
-
-	opt.sm_path = argv[0];
-
-	if (opt.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
-	else
-		prefixed_path = xstrdup(opt.sm_path);
-
-	opt.displaypath = get_submodule_displaypath(prefixed_path, prefix);
-
-	determine_submodule_update_strategy(the_repository, opt.just_cloned,
-					    opt.sm_path, update,
-					    &opt.update_strategy);
-
-	free(prefixed_path);
-
-	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
-		return do_run_update_procedure(&opt);
-
-	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;
@@ -2783,17 +2620,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 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);
 
@@ -2813,8 +2644,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 		free(abs_path);
 		strbuf_release(&sb);
 	}
-
-	return 0;
 }
 
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
@@ -3001,6 +2830,271 @@ 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;
+
+	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 (run_update_procedure(update_data))
+			return 1;
+
+	if (update_data->recursive) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+		struct update_data next = *update_data;
+		int res;
+
+		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 */
+		res = run_command(&cp);
+		if (!res)
+			return 0;
+		die_message(_("Failed to recurse into submodule path '%s'"),
+			    update_data->displaypath);
+		if (res == 128)
+			exit(res);
+		else if (res)
+			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) {
+		res = 1;
+		goto cleanup;
+	}
+
+	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;
+	}
+
+cleanup:
+	string_list_clear(&update_data->references, 0);
+	return res;
+}
+
+static int module_update(int argc, const char **argv, const char *prefix)
+{
+	const char *update = NULL;
+	struct pathspec pathspec;
+	struct update_data opt = UPDATE_DATA_INIT;
+
+	struct option module_update_clone_options[] = {
+		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
+		OPT_BOOL(0, "init", &opt.init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_BOOL(0, "remote", &opt.remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &opt.recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_STRING(0, "prefix", &opt.prefix,
+			   N_("path"),
+			   N_("path into the working tree")),
+		OPT_STRING(0, "recursive-prefix", &opt.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", &opt.references, N_("repo"),
+				N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
+			 N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &opt.depth,
+			    N_("create a shallow clone truncated to the "
+			       "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
+			 N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
+			 N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &opt.require_init,
+			 N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &opt.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(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.max_jobs);
+
+	argc = parse_options(argc, argv, prefix, module_update_clone_options,
+			     git_submodule_helper_usage, 0);
+	oidcpy(&opt.oid, null_oid());
+	oidcpy(&opt.suboid, null_oid());
+
+	if (update)
+		if (parse_submodule_update_strategy(update,
+						    &opt.update_strategy) < 0)
+			die(_("bad value for update parameter"));
+
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
+		return 1;
+
+	if (pathspec.nr)
+		opt.warn_if_uninitialized = 1;
+
+	if (opt.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
+		info.superprefix = opt.recursive_prefix;
+		if (opt.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
+	return update_submodules(&opt);
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
@@ -3388,16 +3482,11 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
-	{"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},
+	{"update", module_update, 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},
diff --git a/git-submodule.sh b/git-submodule.sh
index 652861aa66a..bcd8b92aabd 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.35.0.914.ge5c8aab0d5b


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

* Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C
  2022-01-28 12:56         ` [PATCH v5 9/9] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
@ 2022-02-03  0:18           ` Glen Choo
  2022-02-03  2:26             ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-03  0:18 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

I mentioned (out-of-mailing-list) that I was still looking at this, but
that the big sh -> c conversion is quite challenging for me to parse
personally. I'm still looking at it, but it will take some time..

I'm of the opinion that this patch would be a lot easier to review if it
were broken up into more patches, but it has always looked like this
[1]. The only real difference from [1] to this version is that this also
removes all of the dead code, which doesn't really hinder reviewability.

I don't think you have to go through the effort of splitting it up -
after all you were able to review [1], so given enough time I should
be able to read through this patch too :) That said, I wish that we
already had a split up patch for at least 2 other reasons:

- Junio pointed out that this conflicts with
  es/superproject-aware-submodules [2]. I'm not sure which should be
  based on which. If this does end up being based on
  es/superproject-aware-submodules, it would probably be easier to
  rebase as a series of smaller patches. Atharva noted that the
  conflicts are mild though, so maybe it's not so bad.

- Besides making sure that the sh -> c is faithful, a thorough review
  should hopefully catch unintentional mistakes. The size of this patch
  makes such mistakes difficult to spot. For instance, here's something
  I spotted only after trying to split the patch myself..

  > +static int module_update(int argc, const char **argv, const char *prefix)
  > +{
  > +	const char *update = NULL;
  > +	struct pathspec pathspec;
  > +	struct update_data opt = UPDATE_DATA_INIT;
  > +
  > +	struct option module_update_clone_options[] = {
  [...]
  > +	};
  > +
  > +	const char *const git_submodule_helper_usage[] = {
  > +		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
  > +		NULL
  > +	};
  > +
  > +	update_clone_config_from_gitmodules(&opt.max_jobs);
  > +	git_config(git_update_clone_config, &opt.max_jobs);

  Notice that we copy-pasted the option parsing from update-clone into
  module_update() but forgot to update the names.

My ideal patch organization would be something like:

- wrap some existing command in "git submodule--helper update" (probably
  run-update-procedure)
- absorb the surrounding sh code into "git submodule--helper
  update" one command at-a-time i.e. deprecating and removing the
  commands one at a time - instead of deprecating and removing them all
  at once (like this patch), or deprecating all at once and removing
  them one at a time (like v1).

I don't know if it's feasible or not; Atharva noted upthread that there
are some technical reasons why some things can be done in-process and
some cannot, but it might be a useful exercise.

Here's what I propose:

- If you think this alternative organization would be helpful for you
  too, I will attempt it. This will take a while, but by the end you and
  I will have effectively reviewed all of the code, so it should be easy
  to finish up the review.

- Otherwise e.g. maybe this is a huge waste of time, or you're already
  really confident in the correctness of the sh -> c when you reviewed
  the original patch, etc, I'll just review this patch as-is. I'd
  appreciate any tips and tricks that might help :)

- Orthogonal to patch organization, I'm still not sure if this will be
  rebased on es/superproject-aware-submodules or vice-versa, and I don't
  want either of us to sink too much effort before knowing the answer.

[1] https://lore.kernel.org/git/20210907115932.36068-7-raykar.ath@gmail.com/
[2] https://lore.kernel.org/git/YWiXL+plA7GHfuVv@google.com/


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

* Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C
  2022-02-03  0:18           ` Glen Choo
@ 2022-02-03  2:26             ` Ævar Arnfjörð Bjarmason
  2022-02-03  8:15               ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-03  2:26 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Wed, Feb 02 2022, Glen Choo wrote:

> - Junio pointed out that this conflicts with
>   es/superproject-aware-submodules [2]. I'm not sure which should be
>   based on which. If this does end up being based on
>   es/superproject-aware-submodules, it would probably be easier to
>   rebase as a series of smaller patches. Atharva noted that the
>   conflicts are mild though, so maybe it's not so bad.

I think it makes sense to get this series through first, i.e. the
(supposedly) no-behavior-changing one, and then one that introduces new
submodule behavior.

Particularly because for es/superproject-aware-submodules the main
selling point is a performance improvement, which as I noted in the
review for it I've been unable to observe once the C<->sh layer goes
away.

I'm not saying it's not there, just that I don't think it's been shown
so far, IIRC there was some reference to some Google-internal network FS
that might or might not be helped by it...

> - Besides making sure that the sh -> c is faithful, a thorough review
>   should hopefully catch unintentional mistakes. The size of this patch
>   makes such mistakes difficult to spot. For instance, here's something
>   I spotted only after trying to split the patch myself..
>
>   > +static int module_update(int argc, const char **argv, const char *prefix)
>   > +{
>   > +	const char *update = NULL;
>   > +	struct pathspec pathspec;
>   > +	struct update_data opt = UPDATE_DATA_INIT;
>   > +
>   > +	struct option module_update_clone_options[] = {
>   [...]
>   > +	};
>   > +
>   > +	const char *const git_submodule_helper_usage[] = {
>   > +		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
>   > +		NULL
>   > +	};
>   > +
>   > +	update_clone_config_from_gitmodules(&opt.max_jobs);
>   > +	git_config(git_update_clone_config, &opt.max_jobs);
>
>   Notice that we copy-pasted the option parsing from update-clone into
>   module_update() but forgot to update the names.
>
> My ideal patch organization would be something like:
>
> - wrap some existing command in "git submodule--helper update" (probably
>   run-update-procedure)
> - absorb the surrounding sh code into "git submodule--helper
>   update" one command at-a-time i.e. deprecating and removing the
>   commands one at a time - instead of deprecating and removing them all
>   at once (like this patch), or deprecating all at once and removing
>   them one at a time (like v1).

I do think atomic changes that don't leave dead code for removal later
are easier to read & reason about, whatever else is reorganized.

I.e. not to have something where we replace all the running code, and
then remove already-unused code later.

On that topic, I noticed this series could/should have [1] fixed up into
it.

> - If you think this alternative organization would be helpful for you
>   too, I will attempt it. This will take a while, but by the end you and
>   I will have effectively reviewed all of the code, so it should be easy
>   to finish up the review.

I think it might, but I really don't know. We'll just have to see, so if
you want to take a stab at it that would be great.

Maybe it's a good way forward. E.g. as af first small step we could turn:

    while read -r quickabort sha1 just_cloned sm_path
    [...]
    die_if_unmatched "$quickabort" "$sha1"

into version where we fold that die_if_unmatched() logic into the C
code, and then ensure-core-worktree etc.

> - Otherwise e.g. maybe this is a huge waste of time, or you're already
>   really confident in the correctness of the sh -> c when you reviewed
>   the original patch, etc, I'll just review this patch as-is. I'd
>   appreciate any tips and tricks that might help :)

I'm not really confident in it.

I've read it, tested it as well as I could manage etc. but it's still a
very large change.

1.

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index b93f39288ce..756c2a67c72 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -286,13 +286,6 @@ get_author_ident_from_commit () {
 	parse_ident_from_commit author AUTHOR
 }
 
-# Clear repo-local GIT_* environment variables. Useful when switching to
-# another repository (e.g. when entering a submodule). See also the env
-# list in git_connect()
-clear_local_git_env() {
-	unset $(git rev-parse --local-env-vars)
-}
-
 # Generate a virtual base file for a two-file merge. Uses git apply to
 # remove lines from $1 that are not in $2, leaving only common lines.
 create_virtual_base() {
diff --git a/git-submodule.sh b/git-submodule.sh
index bcd8b92aabd..6c91b9e2403 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -50,30 +50,11 @@ single_branch=
 jobs=
 recommend_shallow=
 
-die_if_unmatched ()
-{
-	if test "$1" = "#unmatched"
-	then
-		exit ${2:-1}
-	fi
-}
-
 isnumber()
 {
 	n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
 }
 
-# Sanitize the local git environment for use within a submodule. We
-# can't simply use clear_local_git_env since we want to preserve some
-# of the settings from GIT_CONFIG_PARAMETERS.
-sanitize_submodule_env()
-{
-	save_config=$GIT_CONFIG_PARAMETERS
-	clear_local_git_env
-	GIT_CONFIG_PARAMETERS=$save_config
-	export GIT_CONFIG_PARAMETERS
-}
-
 #
 # Add a new submodule to the working tree, .gitmodules and the index
 #

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

* Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C
  2022-02-03  2:26             ` Ævar Arnfjörð Bjarmason
@ 2022-02-03  8:15               ` Ævar Arnfjörð Bjarmason
  2022-02-03 17:35                 ` Glen Choo
  0 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-03  8:15 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 03 2022, Ævar Arnfjörð Bjarmason wrote:

> On Wed, Feb 02 2022, Glen Choo wrote:
>
>> - Junio pointed out that this conflicts with
>>   es/superproject-aware-submodules [2]. I'm not sure which should be
>>   based on which. If this does end up being based on
>>   es/superproject-aware-submodules, it would probably be easier to
>>   rebase as a series of smaller patches. Atharva noted that the
>>   conflicts are mild though, so maybe it's not so bad.
>
> I think it makes sense to get this series through first, i.e. the
> (supposedly) no-behavior-changing one, and then one that introduces new
> submodule behavior.
>
> Particularly because for es/superproject-aware-submodules the main
> selling point is a performance improvement, which as I noted in the
> review for it I've been unable to observe once the C<->sh layer goes
> away.
>
> I'm not saying it's not there, just that I don't think it's been shown
> so far, IIRC there was some reference to some Google-internal network FS
> that might or might not be helped by it...
>
>> - Besides making sure that the sh -> c is faithful, a thorough review
>>   should hopefully catch unintentional mistakes. The size of this patch
>>   makes such mistakes difficult to spot. For instance, here's something
>>   I spotted only after trying to split the patch myself..
>>
>>   > +static int module_update(int argc, const char **argv, const char *prefix)
>>   > +{
>>   > +	const char *update = NULL;
>>   > +	struct pathspec pathspec;
>>   > +	struct update_data opt = UPDATE_DATA_INIT;
>>   > +
>>   > +	struct option module_update_clone_options[] = {
>>   [...]
>>   > +	};
>>   > +
>>   > +	const char *const git_submodule_helper_usage[] = {
>>   > +		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
>>   > +		NULL
>>   > +	};
>>   > +
>>   > +	update_clone_config_from_gitmodules(&opt.max_jobs);
>>   > +	git_config(git_update_clone_config, &opt.max_jobs);
>>
>>   Notice that we copy-pasted the option parsing from update-clone into
>>   module_update() but forgot to update the names.
>>
>> My ideal patch organization would be something like:
>>
>> - wrap some existing command in "git submodule--helper update" (probably
>>   run-update-procedure)
>> - absorb the surrounding sh code into "git submodule--helper
>>   update" one command at-a-time i.e. deprecating and removing the
>>   commands one at a time - instead of deprecating and removing them all
>>   at once (like this patch), or deprecating all at once and removing
>>   them one at a time (like v1).
>
> I do think atomic changes that don't leave dead code for removal later
> are easier to read & reason about, whatever else is reorganized.
>
> I.e. not to have something where we replace all the running code, and
> then remove already-unused code later.
>
> On that topic, I noticed this series could/should have [1] fixed up into
> it.
>
>> - If you think this alternative organization would be helpful for you
>>   too, I will attempt it. This will take a while, but by the end you and
>>   I will have effectively reviewed all of the code, so it should be easy
>>   to finish up the review.
>
> I think it might, but I really don't know. We'll just have to see, so if
> you want to take a stab at it that would be great.
>
> Maybe it's a good way forward. E.g. as af first small step we could turn:
>
>     while read -r quickabort sha1 just_cloned sm_path
>     [...]
>     die_if_unmatched "$quickabort" "$sha1"
>
> into version where we fold that die_if_unmatched() logic into the C
> code, and then ensure-core-worktree etc.

Sorry, that one makes no sense since it's an artifact of the shellscript
implementation.

But I tested the below on top of master, and it passes all tests, which
isn't very promising...

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 4a0890954e9..e749008f13a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2783,40 +2783,6 @@ 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)
-{
-	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);
-
-	if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
-		char *cfg_file, *abs_path;
-		const char *rel_path;
-		struct strbuf sb = STRBUF_INIT;
-
-		cfg_file = repo_git_path(&subrepo, "config");
-
-		abs_path = absolute_pathdup(path);
-		rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
-
-		git_config_set_in_file(cfg_file, "core.worktree", rel_path);
-
-		free(cfg_file);
-		free(abs_path);
-		strbuf_release(&sb);
-	}
-
-	return 0;
-}
-
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 {
 	int i;
@@ -3391,7 +3357,6 @@ static struct cmd_struct commands[] = {
 	{"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},
diff --git a/git-submodule.sh b/git-submodule.sh
index 652861aa66a..460cbd4e265 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -387,8 +387,6 @@ cmd_update()
 	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

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

* Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C
  2022-02-03  8:15               ` Ævar Arnfjörð Bjarmason
@ 2022-02-03 17:35                 ` Glen Choo
  0 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-03 17:35 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla

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

> On Thu, Feb 03 2022, Ævar Arnfjörð Bjarmason wrote:
>
>> On Wed, Feb 02 2022, Glen Choo wrote:
>>
>>> - Junio pointed out that this conflicts with
>>>   es/superproject-aware-submodules [2]. I'm not sure which should be
>>>   based on which. If this does end up being based on
>>>   es/superproject-aware-submodules, it would probably be easier to
>>>   rebase as a series of smaller patches. Atharva noted that the
>>>   conflicts are mild though, so maybe it's not so bad.
>>
>> I think it makes sense to get this series through first, i.e. the
>> (supposedly) no-behavior-changing one, and then one that introduces new
>> submodule behavior.
>>
>> Particularly because for es/superproject-aware-submodules the main
>> selling point is a performance improvement, which as I noted in the
>> review for it I've been unable to observe once the C<->sh layer goes
>> away.
>>
>> I'm not saying it's not there, just that I don't think it's been shown
>> so far, IIRC there was some reference to some Google-internal network FS
>> that might or might not be helped by it...

I'll let the experts chime in, I don't think I can add anything useful
to the discussion.

>>> My ideal patch organization would be something like:
>>>
>>> - wrap some existing command in "git submodule--helper update" (probably
>>>   run-update-procedure)
>>> - absorb the surrounding sh code into "git submodule--helper
>>>   update" one command at-a-time i.e. deprecating and removing the
>>>   commands one at a time - instead of deprecating and removing them all
>>>   at once (like this patch), or deprecating all at once and removing
>>>   them one at a time (like v1).
>>
>> I do think atomic changes that don't leave dead code for removal later
>> are easier to read & reason about, whatever else is reorganized.
>>
>> I.e. not to have something where we replace all the running code, and
>> then remove already-unused code later.

I agree - otherwise patches aren't self-contianed and harder to merge.

>>> - If you think this alternative organization would be helpful for you
>>>   too, I will attempt it. This will take a while, but by the end you and
>>>   I will have effectively reviewed all of the code, so it should be easy
>>>   to finish up the review.
>>
>> I think it might, but I really don't know. We'll just have to see, so if
>> you want to take a stab at it that would be great.
>>
>> Maybe it's a good way forward. E.g. as af first small step we could turn:
>>
>>     while read -r quickabort sha1 just_cloned sm_path
>>     [...]
>>     die_if_unmatched "$quickabort" "$sha1"
>>
>> into version where we fold that die_if_unmatched() logic into the C
>> code, and then ensure-core-worktree etc.
>
> Sorry, that one makes no sense since it's an artifact of the shellscript
> implementation.

Whether or not it makes sense, I think it gets the point across i.e.
that we think folding into C can be done incrementally.

>>> - Otherwise e.g. maybe this is a huge waste of time, or you're already
>>>   really confident in the correctness of the sh -> c when you reviewed
>>>   the original patch, etc, I'll just review this patch as-is. I'd
>>>   appreciate any tips and tricks that might help :)
>>
>> I'm not really confident in it.
>>
>> I've read it, tested it as well as I could manage etc. but it's still a
>> very large change.
[...]
> But I tested the below on top of master, and it passes all tests, which
> isn't very promising...

A good enough (i.e. extremely comprehensive) test suite will all but
guarantee that no behavior has changed. Our test suite is nowhere near
that level and probably never will be, so we can't trust that things are
correct even if it passes tests.

So, for the sake of reviewability, I'll take a stab at reorganizing.
I'll be taking a long flight anyway, so I'll have big chunk of
non-company time to spend on this ;)

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

* [PATCH v6 00/16] submodule: convert the rest of 'update' to C
  2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
                           ` (8 preceding siblings ...)
  2022-01-28 12:56         ` [PATCH v5 9/9] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
@ 2022-02-08  8:39         ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 01/16] submodule--helper: get remote names from any repository Glen Choo
                             ` (16 more replies)
  9 siblings, 17 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Here is a split-up of the last patch as I promised :) The intent was to
minimize the diff vs v5 instead of getting to a perfect end state; this
will almost certainly need a reroll.

This split-up isn't as complete as I had hoped - the last patch is still
rather large, but breaking that up already took more time than
everything else combined, and I think this organization is already
easier to review than v5. I'd appreciate any suggestions on how this
could be done [1] :) If inspiration strikes, I'll break it up further in
a reroll, but as of right now, I'm out of ideas.

I did some minimal review of the implementation, but I plan to do more
after sending this to the list e.g. I have not revisited the earlier
preparatory patches to see if my patches make sense with them. Where I
found issues, I left NEEDSWORK comments instead of fixing them because
the result would be easier to diff with v5 (the only differences between
this tree and v5's is the NEEDSWORK comments). I plan to fix
implementation issues (once we've spotted them in reivew) and the
NEEDSWORKs in the next reroll.

Let me know if the trailers make sense - this is my first time reworking
someone else's changes, so I don't think I did a perfect job at
attributing work. I also had to fiddle with the Signed-off-by to make
them resemble the v5 patches' Signed-off-by (ar/submodule-update seemed
to order them differently from v5, I'm not sure why).

[1] The difficulty in the last patch comes from the fact that we have
the --recursive flag handling in shell, and we are piping update-clone
into {run-update-procedure + --recursive flag handling}. Because of how
"git submodule" parses args, it is tricky to implement --recursive
without bypassing "git submodule" with "git submodule--helper update"
(the final patch does this bypass). On the other hand, it's difficult to
leave --recursive for last, because we would need to mimic the piping
and exiting behavior around update-clone and run-update-procedure.

Changes in v6:
- Split up last patch of v5 into patches 9-16.
- Patches 9-10 are preparatory work on submodule--helper.c.
- Patches 11-14 contain sh -> c conversions of the git-submodule.sh code
  surrounding update-clone and run-update-procedure.
- Patch 15 moves functions around in order to shrink patch 16's diff
  - If reviewers prefer, we could choose _not_ to move the functions
    around. If so, we can drop patch 15.
- Patch 16 introduces "submodule--helper update". Change the commit
  message to drop references to work done in previous patches.
- Add NEEDSWORK comments for potential issues. These will be cleaned up
  in the next version.

Atharva Raykar (6):
  submodule--helper: get remote names from any repository
  submodule--helper: refactor get_submodule_displaypath()
  submodule--helper: allow setting superprefix for init_submodule()
  submodule--helper: run update using child process struct
  builtin/submodule--helper.c: reformat designated initializers
  submodule: move core cmd_update() logic to C

Glen Choo (7):
  submodule--helper: remove update-module-mode
  submodule--helper: reorganize code for sh to C conversion
  submodule--helper run-update-procedure: remove --suboid
  submodule--helper run-update-procedure: learn --remote
  submodule--helper: remove ensure-core-worktree
  submodule--helper update-clone: learn --init
  submodule--helper: move functions around

Ævar Arnfjörð Bjarmason (3):
  builtin/submodule--helper.c: rename option variables to "opt"
  submodule--helper: don't use bitfield indirection for parse_options()
  submodule tests: test for init and update failure output

 builtin/submodule--helper.c    | 709 +++++++++++++++++++--------------
 git-submodule.sh               | 145 +------
 t/t7406-submodule-update.sh    |  14 +-
 t/t7408-submodule-reference.sh |  14 +-
 4 files changed, 447 insertions(+), 435 deletions(-)

Range-diff against v5:
 1:  b45e49810a =  1:  86ffb53742 submodule--helper: get remote names from any repository
 2:  8974329fc5 =  2:  2a40266b7a submodule--helper: refactor get_submodule_displaypath()
 3:  bd92e00c05 =  3:  cd851c8eb5 submodule--helper: allow setting superprefix for init_submodule()
 4:  909cb60cd4 =  4:  bfe5cad136 submodule--helper: run update using child process struct
 5:  36575b2f25 =  5:  72c257fdbf builtin/submodule--helper.c: reformat designated initializers
 6:  a743003e09 =  6:  4b5f703fde builtin/submodule--helper.c: rename option variables to "opt"
 7:  3a449d00b9 =  7:  f1d21f5b1c submodule--helper: don't use bitfield indirection for parse_options()
 8:  7da45dde67 =  8:  9d32a73fc3 submodule tests: test for init and update failure output
 -:  ---------- >  9:  087bf43aba submodule--helper: remove update-module-mode
 -:  ---------- > 10:  4eb2893a19 submodule--helper: reorganize code for sh to C conversion
 -:  ---------- > 11:  c08e7781e3 submodule--helper run-update-procedure: remove --suboid
 -:  ---------- > 12:  2419c37184 submodule--helper run-update-procedure: learn --remote
 -:  ---------- > 13:  6691fd3648 submodule--helper: remove ensure-core-worktree
 -:  ---------- > 14:  d2c9c356e9 submodule--helper update-clone: learn --init
 -:  ---------- > 15:  a5cde5e084 submodule--helper: move functions around
 9:  251a0b4241 ! 16:  f0551a37e5 submodule: move core cmd_update() logic to C
    @@ Commit message
         `submodule--helper update`, with a modified `--recursive-prefix` and
         `--prefix` parameter.
     
    -    We also introduce `update_submodules2()` and `update_submodule2()`
    -    which will supersede `update_submodules()` and `update_submodule()`.
    -
    -    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>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
         Signed-off-by: Junio C Hamano <gitster@pobox.com>
    +    Signed-off-by: Glen Choo <chooglen@google.com>
     
      ## builtin/submodule--helper.c ##
    -@@ builtin/submodule--helper.c: static char *get_default_remote(void)
    - 	return repo_get_default_remote(the_repository);
    - }
    - 
    --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]);
    -@@ 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: struct submodule_update_clone {
      	const char *prefix;
      	int single_branch;
    @@ builtin/submodule--helper.c: struct submodule_update_clone {
      	struct update_clone_data *update_clone;
      	int update_clone_nr; int update_clone_alloc;
      
    +@@ builtin/submodule--helper.c: struct submodule_update_clone {
    + 	int failed_clones_nr, failed_clones_alloc;
    + 
    + 	int max_jobs;
    +-	unsigned int init;
    + };
    + #define SUBMODULE_UPDATE_CLONE_INIT { \
    + 	.list = MODULE_LIST_INIT, \
     @@ builtin/submodule--helper.c: struct submodule_update_clone {
      }
      
    @@ builtin/submodule--helper.c: struct update_data {
      	unsigned int quiet;
      	unsigned int nofetch;
      	unsigned int just_cloned;
    -+	unsigned int remote;
    + 	unsigned int remote;
     +	unsigned int recursive;
     +	unsigned int progress;
     +	unsigned int dissociate;
    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u
      	char *oid = oid_to_hex(&ud->oid);
      	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 (ud->update_strategy.type) {
     +	switch (strategy.type) {
      	case SM_UPDATE_CHECKOUT:
      		cp.git_cmd = 1;
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -		ucd->sub->path);
     -}
     -
    --static int update_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_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 opt = 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", &opt.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", &opt.references, N_("repo"),
    --			   N_("reference repository")),
    --		OPT_BOOL(0, "dissociate", &opt.dissociate,
    --			   N_("use --reference only while cloning")),
    --		OPT_STRING(0, "depth", &opt.depth, "<depth>",
    --			   N_("create a shallow clone truncated to the "
    --			      "specified number of revisions")),
    --		OPT_INTEGER('j', "jobs", &opt.max_jobs,
    --			    N_("parallel jobs")),
    --		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
    --			    N_("whether the initial clone should follow the shallow recommendation")),
    --		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
    --		OPT_BOOL(0, "progress", &opt.progress,
    --			    N_("force cloning progress")),
    --		OPT_BOOL(0, "require-init", &opt.require_init,
    --			   N_("disallow cloning into non-empty directory")),
    --		OPT_BOOL(0, "single-branch", &opt.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
    --	};
    --	opt.prefix = prefix;
    --
    --	update_clone_config_from_gitmodules(&opt.max_jobs);
    --	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
    --			die(_("bad value for update parameter"));
    --
    --	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
    --		return 1;
    --
    --	if (pathspec.nr)
    --		opt.warn_if_uninitialized = 1;
    --
    --	return update_submodules(&opt);
    --}
    --
    +-/*
    +- * NEEDSWORK: Use a forward declaration to avoid moving
    +- * run_update_procedure() (which will be removed soon).
    +- */
    +-static int update_submodule2(struct update_data *update_data);
     -static int run_update_procedure(int argc, const char **argv, const char *prefix)
     -{
     -	char *prefixed_path, *update = NULL;
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
     -			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
     -			       parse_opt_object_id),
    --		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
    --			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
    --			       parse_opt_object_id),
    +-		OPT_BOOL(0, "remote", &opt.remote,
    +-			 N_("use SHA-1 of submodule's remote tracking branch")),
     -		OPT_END()
     -	};
     -
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -					    &opt.update_strategy);
     -
     -	free(prefixed_path);
    --
    --	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
    --		return do_run_update_procedure(&opt);
    --
    --	return 3;
    +-	return update_submodule2(&opt);
     -}
     -
     -static int resolve_relative_path(int argc, const char **argv, const char *prefix)
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
      static const char *remote_submodule_branch(const char *path)
      {
      	const struct submodule *sub;
    -@@ builtin/submodule--helper.c: 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 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);
    - 
    -@@ builtin/submodule--helper.c: static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
    - 		free(abs_path);
    - 		strbuf_release(&sb);
    - 	}
    --
    --	return 0;
    - }
    - 
    - static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
     @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char **argv, const char *prefix)
      	return !!ret;
      }
      
    +-/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
    +-static int update_submodule2(struct update_data *update_data)
     +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);
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +}
     +
     +static int update_submodule(struct update_data *update_data)
    -+{
    + {
     +	char *prefixed_path;
     +
    -+	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,
     +					update_data->sm_path);
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +							     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)
    + 	/* NEEDSWORK: fix the style issues e.g. braces */
    + 	if (update_data->just_cloned) {
    + 		oidcpy(&update_data->suboid, null_oid());
    +@@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *update_data)
    + 	}
    + 
    + 	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
    +-		return do_run_update_procedure(update_data);
     +		if (run_update_procedure(update_data))
     +			return 1;
    -+
    + 
    +-	return 3;
     +	if (update_data->recursive) {
     +		struct child_process cp = CHILD_PROCESS_INIT;
     +		struct update_data next = *update_data;
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +	}
     +
     +	return 0;
    -+}
    -+
    + }
    + 
    +-static int update_submodules(struct submodule_update_clone *suc)
     +static int update_submodules(struct update_data *update_data)
    -+{
    + {
    +-	int i;
     +	int i, res = 0;
     +	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
    -+
    + 
    +-	run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
     +	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_start_failure,
    +-				   update_clone_task_finished, suc, "submodule",
     +				   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.
    -+	 */
    + 				   "parallel/update");
    + 
    + 	/*
    +@@ builtin/submodule--helper.c: static int update_submodules(struct submodule_update_clone *suc)
    + 	 *   checkout involve more straightforward sequential I/O.
    + 	 * - the listener can avoid doing any work if fetching failed.
    + 	 */
    +-	if (suc->quickstop)
    +-		return 1;
     +	if (suc.quickstop) {
     +		res = 1;
     +		goto cleanup;
     +	}
    -+
    + 
    +-	for (i = 0; i < suc->update_clone_nr; i++)
    +-		update_submodule(&suc->update_clone[i]);
     +	for (i = 0; i < suc.update_clone_nr; i++) {
     +		struct update_clone_data ucd = suc.update_clone[i];
    -+
    + 
    +-	return 0;
     +		oidcpy(&update_data->oid, &ucd.oid);
     +		update_data->just_cloned = ucd.just_cloned;
     +		update_data->sm_path = ucd.sub->path;
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +cleanup:
     +	string_list_clear(&update_data->references, 0);
     +	return res;
    -+}
    -+
    + }
    + 
    +-static int update_clone(int argc, const char **argv, const char *prefix)
     +static int module_update(int argc, const char **argv, const char *prefix)
    -+{
    -+	const char *update = NULL;
    -+	struct pathspec pathspec;
    + {
    + 	const char *update = NULL;
    + 	struct pathspec pathspec;
    +-	struct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;
     +	struct update_data opt = UPDATE_DATA_INIT;
    -+
    -+	struct option module_update_clone_options[] = {
    + 
    ++	/* NEEDSWORK: update names and strings */
    + 	struct option module_update_clone_options[] = {
     +		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
    -+		OPT_BOOL(0, "init", &opt.init,
    -+			 N_("initialize uninitialized submodules before update")),
    + 		OPT_BOOL(0, "init", &opt.init,
    + 			 N_("initialize uninitialized submodules before update")),
    +-		OPT_STRING(0, "prefix", &prefix,
     +		OPT_BOOL(0, "remote", &opt.remote,
     +			 N_("use SHA-1 of submodule's remote tracking branch")),
     +		OPT_BOOL(0, "recursive", &opt.recursive,
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +		OPT_BOOL('N', "no-fetch", &opt.nofetch,
     +			 N_("don't fetch new objects from the remote site")),
     +		OPT_STRING(0, "prefix", &opt.prefix,
    -+			   N_("path"),
    -+			   N_("path into the working tree")),
    -+		OPT_STRING(0, "recursive-prefix", &opt.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", &opt.references, N_("repo"),
    + 			   N_("path"),
    + 			   N_("path into the working tree")),
    + 		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix,
    +@@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv, const char *prefix)
    + 			   N_("string"),
    + 			   N_("rebase, merge, checkout or none")),
    + 		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
    +-			   N_("reference repository")),
     +				N_("reference repository")),
    -+		OPT_BOOL(0, "dissociate", &opt.dissociate,
    + 		OPT_BOOL(0, "dissociate", &opt.dissociate,
    +-			   N_("use --reference only while cloning")),
    +-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
    +-			   N_("create a shallow clone truncated to the "
    +-			      "specified number of revisions")),
     +			 N_("use --reference only while cloning")),
     +		OPT_INTEGER(0, "depth", &opt.depth,
     +			    N_("create a shallow clone truncated to the "
     +			       "specified number of revisions")),
    -+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
    -+			    N_("parallel jobs")),
    -+		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
    + 		OPT_INTEGER('j', "jobs", &opt.max_jobs,
    + 			    N_("parallel jobs")),
    + 		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
    +-			    N_("whether the initial clone should follow the shallow recommendation")),
     +			 N_("whether the initial clone should follow the shallow recommendation")),
    -+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
    -+		OPT_BOOL(0, "progress", &opt.progress,
    + 		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
    + 		OPT_BOOL(0, "progress", &opt.progress,
    +-			    N_("force cloning progress")),
     +			 N_("force cloning progress")),
    -+		OPT_BOOL(0, "require-init", &opt.require_init,
    + 		OPT_BOOL(0, "require-init", &opt.require_init,
    +-			   N_("disallow cloning into non-empty directory")),
     +			 N_("disallow cloning into non-empty directory")),
    -+		OPT_BOOL(0, "single-branch", &opt.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(&opt.max_jobs);
    -+	git_config(git_update_clone_config, &opt.max_jobs);
    -+
    -+	argc = parse_options(argc, argv, prefix, module_update_clone_options,
    -+			     git_submodule_helper_usage, 0);
    + 		OPT_BOOL(0, "single-branch", &opt.single_branch,
    + 			 N_("clone only one branch, HEAD or --branch")),
    + 		OPT_END()
    +@@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv, const char *prefix)
    + 		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
    + 		NULL
    + 	};
    +-	opt.prefix = prefix;
    + 
    + 	update_clone_config_from_gitmodules(&opt.max_jobs);
    + 	git_config(git_update_clone_config, &opt.max_jobs);
    + 
    + 	argc = parse_options(argc, argv, prefix, module_update_clone_options,
    + 			     git_submodule_helper_usage, 0);
     +	oidcpy(&opt.oid, null_oid());
     +	oidcpy(&opt.suboid, null_oid());
    -+
    -+	if (update)
    + 
    + 	if (update)
    +-		if (parse_submodule_update_strategy(update, &opt.update) < 0)
     +		if (parse_submodule_update_strategy(update,
     +						    &opt.update_strategy) < 0)
    -+			die(_("bad value for update parameter"));
    -+
    -+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
    -+		return 1;
    -+
    -+	if (pathspec.nr)
    -+		opt.warn_if_uninitialized = 1;
    -+
    -+	if (opt.init) {
    -+		struct module_list list = MODULE_LIST_INIT;
    -+		struct init_cb info = INIT_CB_INIT;
    -+
    -+		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
    -+		info.superprefix = opt.recursive_prefix;
    -+		if (opt.quiet)
    -+			info.flags |= OPT_QUIET;
    -+
    -+		for_each_listed_submodule(&list, init_submodule_cb, &info);
    -+	}
    -+
    -+	return update_submodules(&opt);
    -+}
    -+
    - struct add_data {
    - 	const char *prefix;
    - 	const char *branch;
    + 			die(_("bad value for update parameter"));
    + 
    + 	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {
      	{"name", module_name, 0},
      	{"clone", module_clone, 0},
      	{"add", module_add, SUPPORT_SUPER_PREFIX},
    --	{"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},
     +	{"update", module_update, 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},
     
      ## 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
      
    --	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"} submodule--helper update-clone \
     +	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
    -+		${GIT_QUIET:+--quiet} \
    + 		${GIT_QUIET:+--quiet} \
    +-		${progress:+"--progress"} \
     +		${force:+--force} \
     +		${progress:+--progress} \
     +		${dissociate:+--dissociate} \
     +		${remote:+--remote} \
     +		${recursive:+--recursive} \
    -+		${init:+--init} \
    + 		${init:+--init} \
     +		${require_init:+--require-init} \
     +		${nofetch:+--no-fetch} \
      		${wt_prefix:+--prefix "$wt_prefix"} \
    @@ git-submodule.sh: cmd_update()
     -	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
    +-		if test $just_cloned -eq 0
     -		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 \
    @@ git-submodule.sh: cmd_update()
     -			  ${update:+--update "$update"} \
     -			  ${prefix:+--recursive-prefix "$prefix"} \
     -			  ${sha1:+--oid "$sha1"} \
    --			  ${subsha1:+--suboid "$subsha1"} \
    +-			  ${remote:+--remote} \
     -			  "--" \
     -			  "$sm_path")
     -

base-commit: b23dac905bde28da47543484320db16312c87551
-- 
2.33.GIT


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

* [PATCH v6 01/16] submodule--helper: get remote names from any repository
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 02/16] submodule--helper: refactor get_submodule_displaypath() Glen Choo
                             ` (15 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

`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>
Helped-by: Glen Choo <chooglen@google.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 c5d3fc3817..4c7c1e1432 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -29,11 +29,14 @@
 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)
 {
 	char *dest = NULL, *ret;
 	struct strbuf sb = STRBUF_INIT;
-	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+	struct ref_store *store = get_main_ref_store(repo);
+	int ignore_errno;
+	const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
+						      NULL, &ignore_errno);
 
 	if (!refname)
 		die(_("No such ref: %s"), "HEAD");
@@ -46,7 +49,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 +58,19 @@ static char *get_default_remote(void)
 	return ret;
 }
 
+static char *get_default_remote_submodule(const char *module_path)
+{
+	struct repository subrepo;
+
+	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
+	return repo_get_default_remote(&subrepo);
+}
+
+static char *get_default_remote(void)
+{
+	return repo_get_default_remote(the_repository);
+}
+
 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.33.GIT


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

* [PATCH v6 02/16] submodule--helper: refactor get_submodule_displaypath()
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
  2022-02-08  8:39           ` [PATCH v6 01/16] submodule--helper: get remote names from any repository Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 03/16] submodule--helper: allow setting superprefix for init_submodule() Glen Choo
                             ` (14 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 4c7c1e1432..5efceb9d46 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.33.GIT


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

* [PATCH v6 03/16] submodule--helper: allow setting superprefix for init_submodule()
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
  2022-02-08  8:39           ` [PATCH v6 01/16] submodule--helper: get remote names from any repository Glen Choo
  2022-02-08  8:39           ` [PATCH v6 02/16] submodule--helper: refactor get_submodule_displaypath() Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 04/16] submodule--helper: run update using child process struct Glen Choo
                             ` (13 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5efceb9d46..09cda67c1e 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 { 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.33.GIT


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

* [PATCH v6 04/16] submodule--helper: run update using child process struct
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (2 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 03/16] submodule--helper: allow setting superprefix for init_submodule() Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 05/16] builtin/submodule--helper.c: reformat designated initializers Glen Choo
                             ` (12 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 09cda67c1e..db71e6f4ec 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2344,47 +2344,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.33.GIT


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

* [PATCH v6 05/16] builtin/submodule--helper.c: reformat designated initializers
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (3 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 04/16] submodule--helper: run update using child process struct Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 06/16] builtin/submodule--helper.c: rename option variables to "opt" Glen Choo
                             ` (11 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

The second hunk here will make a subsequent commit's diff smaller, and
let's do the first and third hunks while we're at it so that we
consistently format all of these.

Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index db71e6f4ec..9f79bdf4d5 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1654,7 +1654,10 @@ struct module_clone_data {
 	unsigned int require_init: 1;
 	int single_branch;
 };
-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
+#define MODULE_CLONE_DATA_INIT { \
+	.reference = STRING_LIST_INIT_NODUP, \
+	.single_branch = -1, \
+}
 
 struct submodule_alternate_setup {
 	const char *submodule_name;
@@ -2047,7 +2050,9 @@ struct update_data {
 	unsigned int nofetch: 1;
 	unsigned int just_cloned: 1;
 };
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+}
 
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
 		struct strbuf *out, const char *displaypath)
@@ -3013,7 +3018,9 @@ struct add_data {
 	unsigned int progress: 1;
 	unsigned int dissociate: 1;
 };
-#define ADD_DATA_INIT { .depth = -1 }
+#define ADD_DATA_INIT { \
+	.depth = -1, \
+}
 
 static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
 {
-- 
2.33.GIT


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

* [PATCH v6 06/16] builtin/submodule--helper.c: rename option variables to "opt"
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (4 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 05/16] builtin/submodule--helper.c: reformat designated initializers Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 07/16] submodule--helper: don't use bitfield indirection for parse_options() Glen Choo
                             ` (10 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

Rename the "suc" variable in update_clone() to "opt", and do the same
for the "update_data" variable in run_update_procedure().

The only reason for this change is to make the subsequent commit's
diff smaller, by doing this rename we can "anchor" the diff better, as
it "borrow" most of the options declared here as-is as far as the diff
rename detection is concerned.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 74 ++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9f79bdf4d5..c2d4fd0347 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2517,36 +2517,36 @@ 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 submodule_update_clone opt = 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,
+		OPT_STRING(0, "recursive-prefix", &opt.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"),
+		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
 			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &suc.dissociate,
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
 			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
+		OPT_STRING(0, "depth", &opt.depth, "<depth>",
 			   N_("create a shallow clone truncated to the "
 			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
 			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
+		OPT_BOOL(0, "recommend-shallow", &opt.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,
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
 			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &suc.require_init,
+		OPT_BOOL(0, "require-init", &opt.require_init,
 			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &suc.single_branch,
+		OPT_BOOL(0, "single-branch", &opt.single_branch,
 			 N_("clone only one branch, HEAD or --branch")),
 		OPT_END()
 	};
@@ -2555,32 +2555,32 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
 		NULL
 	};
-	suc.prefix = prefix;
+	opt.prefix = prefix;
 
-	update_clone_config_from_gitmodules(&suc.max_jobs);
-	git_config(git_update_clone_config, &suc.max_jobs);
+	update_clone_config_from_gitmodules(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.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)
+		if (parse_submodule_update_strategy(update, &opt.update) < 0)
 			die(_("bad value for update parameter"));
 
-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
 		return 1;
 
 	if (pathspec.nr)
-		suc.warn_if_uninitialized = 1;
+		opt.warn_if_uninitialized = 1;
 
-	return update_submodules(&suc);
+	return update_submodules(&opt);
 }
 
 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 update_data opt = UPDATE_DATA_INIT;
 
 	struct option options[] = {
 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
@@ -2589,20 +2589,20 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 			 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_INTEGER(0, "depth", &opt.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"),
+		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
 			   N_("path into the working tree, across nested "
 			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
+		OPT_CALLBACK_F(0, "oid", &opt.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"),
+		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
 			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
 			       parse_opt_object_id),
 		OPT_END()
@@ -2618,27 +2618,27 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	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];
+	opt.force = !!force;
+	opt.quiet = !!quiet;
+	opt.nofetch = !!nofetch;
+	opt.just_cloned = !!just_cloned;
+	opt.sm_path = argv[0];
 
-	if (update_data.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
+	if (opt.recursive_prefix)
+		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
 	else
-		prefixed_path = xstrdup(update_data.sm_path);
+		prefixed_path = xstrdup(opt.sm_path);
 
-	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
+	opt.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);
+	determine_submodule_update_strategy(the_repository, opt.just_cloned,
+					    opt.sm_path, update,
+					    &opt.update_strategy);
 
 	free(prefixed_path);
 
-	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data);
+	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
+		return do_run_update_procedure(&opt);
 
 	return 3;
 }
-- 
2.33.GIT


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

* [PATCH v6 07/16] submodule--helper: don't use bitfield indirection for parse_options()
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (5 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 06/16] builtin/submodule--helper.c: rename option variables to "opt" Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 08/16] submodule tests: test for init and update failure output Glen Choo
                             ` (9 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

Do away with the indirection of local variables added in
c51f8f94e5b (submodule--helper: run update procedures from C,
2021-08-24).

These were only needed because in C you can't get a pointer to a
single bit, so we were using intermediate variables instead.

This will also make a subsequent large commit's diff smaller.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c2d4fd0347..4a0890954e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2045,10 +2045,10 @@ struct update_data {
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
 	int depth;
-	unsigned int force: 1;
-	unsigned int quiet: 1;
-	unsigned int nofetch: 1;
-	unsigned int just_cloned: 1;
+	unsigned int force;
+	unsigned int quiet;
+	unsigned int nofetch;
+	unsigned int just_cloned;
 };
 #define UPDATE_DATA_INIT { \
 	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
@@ -2578,16 +2578,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 
 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 opt = UPDATE_DATA_INIT;
 
 	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,
+		OPT__QUIET(&opt.quiet,
+			   N_("suppress output for update by rebase or merge")),
+		OPT__FORCE(&opt.force, N_("force checkout updates"),
+			   0),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
 			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &just_cloned,
+		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
 			 N_("overrides update mode in case the repository is a fresh clone")),
 		OPT_INTEGER(0, "depth", &opt.depth, N_("depth for shallow fetch")),
 		OPT_STRING(0, "prefix", &prefix,
@@ -2618,10 +2619,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	if (argc != 1)
 		usage_with_options(usage, options);
 
-	opt.force = !!force;
-	opt.quiet = !!quiet;
-	opt.nofetch = !!nofetch;
-	opt.just_cloned = !!just_cloned;
 	opt.sm_path = argv[0];
 
 	if (opt.recursive_prefix)
-- 
2.33.GIT


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

* [PATCH v6 08/16] submodule tests: test for init and update failure output
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (6 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 07/16] submodule--helper: don't use bitfield indirection for parse_options() Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 09/16] submodule--helper: remove update-module-mode Glen Choo
                             ` (8 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

Amend some submodule tests to test for the failure output of "git
submodule [update|init]". The lack of such tests hid a regression in
an earlier version of a subsequent commit.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 t/t7406-submodule-update.sh    | 14 ++++++++++++--
 t/t7408-submodule-reference.sh | 14 +++++++++++++-
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 11cccbb333..7764c1c3cb 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -205,8 +205,18 @@ test_expect_success 'submodule update should fail due to local changes' '
 	 (cd submodule &&
 	  compare_head
 	 ) &&
-	 test_must_fail git submodule update submodule
-	)
+	 test_must_fail git submodule update submodule 2>../actual.raw
+	) &&
+	sed "s/^> //" >expect <<-\EOF &&
+	> error: Your local changes to the following files would be overwritten by checkout:
+	> 	file
+	> Please commit your changes or stash them before you switch branches.
+	> Aborting
+	> fatal: Unable to checkout OID in submodule path '\''submodule'\''
+	EOF
+	sed -e "s/checkout $SQ[^$SQ]*$SQ/checkout OID/" <actual.raw >actual &&
+	test_cmp expect actual
+
 '
 test_expect_success 'submodule update should throw away changes with --force ' '
 	(cd super &&
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index a3892f494b..c3a4545510 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -193,7 +193,19 @@ test_expect_success 'missing nested submodule alternate fails clone and submodul
 		cd supersuper-clone &&
 		check_that_two_of_three_alternates_are_used &&
 		# update of the submodule fails
-		test_must_fail git submodule update --init --recursive
+		cat >expect <<-\EOF &&
+		fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub'\''. Retry scheduled
+		fatal: submodule '\''sub-dissociate'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub-dissociate'\''. Retry scheduled
+		fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub'\'' a second time, aborting
+		fatal: Failed to recurse into submodule path ...
+		EOF
+		test_must_fail git submodule update --init --recursive 2>err &&
+		grep -e fatal: -e ^Failed err >actual.raw &&
+		sed -e "s/path $SQ[^$SQ]*$SQ/path .../" <actual.raw >actual &&
+		test_cmp expect actual
 	)
 '
 
-- 
2.33.GIT


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

* [PATCH v6 09/16] submodule--helper: remove update-module-mode
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (7 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 08/16] submodule tests: test for init and update failure output Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 10/16] submodule--helper: reorganize code for sh to C conversion Glen Choo
                             ` (7 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

This is dead code - it has not been used since c51f8f94e5
(submodule--helper: run update procedures from C, 2021-08-24).

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 4a0890954e..e0cc1c1b79 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1965,29 +1965,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;
@@ -3388,7 +3365,6 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
-	{"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},
-- 
2.33.GIT


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

* [PATCH v6 10/16] submodule--helper: reorganize code for sh to C conversion
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (8 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 09/16] submodule--helper: remove update-module-mode Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 11/16] submodule--helper run-update-procedure: remove --suboid Glen Choo
                             ` (6 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Introduce a function, update_submodule2(), that performs an update for
one submodule. This function will implement the functionality of
run-update-procedure and its surrounding shell code in submodule.sh.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index e0cc1c1b79..0b5120734a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2553,6 +2553,11 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	return update_submodules(&opt);
 }
 
+/*
+ * NEEDSWORK: Use a forward declaration to avoid moving
+ * run_update_procedure() (which will be removed soon).
+ */
+static int update_submodule2(struct update_data *update_data);
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
 {
 	char *prefixed_path, *update = NULL;
@@ -2610,11 +2615,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 					    &opt.update_strategy);
 
 	free(prefixed_path);
-
-	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
-		return do_run_update_procedure(&opt);
-
-	return 3;
+	return update_submodule2(&opt);
 }
 
 static int resolve_relative_path(int argc, const char **argv, const char *prefix)
@@ -2978,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 	return !!ret;
 }
 
+/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
+static int update_submodule2(struct update_data *update_data)
+{
+	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
+		return do_run_update_procedure(update_data);
+
+	return 3;
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
-- 
2.33.GIT


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

* [PATCH v6 11/16] submodule--helper run-update-procedure: remove --suboid
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (9 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 10/16] submodule--helper: reorganize code for sh to C conversion Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 12/16] submodule--helper run-update-procedure: learn --remote Glen Choo
                             ` (5 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Teach run-update-procedure to determine the oid of the submodule's HEAD
instead of doing it in git-subomdule.sh.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 12 +++++++++---
 git-submodule.sh            |  8 +-------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0b5120734a..a26477ce04 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2585,9 +2585,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
 			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
 			       parse_opt_object_id),
-		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
-			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
 		OPT_END()
 	};
 
@@ -2982,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 /* NEEDSWORK: this is a temporary name until we delete update_submodule() */
 static int update_submodule2(struct update_data *update_data)
 {
+	/* NEEDSWORK: fix the style issues e.g. braces */
+	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 (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
 		return do_run_update_procedure(update_data);
 
diff --git a/git-submodule.sh b/git-submodule.sh
index 652861aa66..d48c314f01 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -391,14 +391,9 @@ cmd_update()
 
 		displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
 
-		if test $just_cloned -eq 1
+		if test $just_cloned -eq 0
 		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"
@@ -426,7 +421,6 @@ cmd_update()
 			  ${update:+--update "$update"} \
 			  ${prefix:+--recursive-prefix "$prefix"} \
 			  ${sha1:+--oid "$sha1"} \
-			  ${subsha1:+--suboid "$subsha1"} \
 			  "--" \
 			  "$sm_path")
 
-- 
2.33.GIT


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

* [PATCH v6 12/16] submodule--helper run-update-procedure: learn --remote
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (10 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 11/16] submodule--helper run-update-procedure: remove --suboid Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 13/16] submodule--helper: remove ensure-core-worktree Glen Choo
                             ` (4 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Teach run-update-procedure to handle --remote instead of parsing
--remote in git-submodule.sh. As a result, "git submodule--helper
print-default-remote" has no more callers, so remove it.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 39 ++++++++++++++++++++++---------------
 git-submodule.sh            | 30 +---------------------------
 2 files changed, 24 insertions(+), 45 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a26477ce04..15ae986692 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);
 }
 
-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]);
@@ -2026,6 +2011,7 @@ struct update_data {
 	unsigned int quiet;
 	unsigned int nofetch;
 	unsigned int just_cloned;
+	unsigned int remote;
 };
 #define UPDATE_DATA_INIT { \
 	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
@@ -2585,6 +2571,8 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
 			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
 			       parse_opt_object_id),
+		OPT_BOOL(0, "remote", &opt.remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
 		OPT_END()
 	};
 
@@ -2988,6 +2976,25 @@ static int update_submodule2(struct update_data *update_data)
 			    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)
 		return do_run_update_procedure(update_data);
 
@@ -3389,10 +3396,10 @@ 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},
+	/* NEEDSWORK: remote-branch is also obsolete */
 	{"remote-branch", resolve_remote_submodule_branch, 0},
 	{"push-check", push_check, 0},
 	{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --git a/git-submodule.sh b/git-submodule.sh
index d48c314f01..29fd69250d 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
 #
@@ -396,21 +382,6 @@ cmd_update()
 			just_cloned=
 		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} \
@@ -421,6 +392,7 @@ cmd_update()
 			  ${update:+--update "$update"} \
 			  ${prefix:+--recursive-prefix "$prefix"} \
 			  ${sha1:+--oid "$sha1"} \
+			  ${remote:+--remote} \
 			  "--" \
 			  "$sm_path")
 
-- 
2.33.GIT


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

* [PATCH v6 13/16] submodule--helper: remove ensure-core-worktree
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (11 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 12/16] submodule--helper run-update-procedure: learn --remote Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 14/16] submodule--helper update-clone: learn --init Glen Choo
                             ` (3 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Move the logic of "git submodule--helper ensure-core-worktree" into
run-update-procedure. Since the ensure-core-worktree command is
obsolete, remove it.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 13 +++----------
 git-submodule.sh            |  2 --
 2 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 15ae986692..a05aea5cd6 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2746,17 +2746,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 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);
 
@@ -2776,8 +2770,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 		free(abs_path);
 		strbuf_release(&sb);
 	}
-
-	return 0;
 }
 
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
@@ -2967,6 +2959,8 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 /* NEEDSWORK: this is a temporary name until we delete update_submodule() */
 static int update_submodule2(struct update_data *update_data)
 {
+	ensure_core_worktree(update_data->sm_path);
+
 	/* NEEDSWORK: fix the style issues e.g. braces */
 	if (update_data->just_cloned) {
 		oidcpy(&update_data->suboid, null_oid());
@@ -3390,7 +3384,6 @@ static struct cmd_struct commands[] = {
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
 	{"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},
diff --git a/git-submodule.sh b/git-submodule.sh
index 29fd69250d..aa9c898e1c 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -373,8 +373,6 @@ cmd_update()
 	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 0
-- 
2.33.GIT


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

* [PATCH v6 14/16] submodule--helper update-clone: learn --init
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (12 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 13/16] submodule--helper: remove ensure-core-worktree Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 15/16] submodule--helper: move functions around Glen Choo
                             ` (2 subsequent siblings)
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Teach "git submodule--helper update-clone" the --init flag and remove
the corresponding shell code.

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. So we instead run the
`init_submodule_cb()` callback over each submodule in the same process.

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

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 26 ++++++++++++++++++++++++++
 git-submodule.sh            |  9 +++------
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a05aea5cd6..5635f0c48b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1989,6 +1989,7 @@ struct submodule_update_clone {
 	int failed_clones_nr, failed_clones_alloc;
 
 	int max_jobs;
+	unsigned int init;
 };
 #define SUBMODULE_UPDATE_CLONE_INIT { \
 	.list = MODULE_LIST_INIT, \
@@ -2483,6 +2484,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	struct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;
 
 	struct option module_update_clone_options[] = {
+		OPT_BOOL(0, "init", &opt.init,
+			 N_("initialize uninitialized submodules before update")),
 		OPT_STRING(0, "prefix", &prefix,
 			   N_("path"),
 			   N_("path into the working tree")),
@@ -2536,6 +2539,29 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	if (pathspec.nr)
 		opt.warn_if_uninitialized = 1;
 
+	if (opt.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
+		info.superprefix = opt.recursive_prefix;
+		if (opt.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
 	return update_submodules(&opt);
 }
 
diff --git a/git-submodule.sh b/git-submodule.sh
index aa9c898e1c..3ccf2388bf 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -347,14 +347,11 @@ cmd_update()
 		shift
 	done
 
-	if test -n "$init"
-	then
-		cmd_init "--" "$@" || return
-	fi
-
 	{
-	git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \
+		${GIT_QUIET:+--quiet} \
 		${progress:+"--progress"} \
+		${init:+--init} \
 		${wt_prefix:+--prefix "$wt_prefix"} \
 		${prefix:+--recursive-prefix "$prefix"} \
 		${update:+--update "$update"} \
-- 
2.33.GIT


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

* [PATCH v6 15/16] submodule--helper: move functions around
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (13 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 14/16] submodule--helper update-clone: learn --init Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-08  8:39           ` [PATCH v6 16/16] submodule: move core cmd_update() logic to C Glen Choo
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

The next commit will change the internals of several functions and
arrange them in a more logical manner. Move these functions to their
final positions so that the diff is smaller.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 228 ++++++++++++++++++------------------
 1 file changed, 114 insertions(+), 114 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5635f0c48b..0ab8f9d49f 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2451,120 +2451,6 @@ static void update_submodule(struct update_clone_data *ucd)
 		ucd->sub->path);
 }
 
-static int update_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_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 opt = SUBMODULE_UPDATE_CLONE_INIT;
-
-	struct option module_update_clone_options[] = {
-		OPT_BOOL(0, "init", &opt.init,
-			 N_("initialize uninitialized submodules before update")),
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "recursive-prefix", &opt.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", &opt.references, N_("repo"),
-			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &opt.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &opt.max_jobs,
-			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
-		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
-		OPT_BOOL(0, "progress", &opt.progress,
-			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &opt.require_init,
-			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &opt.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
-	};
-	opt.prefix = prefix;
-
-	update_clone_config_from_gitmodules(&opt.max_jobs);
-	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
-			die(_("bad value for update parameter"));
-
-	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
-		return 1;
-
-	if (pathspec.nr)
-		opt.warn_if_uninitialized = 1;
-
-	if (opt.init) {
-		struct module_list list = MODULE_LIST_INIT;
-		struct init_cb info = INIT_CB_INIT;
-
-		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
-		info.superprefix = opt.recursive_prefix;
-		if (opt.quiet)
-			info.flags |= OPT_QUIET;
-
-		for_each_listed_submodule(&list, init_submodule_cb, &info);
-	}
-
-	return update_submodules(&opt);
-}
-
 /*
  * NEEDSWORK: Use a forward declaration to avoid moving
  * run_update_procedure() (which will be removed soon).
@@ -3021,6 +2907,120 @@ static int update_submodule2(struct update_data *update_data)
 	return 3;
 }
 
+static int update_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_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 opt = SUBMODULE_UPDATE_CLONE_INIT;
+
+	struct option module_update_clone_options[] = {
+		OPT_BOOL(0, "init", &opt.init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_STRING(0, "prefix", &prefix,
+			   N_("path"),
+			   N_("path into the working tree")),
+		OPT_STRING(0, "recursive-prefix", &opt.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", &opt.references, N_("repo"),
+			   N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
+			   N_("use --reference only while cloning")),
+		OPT_STRING(0, "depth", &opt.depth, "<depth>",
+			   N_("create a shallow clone truncated to the "
+			      "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
+			    N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
+			    N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &opt.require_init,
+			   N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &opt.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
+	};
+	opt.prefix = prefix;
+
+	update_clone_config_from_gitmodules(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
+			die(_("bad value for update parameter"));
+
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
+		return 1;
+
+	if (pathspec.nr)
+		opt.warn_if_uninitialized = 1;
+
+	if (opt.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
+		info.superprefix = opt.recursive_prefix;
+		if (opt.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
+	return update_submodules(&opt);
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
-- 
2.33.GIT


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

* [PATCH v6 16/16] submodule: move core cmd_update() logic to C
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (14 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 15/16] submodule--helper: move functions around Glen Choo
@ 2022-02-08  8:39           ` Glen Choo
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
  16 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-08  8:39 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 360 ++++++++++++++++++++++--------------
 git-submodule.sh            | 102 +---------
 2 files changed, 227 insertions(+), 235 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0ab8f9d49f..5085b28a2d 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1977,7 +1977,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;
 
@@ -1989,7 +1988,6 @@ struct submodule_update_clone {
 	int failed_clones_nr, failed_clones_alloc;
 
 	int max_jobs;
-	unsigned int init;
 };
 #define SUBMODULE_UPDATE_CLONE_INIT { \
 	.list = MODULE_LIST_INIT, \
@@ -2001,6 +1999,7 @@ struct submodule_update_clone {
 }
 
 struct update_data {
+	const char *prefix;
 	const char *recursive_prefix;
 	const char *sm_path;
 	const char *displaypath;
@@ -2008,14 +2007,54 @@ struct update_data {
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
 	int depth;
+	int recommend_shallow;
+	int single_branch;
+	int max_jobs;
+	unsigned int init;
 	unsigned int force;
 	unsigned int quiet;
 	unsigned int nofetch;
 	unsigned int just_cloned;
 	unsigned int remote;
+	unsigned int recursive;
+	unsigned int progress;
+	unsigned int dissociate;
+	unsigned int require_init;
+	unsigned warn_if_uninitialized ;
+	struct string_list references;
+	struct module_list list;
 };
 #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,
@@ -2316,8 +2355,15 @@ static int run_update_command(struct update_data *ud, int subforce)
 	struct child_process cp = CHILD_PROCESS_INIT;
 	char *oid = oid_to_hex(&ud->oid);
 	int must_die_on_failure = 0;
+	struct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;
+
+	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) {
+	switch (strategy.type) {
 	case SM_UPDATE_CHECKOUT:
 		cp.git_cmd = 1;
 		strvec_pushl(&cp.args, "checkout", "-q", NULL);
@@ -2340,55 +2386,54 @@ 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) {
+		switch (strategy.type) {
 		case SM_UPDATE_CHECKOUT:
-			printf(_("Unable to checkout '%s' in submodule path '%s'"),
-			       oid, ud->displaypath);
+			die_message(_("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);
+			if (!must_die_on_failure)
+				break;
+			die(_("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);
+			if (!must_die_on_failure)
+				break;
+			die(_("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);
+			if (!must_die_on_failure)
+				break;
+			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(&ud->update_strategy));
+			    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 */
 		return 1;
 	}
 
-	switch (ud->update_strategy.type) {
+	if (ud->quiet)
+		return 0;
+
+	switch (strategy.type) {
 	case SM_UPDATE_CHECKOUT:
 		printf(_("Submodule path '%s': checked out '%s'\n"),
 		       ud->displaypath, oid);
@@ -2403,17 +2448,17 @@ static int run_update_command(struct update_data *ud, int subforce)
 		break;
 	case SM_UPDATE_COMMAND:
 		printf(_("Submodule path '%s': '%s %s'\n"),
-		       ud->displaypath, ud->update_strategy.command, oid);
+		       ud->displaypath, strategy.command, oid);
 		break;
 	default:
 		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&ud->update_strategy));
+		    submodule_strategy_to_string(&strategy));
 	}
 
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud)
+static int run_update_procedure(struct update_data *ud)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2443,89 +2488,6 @@ 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)
-{
-	fprintf(stdout, "dummy %s %d\t%s\n",
-		oid_to_hex(&ucd->oid),
-		ucd->just_cloned,
-		ucd->sub->path);
-}
-
-/*
- * NEEDSWORK: Use a forward declaration to avoid moving
- * run_update_procedure() (which will be removed soon).
- */
-static int update_submodule2(struct update_data *update_data);
-static int run_update_procedure(int argc, const char **argv, const char *prefix)
-{
-	char *prefixed_path, *update = NULL;
-	struct update_data opt = UPDATE_DATA_INIT;
-
-	struct option options[] = {
-		OPT__QUIET(&opt.quiet,
-			   N_("suppress output for update by rebase or merge")),
-		OPT__FORCE(&opt.force, N_("force checkout updates"),
-			   0),
-		OPT_BOOL('N', "no-fetch", &opt.nofetch,
-			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
-			 N_("overrides update mode in case the repository is a fresh clone")),
-		OPT_INTEGER(0, "depth", &opt.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", &opt.recursive_prefix, N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
-			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_BOOL(0, "remote", &opt.remote,
-			 N_("use SHA-1 of submodule's remote tracking branch")),
-		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);
-
-	opt.sm_path = argv[0];
-
-	if (opt.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
-	else
-		prefixed_path = xstrdup(opt.sm_path);
-
-	opt.displaypath = get_submodule_displaypath(prefixed_path, prefix);
-
-	determine_submodule_update_strategy(the_repository, opt.just_cloned,
-					    opt.sm_path, update,
-					    &opt.update_strategy);
-
-	free(prefixed_path);
-	return update_submodule2(&opt);
-}
-
-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;
@@ -2868,11 +2830,66 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 	return !!ret;
 }
 
-/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
-static int update_submodule2(struct update_data *update_data)
+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;
+
 	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);
+
 	/* NEEDSWORK: fix the style issues e.g. braces */
 	if (update_data->just_cloned) {
 		oidcpy(&update_data->suboid, null_oid());
@@ -2902,18 +2919,55 @@ static int update_submodule2(struct update_data *update_data)
 	}
 
 	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
-		return do_run_update_procedure(update_data);
+		if (run_update_procedure(update_data))
+			return 1;
 
-	return 3;
+	if (update_data->recursive) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+		struct update_data next = *update_data;
+		int res;
+
+		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 */
+		res = run_command(&cp);
+		if (!res)
+			return 0;
+		die_message(_("Failed to recurse into submodule path '%s'"),
+			    update_data->displaypath);
+		if (res == 128)
+			exit(res);
+		else if (res)
+			return 1;
+	}
+
+	return 0;
 }
 
-static int update_submodules(struct submodule_update_clone *suc)
+static int update_submodules(struct update_data *update_data)
 {
-	int i;
+	int i, res = 0;
+	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
 
-	run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
+	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",
+				   update_clone_task_finished, &suc, "submodule",
 				   "parallel/update");
 
 	/*
@@ -2924,25 +2978,45 @@ static int update_submodules(struct submodule_update_clone *suc)
 	 *   checkout involve more straightforward sequential I/O.
 	 * - the listener can avoid doing any work if fetching failed.
 	 */
-	if (suc->quickstop)
-		return 1;
+	if (suc.quickstop) {
+		res = 1;
+		goto cleanup;
+	}
 
-	for (i = 0; i < suc->update_clone_nr; i++)
-		update_submodule(&suc->update_clone[i]);
+	for (i = 0; i < suc.update_clone_nr; i++) {
+		struct update_clone_data ucd = suc.update_clone[i];
 
-	return 0;
+		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;
+	}
+
+cleanup:
+	string_list_clear(&update_data->references, 0);
+	return res;
 }
 
-static int update_clone(int argc, const char **argv, const char *prefix)
+static int module_update(int argc, const char **argv, const char *prefix)
 {
 	const char *update = NULL;
 	struct pathspec pathspec;
-	struct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;
+	struct update_data opt = UPDATE_DATA_INIT;
 
+	/* NEEDSWORK: update names and strings */
 	struct option module_update_clone_options[] = {
+		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
 			 N_("initialize uninitialized submodules before update")),
-		OPT_STRING(0, "prefix", &prefix,
+		OPT_BOOL(0, "remote", &opt.remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &opt.recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_STRING(0, "prefix", &opt.prefix,
 			   N_("path"),
 			   N_("path into the working tree")),
 		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix,
@@ -2953,21 +3027,21 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 			   N_("string"),
 			   N_("rebase, merge, checkout or none")),
 		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
-			   N_("reference repository")),
+				N_("reference repository")),
 		OPT_BOOL(0, "dissociate", &opt.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
+			 N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &opt.depth,
+			    N_("create a shallow clone truncated to the "
+			       "specified number of revisions")),
 		OPT_INTEGER('j', "jobs", &opt.max_jobs,
 			    N_("parallel jobs")),
 		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
+			 N_("whether the initial clone should follow the shallow recommendation")),
 		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
 		OPT_BOOL(0, "progress", &opt.progress,
-			    N_("force cloning progress")),
+			 N_("force cloning progress")),
 		OPT_BOOL(0, "require-init", &opt.require_init,
-			   N_("disallow cloning into non-empty directory")),
+			 N_("disallow cloning into non-empty directory")),
 		OPT_BOOL(0, "single-branch", &opt.single_branch,
 			 N_("clone only one branch, HEAD or --branch")),
 		OPT_END()
@@ -2977,16 +3051,18 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
 		NULL
 	};
-	opt.prefix = prefix;
 
 	update_clone_config_from_gitmodules(&opt.max_jobs);
 	git_config(git_update_clone_config, &opt.max_jobs);
 
 	argc = parse_options(argc, argv, prefix, module_update_clone_options,
 			     git_submodule_helper_usage, 0);
+	oidcpy(&opt.oid, null_oid());
+	oidcpy(&opt.suboid, null_oid());
 
 	if (update)
-		if (parse_submodule_update_strategy(update, &opt.update) < 0)
+		if (parse_submodule_update_strategy(update,
+						    &opt.update_strategy) < 0)
 			die(_("bad value for update parameter"));
 
 	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
@@ -3408,9 +3484,7 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
-	{"update-clone", update_clone, 0},
-	{"run-update-procedure", run_update_procedure, 0},
-	{"relative-path", resolve_relative_path, 0},
+	{"update", module_update, 0},
 	{"resolve-relative-url-test", resolve_relative_url_test, 0},
 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
 	{"init", module_init, SUPPORT_SUPER_PREFIX},
diff --git a/git-submodule.sh b/git-submodule.sh
index 3ccf2388bf..bcd8b92aab 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -347,108 +347,26 @@ cmd_update()
 		shift
 	done
 
-	{
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \
+	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
 		${GIT_QUIET:+--quiet} \
-		${progress:+"--progress"} \
+		${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"
-
-		displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
-
-		if test $just_cloned -eq 0
-		then
-			just_cloned=
-		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"} \
-			  ${remote:+--remote} \
-			  "--" \
-			  "$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.33.GIT


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

* [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
                             ` (15 preceding siblings ...)
  2022-02-08  8:39           ` [PATCH v6 16/16] submodule: move core cmd_update() logic to C Glen Choo
@ 2022-02-10  9:28           ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 01/20] submodule--helper: get remote names from any repository Glen Choo
                               ` (21 more replies)
  16 siblings, 22 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

This reroll contains another 'easy' preparatory patch and the fixups I
alluded to in v6 [1]. This isn't the split-up I described in the
footnote of v6, but it gets the big patch (patch 17) to what I think is
a reviewable state.

The diff between v7 and v5 is no longer just NEEDSWORK comments, but I
think it is easier to reason about. Patch 17 resembles v5 the most (I
will include a diff in a reply to that patch); everything after patch 17
is fixups (I did not squash them in because they would grow the diff
even more).

I will also leave a review on patch 17 since the changes were not
originally authored by me.

[1] https://lore.kernel.org/git/20220208083952.35036-1-chooglen@google.com

Changes in v7:
- Split the last patch of v6 (the big one) into patches 16-17.
- Patch 16 moves logic out of run_update_procedure() (because the
  command is going away), removing some noise from patch 17. This makes
  the update_strategy parsing easier to reason about, but at the cost of
  growing the diff vis-a-vis v5
- Patches 18-20 are fixups that address NEEDSWORK comments from earlier
  patches. Once maintaining a small diff vis-a-vis v5 stops making
  sense, I will squash them in.

Atharva Raykar (6):
  submodule--helper: get remote names from any repository
  submodule--helper: refactor get_submodule_displaypath()
  submodule--helper: allow setting superprefix for init_submodule()
  submodule--helper: run update using child process struct
  builtin/submodule--helper.c: reformat designated initializers
  submodule: move core cmd_update() logic to C

Glen Choo (11):
  submodule--helper: remove update-module-mode
  submodule--helper: reorganize code for sh to C conversion
  submodule--helper run-update-procedure: remove --suboid
  submodule--helper run-update-procedure: learn --remote
  submodule--helper: remove ensure-core-worktree
  submodule--helper update-clone: learn --init
  submodule--helper: move functions around
  submodule--helper: reduce logic in run_update_procedure()
  fixup! submodule--helper run-update-procedure: remove --suboid
  fixup! submodule--helper run-update-procedure: learn --remote
  fixup! submodule: move core cmd_update() logic to C

Ævar Arnfjörð Bjarmason (3):
  builtin/submodule--helper.c: rename option variables to "opt"
  submodule--helper: don't use bitfield indirection for parse_options()
  submodule tests: test for init and update failure output

 builtin/submodule--helper.c    | 695 ++++++++++++++++++---------------
 git-submodule.sh               | 153 +-------
 t/t7406-submodule-update.sh    |  14 +-
 t/t7408-submodule-reference.sh |  14 +-
 4 files changed, 423 insertions(+), 453 deletions(-)

Range-diff against v6:
 1:  79c522cf56 =  1:  86ffb53742 submodule--helper: get remote names from any repository
 2:  0b97034d89 =  2:  2a40266b7a submodule--helper: refactor get_submodule_displaypath()
 3:  fedbed87a3 =  3:  cd851c8eb5 submodule--helper: allow setting superprefix for init_submodule()
 4:  8e7868c5d1 =  4:  bfe5cad136 submodule--helper: run update using child process struct
 5:  3dee4b9b15 =  5:  72c257fdbf builtin/submodule--helper.c: reformat designated initializers
 6:  e2cc866e6b =  6:  4b5f703fde builtin/submodule--helper.c: rename option variables to "opt"
 7:  4831695dc6 =  7:  f1d21f5b1c submodule--helper: don't use bitfield indirection for parse_options()
 8:  c2dadfffb2 =  8:  9d32a73fc3 submodule tests: test for init and update failure output
 9:  79ceb88dee =  9:  087bf43aba submodule--helper: remove update-module-mode
10:  6fe25e24da = 10:  4eb2893a19 submodule--helper: reorganize code for sh to C conversion
11:  52c997f97b = 11:  c08e7781e3 submodule--helper run-update-procedure: remove --suboid
12:  61a5b02472 = 12:  2419c37184 submodule--helper run-update-procedure: learn --remote
13:  f76627a078 = 13:  6691fd3648 submodule--helper: remove ensure-core-worktree
14:  2d93c4232b = 14:  d2c9c356e9 submodule--helper update-clone: learn --init
15:  d4899c5635 ! 15:  c8945fcc6f submodule--helper: move functions around
    @@ Metadata
      ## Commit message ##
         submodule--helper: move functions around
     
    -    The next commit will change the internals of several functions and
    +    A subsequent commit will change the internals of several functions and
         arrange them in a more logical manner. Move these functions to their
         final positions so that the diff is smaller.
     
 -:  ---------- > 16:  10af533ae0 submodule--helper: reduce logic in run_update_procedure()
16:  edf752da8d ! 17:  19143f6009 submodule: move core cmd_update() logic to C
    @@ builtin/submodule--helper.c: struct submodule_update_clone {
      };
      #define SUBMODULE_UPDATE_CLONE_INIT { \
      	.list = MODULE_LIST_INIT, \
    -@@ builtin/submodule--helper.c: struct submodule_update_clone {
    - }
    - 
    - struct update_data {
    -+	const char *prefix;
    - 	const char *recursive_prefix;
    - 	const char *sm_path;
    - 	const char *displaypath;
     @@ builtin/submodule--helper.c: struct update_data {
      	struct object_id suboid;
      	struct submodule_update_strategy update_strategy;
    @@ builtin/submodule--helper.c: struct update_data {
      
      static void next_submodule_warn_missing(struct submodule_update_clone *suc,
     @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)
    - 	struct child_process cp = CHILD_PROCESS_INIT;
    - 	char *oid = oid_to_hex(&ud->oid);
    - 	int must_die_on_failure = 0;
    -+	struct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;
    -+
    -+	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) {
    -+	switch (strategy.type) {
    - 	case SM_UPDATE_CHECKOUT:
    - 		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:
    - 		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) {
    -+		switch (strategy.type) {
    + 		switch (ud->update_strategy.type) {
      		case SM_UPDATE_CHECKOUT:
     -			printf(_("Unable to checkout '%s' in submodule path '%s'"),
     -			       oid, ud->displaypath);
    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u
      		case SM_UPDATE_REBASE:
     -			printf(_("Unable to rebase '%s' in submodule path '%s'"),
     -			       oid, ud->displaypath);
    -+			if (!must_die_on_failure)
    -+				break;
    -+			die(_("Unable to rebase '%s' in submodule path '%s'"),
    ++			die_message(_("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);
    -+			if (!must_die_on_failure)
    -+				break;
    -+			die(_("Unable to merge '%s' in submodule path '%s'"),
    ++			die_message(_("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);
    -+			if (!must_die_on_failure)
    -+				break;
    -+			die(_("Execution of '%s %s' failed in submodule path '%s'"),
    -+			    strategy.command, oid, ud->displaypath);
    ++			die_message(_("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));
    -+			    submodule_strategy_to_string(&strategy));
    + 			    submodule_strategy_to_string(&ud->update_strategy));
      		}
     -		/*
     -		 * NEEDSWORK: We are currently printing to stdout with error
    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u
     -		 * properly. Once we start handling the error messages within
     -		 * C, we should use die() instead.
     -		 */
    --		if (must_die_on_failure)
    + 		if (must_die_on_failure)
     -			return 2;
     -		/*
     -		 * This signifies to the caller in shell that the command
     -		 * failed without dying
     -		 */
    ++			exit(128);
     +
     +		/* the command failed, but update must continue */
      		return 1;
      	}
      
    --	switch (ud->update_strategy.type) {
     +	if (ud->quiet)
     +		return 0;
     +
    -+	switch (strategy.type) {
    + 	switch (ud->update_strategy.type) {
      	case SM_UPDATE_CHECKOUT:
      		printf(_("Submodule path '%s': checked out '%s'\n"),
    - 		       ud->displaypath, oid);
     @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)
    - 		break;
    - 	case SM_UPDATE_COMMAND:
    - 		printf(_("Submodule path '%s': '%s %s'\n"),
    --		       ud->displaypath, ud->update_strategy.command, oid);
    -+		       ud->displaypath, strategy.command, oid);
    - 		break;
    - 	default:
    - 		BUG("unexpected update strategy type: %s",
    --		    submodule_strategy_to_string(&ud->update_strategy));
    -+		    submodule_strategy_to_string(&strategy));
    - 	}
    - 
      	return 0;
      }
      
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -static int update_submodule2(struct update_data *update_data);
     -static int run_update_procedure(int argc, const char **argv, const char *prefix)
     -{
    --	char *prefixed_path, *update = NULL;
     -	struct update_data opt = UPDATE_DATA_INIT;
     -
     -	struct option options[] = {
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
     -			 N_("overrides update mode in case the repository is a fresh clone")),
     -		OPT_INTEGER(0, "depth", &opt.depth, N_("depth for shallow fetch")),
    --		OPT_STRING(0, "prefix", &prefix,
    +-		OPT_STRING(0, "prefix", &opt.prefix,
     -			   N_("path"),
     -			   N_("path into the working tree")),
    --		OPT_STRING(0, "update", &update,
    +-		OPT_STRING(0, "update", &opt.update_default,
     -			   N_("string"),
     -			   N_("rebase, merge, checkout or none")),
     -		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da
     -
     -	opt.sm_path = argv[0];
     -
    --	if (opt.recursive_prefix)
    --		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
    --	else
    --		prefixed_path = xstrdup(opt.sm_path);
    --
    --	opt.displaypath = get_submodule_displaypath(prefixed_path, prefix);
    --
    --	determine_submodule_update_strategy(the_repository, opt.just_cloned,
    --					    opt.sm_path, update,
    --					    &opt.update_strategy);
    --
    --	free(prefixed_path);
     -	return update_submodule2(&opt);
     -}
     -
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     -static int update_submodule2(struct update_data *update_data)
     +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);
    ++	/*
    ++	 * NEEDSWORK: the equivalent code in git-submodule.sh does not
    ++	 * pass --prefix, so this shouldn't either
    ++	*/
     +	if (update_data->prefix)
     +		strvec_pushl(args, "--prefix", update_data->prefix, NULL);
     +	if (update_data->recursive_prefix)
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +		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->update_default)
    ++		strvec_pushl(args, "--update", update_data->update_default, NULL);
     +	if (update_data->references.nr) {
     +		struct string_list_item *item;
     +		for_each_string_list_item(item, &update_data->references)
    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *
     +
     +static int update_submodule(struct update_data *update_data)
      {
    -+	char *prefixed_path;
    -+
    - 	ensure_core_worktree(update_data->sm_path);
    + 	char *prefixed_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);
    -+
    - 	/* NEEDSWORK: fix the style issues e.g. braces */
    - 	if (update_data->just_cloned) {
    - 		oidcpy(&update_data->suboid, null_oid());
     @@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *update_data)
      	}
      
    @@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *up
     -		return do_run_update_procedure(update_data);
     +		if (run_update_procedure(update_data))
     +			return 1;
    - 
    --	return 3;
    ++
     +	if (update_data->recursive) {
     +		struct child_process cp = CHILD_PROCESS_INIT;
     +		struct update_data next = *update_data;
    @@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *up
     +		cp.git_cmd = 1;
     +		prepare_submodule_repo_env(&cp.env_array);
     +		update_data_to_args(&next, &cp.args);
    -+
    + 
    +-	return 3;
     +		/* die() if child process die()'d */
     +		res = run_command(&cp);
     +		if (!res)
    @@ builtin/submodule--helper.c: static int update_submodules(struct submodule_updat
     -static int update_clone(int argc, const char **argv, const char *prefix)
     +static int module_update(int argc, const char **argv, const char *prefix)
      {
    - 	const char *update = NULL;
    +-	const char *update = NULL;
      	struct pathspec pathspec;
     -	struct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;
     +	struct update_data opt = UPDATE_DATA_INIT;
    @@ builtin/submodule--helper.c: static int update_submodules(struct submodule_updat
      			   N_("path"),
      			   N_("path into the working tree")),
      		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix,
    -@@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv, const char *prefix)
    + 			   N_("path"),
    + 			   N_("path into the working tree, across nested "
    + 			      "submodule boundaries")),
    +-		OPT_STRING(0, "update", &update,
    ++		OPT_STRING(0, "update", &opt.update_default,
      			   N_("string"),
      			   N_("rebase, merge, checkout or none")),
      		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
    @@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv
     +	oidcpy(&opt.oid, null_oid());
     +	oidcpy(&opt.suboid, null_oid());
      
    - 	if (update)
    +-	if (update)
     -		if (parse_submodule_update_strategy(update, &opt.update) < 0)
    -+		if (parse_submodule_update_strategy(update,
    ++	if (opt.update_default)
    ++		if (parse_submodule_update_strategy(opt.update_default,
     +						    &opt.update_strategy) < 0)
      			die(_("bad value for update parameter"));
      
    @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {
      	{"init", module_init, SUPPORT_SUPER_PREFIX},
     
      ## git-submodule.sh ##
    +@@ git-submodule.sh: single_branch=
    + jobs=
    + recommend_shallow=
    + 
    ++# NEEDSWORK this is now unused
    + die_if_unmatched ()
    + {
    + 	if test "$1" = "#unmatched"
     @@ git-submodule.sh: cmd_update()
      		shift
      	done
      
     -	{
     -	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \
    ++	# NEEDSWORK --super-prefix isn't actually supported by this
    ++	# command - we just pass the $prefix to --recursive-prefix.
     +	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
      		${GIT_QUIET:+--quiet} \
     -		${progress:+"--progress"} \
 -:  ---------- > 18:  9d0afc60ec fixup! submodule--helper run-update-procedure: remove --suboid
 -:  ---------- > 19:  e700861239 fixup! submodule--helper run-update-procedure: learn --remote
 -:  ---------- > 20:  aef1a03b44 fixup! submodule: move core cmd_update() logic to C

base-commit: b23dac905bde28da47543484320db16312c87551
-- 
2.33.GIT


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

* [PATCH v7 01/20] submodule--helper: get remote names from any repository
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath() Glen Choo
                               ` (20 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

`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>
Helped-by: Glen Choo <chooglen@google.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 c5d3fc3817..4c7c1e1432 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -29,11 +29,14 @@
 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)
 {
 	char *dest = NULL, *ret;
 	struct strbuf sb = STRBUF_INIT;
-	const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+	struct ref_store *store = get_main_ref_store(repo);
+	int ignore_errno;
+	const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
+						      NULL, &ignore_errno);
 
 	if (!refname)
 		die(_("No such ref: %s"), "HEAD");
@@ -46,7 +49,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 +58,19 @@ static char *get_default_remote(void)
 	return ret;
 }
 
+static char *get_default_remote_submodule(const char *module_path)
+{
+	struct repository subrepo;
+
+	repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
+	return repo_get_default_remote(&subrepo);
+}
+
+static char *get_default_remote(void)
+{
+	return repo_get_default_remote(the_repository);
+}
+
 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.33.GIT


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

* [PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath()
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
  2022-02-10  9:28             ` [PATCH v7 01/20] submodule--helper: get remote names from any repository Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:24               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule() Glen Choo
                               ` (19 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 4c7c1e1432..5efceb9d46 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.33.GIT


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

* [PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule()
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
  2022-02-10  9:28             ` [PATCH v7 01/20] submodule--helper: get remote names from any repository Glen Choo
  2022-02-10  9:28             ` [PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath() Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:30               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 04/20] submodule--helper: run update using child process struct Glen Choo
                               ` (18 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5efceb9d46..09cda67c1e 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 { 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.33.GIT


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

* [PATCH v7 04/20] submodule--helper: run update using child process struct
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (2 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule() Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:33               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 05/20] builtin/submodule--helper.c: reformat designated initializers Glen Choo
                               ` (17 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 09cda67c1e..db71e6f4ec 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2344,47 +2344,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.33.GIT


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

* [PATCH v7 05/20] builtin/submodule--helper.c: reformat designated initializers
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (3 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 04/20] submodule--helper: run update using child process struct Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 06/20] builtin/submodule--helper.c: rename option variables to "opt" Glen Choo
                               ` (16 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

The second hunk here will make a subsequent commit's diff smaller, and
let's do the first and third hunks while we're at it so that we
consistently format all of these.

Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index db71e6f4ec..9f79bdf4d5 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1654,7 +1654,10 @@ struct module_clone_data {
 	unsigned int require_init: 1;
 	int single_branch;
 };
-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
+#define MODULE_CLONE_DATA_INIT { \
+	.reference = STRING_LIST_INIT_NODUP, \
+	.single_branch = -1, \
+}
 
 struct submodule_alternate_setup {
 	const char *submodule_name;
@@ -2047,7 +2050,9 @@ struct update_data {
 	unsigned int nofetch: 1;
 	unsigned int just_cloned: 1;
 };
-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
+#define UPDATE_DATA_INIT { \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+}
 
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
 		struct strbuf *out, const char *displaypath)
@@ -3013,7 +3018,9 @@ struct add_data {
 	unsigned int progress: 1;
 	unsigned int dissociate: 1;
 };
-#define ADD_DATA_INIT { .depth = -1 }
+#define ADD_DATA_INIT { \
+	.depth = -1, \
+}
 
 static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
 {
-- 
2.33.GIT


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

* [PATCH v7 06/20] builtin/submodule--helper.c: rename option variables to "opt"
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (4 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 05/20] builtin/submodule--helper.c: reformat designated initializers Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 07/20] submodule--helper: don't use bitfield indirection for parse_options() Glen Choo
                               ` (15 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

Rename the "suc" variable in update_clone() to "opt", and do the same
for the "update_data" variable in run_update_procedure().

The only reason for this change is to make the subsequent commit's
diff smaller, by doing this rename we can "anchor" the diff better, as
it "borrow" most of the options declared here as-is as far as the diff
rename detection is concerned.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 74 ++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9f79bdf4d5..c2d4fd0347 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2517,36 +2517,36 @@ 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 submodule_update_clone opt = 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,
+		OPT_STRING(0, "recursive-prefix", &opt.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"),
+		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
 			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &suc.dissociate,
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
 			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &suc.depth, "<depth>",
+		OPT_STRING(0, "depth", &opt.depth, "<depth>",
 			   N_("create a shallow clone truncated to the "
 			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &suc.max_jobs,
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
 			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
+		OPT_BOOL(0, "recommend-shallow", &opt.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,
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
 			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &suc.require_init,
+		OPT_BOOL(0, "require-init", &opt.require_init,
 			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &suc.single_branch,
+		OPT_BOOL(0, "single-branch", &opt.single_branch,
 			 N_("clone only one branch, HEAD or --branch")),
 		OPT_END()
 	};
@@ -2555,32 +2555,32 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
 		NULL
 	};
-	suc.prefix = prefix;
+	opt.prefix = prefix;
 
-	update_clone_config_from_gitmodules(&suc.max_jobs);
-	git_config(git_update_clone_config, &suc.max_jobs);
+	update_clone_config_from_gitmodules(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.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)
+		if (parse_submodule_update_strategy(update, &opt.update) < 0)
 			die(_("bad value for update parameter"));
 
-	if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
 		return 1;
 
 	if (pathspec.nr)
-		suc.warn_if_uninitialized = 1;
+		opt.warn_if_uninitialized = 1;
 
-	return update_submodules(&suc);
+	return update_submodules(&opt);
 }
 
 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 update_data opt = UPDATE_DATA_INIT;
 
 	struct option options[] = {
 		OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
@@ -2589,20 +2589,20 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 			 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_INTEGER(0, "depth", &opt.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"),
+		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
 			   N_("path into the working tree, across nested "
 			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
+		OPT_CALLBACK_F(0, "oid", &opt.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"),
+		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
 			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
 			       parse_opt_object_id),
 		OPT_END()
@@ -2618,27 +2618,27 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	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];
+	opt.force = !!force;
+	opt.quiet = !!quiet;
+	opt.nofetch = !!nofetch;
+	opt.just_cloned = !!just_cloned;
+	opt.sm_path = argv[0];
 
-	if (update_data.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path);
+	if (opt.recursive_prefix)
+		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
 	else
-		prefixed_path = xstrdup(update_data.sm_path);
+		prefixed_path = xstrdup(opt.sm_path);
 
-	update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);
+	opt.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);
+	determine_submodule_update_strategy(the_repository, opt.just_cloned,
+					    opt.sm_path, update,
+					    &opt.update_strategy);
 
 	free(prefixed_path);
 
-	if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
-		return do_run_update_procedure(&update_data);
+	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
+		return do_run_update_procedure(&opt);
 
 	return 3;
 }
-- 
2.33.GIT


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

* [PATCH v7 07/20] submodule--helper: don't use bitfield indirection for parse_options()
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (5 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 06/20] builtin/submodule--helper.c: rename option variables to "opt" Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 08/20] submodule tests: test for init and update failure output Glen Choo
                               ` (14 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

Do away with the indirection of local variables added in
c51f8f94e5b (submodule--helper: run update procedures from C,
2021-08-24).

These were only needed because in C you can't get a pointer to a
single bit, so we were using intermediate variables instead.

This will also make a subsequent large commit's diff smaller.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/submodule--helper.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c2d4fd0347..4a0890954e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2045,10 +2045,10 @@ struct update_data {
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
 	int depth;
-	unsigned int force: 1;
-	unsigned int quiet: 1;
-	unsigned int nofetch: 1;
-	unsigned int just_cloned: 1;
+	unsigned int force;
+	unsigned int quiet;
+	unsigned int nofetch;
+	unsigned int just_cloned;
 };
 #define UPDATE_DATA_INIT { \
 	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
@@ -2578,16 +2578,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 
 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 opt = UPDATE_DATA_INIT;
 
 	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,
+		OPT__QUIET(&opt.quiet,
+			   N_("suppress output for update by rebase or merge")),
+		OPT__FORCE(&opt.force, N_("force checkout updates"),
+			   0),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
 			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &just_cloned,
+		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
 			 N_("overrides update mode in case the repository is a fresh clone")),
 		OPT_INTEGER(0, "depth", &opt.depth, N_("depth for shallow fetch")),
 		OPT_STRING(0, "prefix", &prefix,
@@ -2618,10 +2619,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 	if (argc != 1)
 		usage_with_options(usage, options);
 
-	opt.force = !!force;
-	opt.quiet = !!quiet;
-	opt.nofetch = !!nofetch;
-	opt.just_cloned = !!just_cloned;
 	opt.sm_path = argv[0];
 
 	if (opt.recursive_prefix)
-- 
2.33.GIT


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

* [PATCH v7 08/20] submodule tests: test for init and update failure output
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (6 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 07/20] submodule--helper: don't use bitfield indirection for parse_options() Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 09/20] submodule--helper: remove update-module-mode Glen Choo
                               ` (13 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

Amend some submodule tests to test for the failure output of "git
submodule [update|init]". The lack of such tests hid a regression in
an earlier version of a subsequent commit.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 t/t7406-submodule-update.sh    | 14 ++++++++++++--
 t/t7408-submodule-reference.sh | 14 +++++++++++++-
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 11cccbb333..7764c1c3cb 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -205,8 +205,18 @@ test_expect_success 'submodule update should fail due to local changes' '
 	 (cd submodule &&
 	  compare_head
 	 ) &&
-	 test_must_fail git submodule update submodule
-	)
+	 test_must_fail git submodule update submodule 2>../actual.raw
+	) &&
+	sed "s/^> //" >expect <<-\EOF &&
+	> error: Your local changes to the following files would be overwritten by checkout:
+	> 	file
+	> Please commit your changes or stash them before you switch branches.
+	> Aborting
+	> fatal: Unable to checkout OID in submodule path '\''submodule'\''
+	EOF
+	sed -e "s/checkout $SQ[^$SQ]*$SQ/checkout OID/" <actual.raw >actual &&
+	test_cmp expect actual
+
 '
 test_expect_success 'submodule update should throw away changes with --force ' '
 	(cd super &&
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index a3892f494b..c3a4545510 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -193,7 +193,19 @@ test_expect_success 'missing nested submodule alternate fails clone and submodul
 		cd supersuper-clone &&
 		check_that_two_of_three_alternates_are_used &&
 		# update of the submodule fails
-		test_must_fail git submodule update --init --recursive
+		cat >expect <<-\EOF &&
+		fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub'\''. Retry scheduled
+		fatal: submodule '\''sub-dissociate'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub-dissociate'\''. Retry scheduled
+		fatal: submodule '\''sub'\'' cannot add alternate: path ... does not exist
+		Failed to clone '\''sub'\'' a second time, aborting
+		fatal: Failed to recurse into submodule path ...
+		EOF
+		test_must_fail git submodule update --init --recursive 2>err &&
+		grep -e fatal: -e ^Failed err >actual.raw &&
+		sed -e "s/path $SQ[^$SQ]*$SQ/path .../" <actual.raw >actual &&
+		test_cmp expect actual
 	)
 '
 
-- 
2.33.GIT


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

* [PATCH v7 09/20] submodule--helper: remove update-module-mode
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (7 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 08/20] submodule tests: test for init and update failure output Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:35               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 10/20] submodule--helper: reorganize code for sh to C conversion Glen Choo
                               ` (12 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

This is dead code - it has not been used since c51f8f94e5
(submodule--helper: run update procedures from C, 2021-08-24).

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 4a0890954e..e0cc1c1b79 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1965,29 +1965,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;
@@ -3388,7 +3365,6 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
-	{"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},
-- 
2.33.GIT


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

* [PATCH v7 10/20] submodule--helper: reorganize code for sh to C conversion
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (8 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 09/20] submodule--helper: remove update-module-mode Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 11/20] submodule--helper run-update-procedure: remove --suboid Glen Choo
                               ` (11 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Introduce a function, update_submodule2(), that performs an update for
one submodule. This function will implement the functionality of
run-update-procedure and its surrounding shell code in submodule.sh.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index e0cc1c1b79..0b5120734a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2553,6 +2553,11 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	return update_submodules(&opt);
 }
 
+/*
+ * NEEDSWORK: Use a forward declaration to avoid moving
+ * run_update_procedure() (which will be removed soon).
+ */
+static int update_submodule2(struct update_data *update_data);
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
 {
 	char *prefixed_path, *update = NULL;
@@ -2610,11 +2615,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 					    &opt.update_strategy);
 
 	free(prefixed_path);
-
-	if (!oideq(&opt.oid, &opt.suboid) || opt.force)
-		return do_run_update_procedure(&opt);
-
-	return 3;
+	return update_submodule2(&opt);
 }
 
 static int resolve_relative_path(int argc, const char **argv, const char *prefix)
@@ -2978,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 	return !!ret;
 }
 
+/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
+static int update_submodule2(struct update_data *update_data)
+{
+	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
+		return do_run_update_procedure(update_data);
+
+	return 3;
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
-- 
2.33.GIT


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

* [PATCH v7 11/20] submodule--helper run-update-procedure: remove --suboid
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (9 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 10/20] submodule--helper: reorganize code for sh to C conversion Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote Glen Choo
                               ` (10 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Teach run-update-procedure to determine the oid of the submodule's HEAD
instead of doing it in git-subomdule.sh.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 12 +++++++++---
 git-submodule.sh            |  8 +-------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0b5120734a..a26477ce04 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2585,9 +2585,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
 			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
 			       parse_opt_object_id),
-		OPT_CALLBACK_F(0, "suboid", &opt.suboid, N_("subsha1"),
-			       N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
 		OPT_END()
 	};
 
@@ -2982,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 /* NEEDSWORK: this is a temporary name until we delete update_submodule() */
 static int update_submodule2(struct update_data *update_data)
 {
+	/* NEEDSWORK: fix the style issues e.g. braces */
+	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 (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
 		return do_run_update_procedure(update_data);
 
diff --git a/git-submodule.sh b/git-submodule.sh
index 652861aa66..d48c314f01 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -391,14 +391,9 @@ cmd_update()
 
 		displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
 
-		if test $just_cloned -eq 1
+		if test $just_cloned -eq 0
 		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"
@@ -426,7 +421,6 @@ cmd_update()
 			  ${update:+--update "$update"} \
 			  ${prefix:+--recursive-prefix "$prefix"} \
 			  ${sha1:+--oid "$sha1"} \
-			  ${subsha1:+--suboid "$subsha1"} \
 			  "--" \
 			  "$sm_path")
 
-- 
2.33.GIT


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

* [PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (10 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 11/20] submodule--helper run-update-procedure: remove --suboid Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:38               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 13/20] submodule--helper: remove ensure-core-worktree Glen Choo
                               ` (9 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Teach run-update-procedure to handle --remote instead of parsing
--remote in git-submodule.sh. As a result, "git submodule--helper
print-default-remote" has no more callers, so remove it.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 39 ++++++++++++++++++++++---------------
 git-submodule.sh            | 30 +---------------------------
 2 files changed, 24 insertions(+), 45 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a26477ce04..15ae986692 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);
 }
 
-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]);
@@ -2026,6 +2011,7 @@ struct update_data {
 	unsigned int quiet;
 	unsigned int nofetch;
 	unsigned int just_cloned;
+	unsigned int remote;
 };
 #define UPDATE_DATA_INIT { \
 	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
@@ -2585,6 +2571,8 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
 			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
 			       parse_opt_object_id),
+		OPT_BOOL(0, "remote", &opt.remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
 		OPT_END()
 	};
 
@@ -2988,6 +2976,25 @@ static int update_submodule2(struct update_data *update_data)
 			    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)
 		return do_run_update_procedure(update_data);
 
@@ -3389,10 +3396,10 @@ 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},
+	/* NEEDSWORK: remote-branch is also obsolete */
 	{"remote-branch", resolve_remote_submodule_branch, 0},
 	{"push-check", push_check, 0},
 	{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --git a/git-submodule.sh b/git-submodule.sh
index d48c314f01..29fd69250d 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
 #
@@ -396,21 +382,6 @@ cmd_update()
 			just_cloned=
 		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} \
@@ -421,6 +392,7 @@ cmd_update()
 			  ${update:+--update "$update"} \
 			  ${prefix:+--recursive-prefix "$prefix"} \
 			  ${sha1:+--oid "$sha1"} \
+			  ${remote:+--remote} \
 			  "--" \
 			  "$sm_path")
 
-- 
2.33.GIT


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

* [PATCH v7 13/20] submodule--helper: remove ensure-core-worktree
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (11 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 14/20] submodule--helper update-clone: learn --init Glen Choo
                               ` (8 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Move the logic of "git submodule--helper ensure-core-worktree" into
run-update-procedure. Since the ensure-core-worktree command is
obsolete, remove it.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 13 +++----------
 git-submodule.sh            |  2 --
 2 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 15ae986692..a05aea5cd6 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2746,17 +2746,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 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);
 
@@ -2776,8 +2770,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 		free(abs_path);
 		strbuf_release(&sb);
 	}
-
-	return 0;
 }
 
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
@@ -2967,6 +2959,8 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 /* NEEDSWORK: this is a temporary name until we delete update_submodule() */
 static int update_submodule2(struct update_data *update_data)
 {
+	ensure_core_worktree(update_data->sm_path);
+
 	/* NEEDSWORK: fix the style issues e.g. braces */
 	if (update_data->just_cloned) {
 		oidcpy(&update_data->suboid, null_oid());
@@ -3390,7 +3384,6 @@ static struct cmd_struct commands[] = {
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
 	{"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},
diff --git a/git-submodule.sh b/git-submodule.sh
index 29fd69250d..aa9c898e1c 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -373,8 +373,6 @@ cmd_update()
 	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 0
-- 
2.33.GIT


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

* [PATCH v7 14/20] submodule--helper update-clone: learn --init
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (12 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 13/20] submodule--helper: remove ensure-core-worktree Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 15/20] submodule--helper: move functions around Glen Choo
                               ` (7 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Teach "git submodule--helper update-clone" the --init flag and remove
the corresponding shell code.

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. So we instead run the
`init_submodule_cb()` callback over each submodule in the same process.

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

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 26 ++++++++++++++++++++++++++
 git-submodule.sh            |  9 +++------
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a05aea5cd6..5635f0c48b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1989,6 +1989,7 @@ struct submodule_update_clone {
 	int failed_clones_nr, failed_clones_alloc;
 
 	int max_jobs;
+	unsigned int init;
 };
 #define SUBMODULE_UPDATE_CLONE_INIT { \
 	.list = MODULE_LIST_INIT, \
@@ -2483,6 +2484,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	struct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;
 
 	struct option module_update_clone_options[] = {
+		OPT_BOOL(0, "init", &opt.init,
+			 N_("initialize uninitialized submodules before update")),
 		OPT_STRING(0, "prefix", &prefix,
 			   N_("path"),
 			   N_("path into the working tree")),
@@ -2536,6 +2539,29 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	if (pathspec.nr)
 		opt.warn_if_uninitialized = 1;
 
+	if (opt.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
+		info.superprefix = opt.recursive_prefix;
+		if (opt.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
 	return update_submodules(&opt);
 }
 
diff --git a/git-submodule.sh b/git-submodule.sh
index aa9c898e1c..3ccf2388bf 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -347,14 +347,11 @@ cmd_update()
 		shift
 	done
 
-	if test -n "$init"
-	then
-		cmd_init "--" "$@" || return
-	fi
-
 	{
-	git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \
+		${GIT_QUIET:+--quiet} \
 		${progress:+"--progress"} \
+		${init:+--init} \
 		${wt_prefix:+--prefix "$wt_prefix"} \
 		${prefix:+--recursive-prefix "$prefix"} \
 		${update:+--update "$update"} \
-- 
2.33.GIT


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

* [PATCH v7 15/20] submodule--helper: move functions around
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (13 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 14/20] submodule--helper update-clone: learn --init Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:41               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 16/20] submodule--helper: reduce logic in run_update_procedure() Glen Choo
                               ` (6 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

A subsequent commit will change the internals of several functions and
arrange them in a more logical manner. Move these functions to their
final positions so that the diff is smaller.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 228 ++++++++++++++++++------------------
 1 file changed, 114 insertions(+), 114 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5635f0c48b..0ab8f9d49f 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2451,120 +2451,6 @@ static void update_submodule(struct update_clone_data *ucd)
 		ucd->sub->path);
 }
 
-static int update_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_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 opt = SUBMODULE_UPDATE_CLONE_INIT;
-
-	struct option module_update_clone_options[] = {
-		OPT_BOOL(0, "init", &opt.init,
-			 N_("initialize uninitialized submodules before update")),
-		OPT_STRING(0, "prefix", &prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "recursive-prefix", &opt.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", &opt.references, N_("repo"),
-			   N_("reference repository")),
-		OPT_BOOL(0, "dissociate", &opt.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
-		OPT_INTEGER('j', "jobs", &opt.max_jobs,
-			    N_("parallel jobs")),
-		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
-		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
-		OPT_BOOL(0, "progress", &opt.progress,
-			    N_("force cloning progress")),
-		OPT_BOOL(0, "require-init", &opt.require_init,
-			   N_("disallow cloning into non-empty directory")),
-		OPT_BOOL(0, "single-branch", &opt.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
-	};
-	opt.prefix = prefix;
-
-	update_clone_config_from_gitmodules(&opt.max_jobs);
-	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
-			die(_("bad value for update parameter"));
-
-	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
-		return 1;
-
-	if (pathspec.nr)
-		opt.warn_if_uninitialized = 1;
-
-	if (opt.init) {
-		struct module_list list = MODULE_LIST_INIT;
-		struct init_cb info = INIT_CB_INIT;
-
-		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
-		info.superprefix = opt.recursive_prefix;
-		if (opt.quiet)
-			info.flags |= OPT_QUIET;
-
-		for_each_listed_submodule(&list, init_submodule_cb, &info);
-	}
-
-	return update_submodules(&opt);
-}
-
 /*
  * NEEDSWORK: Use a forward declaration to avoid moving
  * run_update_procedure() (which will be removed soon).
@@ -3021,6 +2907,120 @@ static int update_submodule2(struct update_data *update_data)
 	return 3;
 }
 
+static int update_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_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 opt = SUBMODULE_UPDATE_CLONE_INIT;
+
+	struct option module_update_clone_options[] = {
+		OPT_BOOL(0, "init", &opt.init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_STRING(0, "prefix", &prefix,
+			   N_("path"),
+			   N_("path into the working tree")),
+		OPT_STRING(0, "recursive-prefix", &opt.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", &opt.references, N_("repo"),
+			   N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
+			   N_("use --reference only while cloning")),
+		OPT_STRING(0, "depth", &opt.depth, "<depth>",
+			   N_("create a shallow clone truncated to the "
+			      "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
+			    N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
+			    N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &opt.require_init,
+			   N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &opt.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
+	};
+	opt.prefix = prefix;
+
+	update_clone_config_from_gitmodules(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.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, &opt.update) < 0)
+			die(_("bad value for update parameter"));
+
+	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
+		return 1;
+
+	if (pathspec.nr)
+		opt.warn_if_uninitialized = 1;
+
+	if (opt.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argc, argv, opt.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 = opt.prefix;
+		info.superprefix = opt.recursive_prefix;
+		if (opt.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+	}
+
+	return update_submodules(&opt);
+}
+
 struct add_data {
 	const char *prefix;
 	const char *branch;
-- 
2.33.GIT


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

* [PATCH v7 16/20] submodule--helper: reduce logic in run_update_procedure()
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (14 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 15/20] submodule--helper: move functions around Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 17/20] submodule: move core cmd_update() logic to C Glen Choo
                               ` (5 subsequent siblings)
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

A later commit will combine the "update-clone" and
"run-update-procedure" commands, so run_update_procedure() will be
removed. Prepare for this by moving as much logic as possible out of
run_update_procedure() and into update_submodule2().

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0ab8f9d49f..ff7ee73e1a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2001,9 +2001,11 @@ struct submodule_update_clone {
 }
 
 struct update_data {
+	const char *prefix;
 	const char *recursive_prefix;
 	const char *sm_path;
 	const char *displaypath;
+	const char *update_default;
 	struct object_id oid;
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
@@ -2458,7 +2460,6 @@ static void update_submodule(struct update_clone_data *ucd)
 static int update_submodule2(struct update_data *update_data);
 static int run_update_procedure(int argc, const char **argv, const char *prefix)
 {
-	char *prefixed_path, *update = NULL;
 	struct update_data opt = UPDATE_DATA_INIT;
 
 	struct option options[] = {
@@ -2471,10 +2472,10 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
 			 N_("overrides update mode in case the repository is a fresh clone")),
 		OPT_INTEGER(0, "depth", &opt.depth, N_("depth for shallow fetch")),
-		OPT_STRING(0, "prefix", &prefix,
+		OPT_STRING(0, "prefix", &opt.prefix,
 			   N_("path"),
 			   N_("path into the working tree")),
-		OPT_STRING(0, "update", &update,
+		OPT_STRING(0, "update", &opt.update_default,
 			   N_("string"),
 			   N_("rebase, merge, checkout or none")),
 		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
@@ -2500,18 +2501,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
 
 	opt.sm_path = argv[0];
 
-	if (opt.recursive_prefix)
-		prefixed_path = xstrfmt("%s%s", opt.recursive_prefix, opt.sm_path);
-	else
-		prefixed_path = xstrdup(opt.sm_path);
-
-	opt.displaypath = get_submodule_displaypath(prefixed_path, prefix);
-
-	determine_submodule_update_strategy(the_repository, opt.just_cloned,
-					    opt.sm_path, update,
-					    &opt.update_strategy);
-
-	free(prefixed_path);
 	return update_submodule2(&opt);
 }
 
@@ -2871,8 +2860,24 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 /* NEEDSWORK: this is a temporary name until we delete update_submodule() */
 static int update_submodule2(struct update_data *update_data)
 {
+	char *prefixed_path;
+
 	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);
+
+	determine_submodule_update_strategy(the_repository, update_data->just_cloned,
+					    update_data->sm_path, update_data->update_default,
+					    &update_data->update_strategy);
+
 	/* NEEDSWORK: fix the style issues e.g. braces */
 	if (update_data->just_cloned) {
 		oidcpy(&update_data->suboid, null_oid());
-- 
2.33.GIT


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

* [PATCH v7 17/20] submodule: move core cmd_update() logic to C
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (15 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 16/20] submodule--helper: reduce logic in run_update_procedure() Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-10  9:34               ` Glen Choo
  2022-02-10  9:28             ` [PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid Glen Choo
                               ` (4 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

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

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.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 312 ++++++++++++++++++++++--------------
 git-submodule.sh            | 105 ++----------
 2 files changed, 201 insertions(+), 216 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index ff7ee73e1a..b895e88a64 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1977,7 +1977,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;
 
@@ -1989,7 +1988,6 @@ struct submodule_update_clone {
 	int failed_clones_nr, failed_clones_alloc;
 
 	int max_jobs;
-	unsigned int init;
 };
 #define SUBMODULE_UPDATE_CLONE_INIT { \
 	.list = MODULE_LIST_INIT, \
@@ -2010,14 +2008,54 @@ struct update_data {
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
 	int depth;
+	int recommend_shallow;
+	int single_branch;
+	int max_jobs;
+	unsigned int init;
 	unsigned int force;
 	unsigned int quiet;
 	unsigned int nofetch;
 	unsigned int just_cloned;
 	unsigned int remote;
+	unsigned int recursive;
+	unsigned int progress;
+	unsigned int dissociate;
+	unsigned int require_init;
+	unsigned warn_if_uninitialized ;
+	struct string_list references;
+	struct module_list list;
 };
 #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,
@@ -2356,40 +2394,35 @@ static int run_update_command(struct update_data *ud, int subforce)
 	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);
+			die_message(_("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);
+			die_message(_("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);
+			die_message(_("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);
+			die_message(_("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));
 		}
-		/*
-		 * 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
-		 */
+			exit(128);
+
+		/* the command failed, but update must continue */
 		return 1;
 	}
 
+	if (ud->quiet)
+		return 0;
+
 	switch (ud->update_strategy.type) {
 	case SM_UPDATE_CHECKOUT:
 		printf(_("Submodule path '%s': checked out '%s'\n"),
@@ -2415,7 +2448,7 @@ static int run_update_command(struct update_data *ud, int subforce)
 	return 0;
 }
 
-static int do_run_update_procedure(struct update_data *ud)
+static int run_update_procedure(struct update_data *ud)
 {
 	int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2445,76 +2478,6 @@ 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)
-{
-	fprintf(stdout, "dummy %s %d\t%s\n",
-		oid_to_hex(&ucd->oid),
-		ucd->just_cloned,
-		ucd->sub->path);
-}
-
-/*
- * NEEDSWORK: Use a forward declaration to avoid moving
- * run_update_procedure() (which will be removed soon).
- */
-static int update_submodule2(struct update_data *update_data);
-static int run_update_procedure(int argc, const char **argv, const char *prefix)
-{
-	struct update_data opt = UPDATE_DATA_INIT;
-
-	struct option options[] = {
-		OPT__QUIET(&opt.quiet,
-			   N_("suppress output for update by rebase or merge")),
-		OPT__FORCE(&opt.force, N_("force checkout updates"),
-			   0),
-		OPT_BOOL('N', "no-fetch", &opt.nofetch,
-			 N_("don't fetch new objects from the remote site")),
-		OPT_BOOL(0, "just-cloned", &opt.just_cloned,
-			 N_("overrides update mode in case the repository is a fresh clone")),
-		OPT_INTEGER(0, "depth", &opt.depth, N_("depth for shallow fetch")),
-		OPT_STRING(0, "prefix", &opt.prefix,
-			   N_("path"),
-			   N_("path into the working tree")),
-		OPT_STRING(0, "update", &opt.update_default,
-			   N_("string"),
-			   N_("rebase, merge, checkout or none")),
-		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix, N_("path"),
-			   N_("path into the working tree, across nested "
-			      "submodule boundaries")),
-		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
-			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
-			       parse_opt_object_id),
-		OPT_BOOL(0, "remote", &opt.remote,
-			 N_("use SHA-1 of submodule's remote tracking branch")),
-		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);
-
-	opt.sm_path = argv[0];
-
-	return update_submodule2(&opt);
-}
-
-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;
@@ -2857,8 +2820,53 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 	return !!ret;
 }
 
-/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
-static int update_submodule2(struct update_data *update_data)
+static void update_data_to_args(struct update_data *update_data, struct strvec *args)
+{
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
+	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
+	/*
+	 * NEEDSWORK: the equivalent code in git-submodule.sh does not
+	 * pass --prefix, so this shouldn't either
+	*/
+	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_data->update_default)
+		strvec_pushl(args, "--update", update_data->update_default, 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;
 
@@ -2907,18 +2915,55 @@ static int update_submodule2(struct update_data *update_data)
 	}
 
 	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
-		return do_run_update_procedure(update_data);
+		if (run_update_procedure(update_data))
+			return 1;
+
+	if (update_data->recursive) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+		struct update_data next = *update_data;
+		int res;
+
+		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);
 
-	return 3;
+		/* die() if child process die()'d */
+		res = run_command(&cp);
+		if (!res)
+			return 0;
+		die_message(_("Failed to recurse into submodule path '%s'"),
+			    update_data->displaypath);
+		if (res == 128)
+			exit(res);
+		else if (res)
+			return 1;
+	}
+
+	return 0;
 }
 
-static int update_submodules(struct submodule_update_clone *suc)
+static int update_submodules(struct update_data *update_data)
 {
-	int i;
+	int i, res = 0;
+	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
 
-	run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
+	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",
+				   update_clone_task_finished, &suc, "submodule",
 				   "parallel/update");
 
 	/*
@@ -2929,50 +2974,69 @@ static int update_submodules(struct submodule_update_clone *suc)
 	 *   checkout involve more straightforward sequential I/O.
 	 * - the listener can avoid doing any work if fetching failed.
 	 */
-	if (suc->quickstop)
-		return 1;
+	if (suc.quickstop) {
+		res = 1;
+		goto cleanup;
+	}
 
-	for (i = 0; i < suc->update_clone_nr; i++)
-		update_submodule(&suc->update_clone[i]);
+	for (i = 0; i < suc.update_clone_nr; i++) {
+		struct update_clone_data ucd = suc.update_clone[i];
 
-	return 0;
+		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;
+	}
+
+cleanup:
+	string_list_clear(&update_data->references, 0);
+	return res;
 }
 
-static int update_clone(int argc, const char **argv, const char *prefix)
+static int module_update(int argc, const char **argv, const char *prefix)
 {
-	const char *update = NULL;
 	struct pathspec pathspec;
-	struct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;
+	struct update_data opt = UPDATE_DATA_INIT;
 
+	/* NEEDSWORK: update names and strings */
 	struct option module_update_clone_options[] = {
+		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
 			 N_("initialize uninitialized submodules before update")),
-		OPT_STRING(0, "prefix", &prefix,
+		OPT_BOOL(0, "remote", &opt.remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &opt.recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_STRING(0, "prefix", &opt.prefix,
 			   N_("path"),
 			   N_("path into the working tree")),
 		OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix,
 			   N_("path"),
 			   N_("path into the working tree, across nested "
 			      "submodule boundaries")),
-		OPT_STRING(0, "update", &update,
+		OPT_STRING(0, "update", &opt.update_default,
 			   N_("string"),
 			   N_("rebase, merge, checkout or none")),
 		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
-			   N_("reference repository")),
+				N_("reference repository")),
 		OPT_BOOL(0, "dissociate", &opt.dissociate,
-			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &opt.depth, "<depth>",
-			   N_("create a shallow clone truncated to the "
-			      "specified number of revisions")),
+			 N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &opt.depth,
+			    N_("create a shallow clone truncated to the "
+			       "specified number of revisions")),
 		OPT_INTEGER('j', "jobs", &opt.max_jobs,
 			    N_("parallel jobs")),
 		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
-			    N_("whether the initial clone should follow the shallow recommendation")),
+			 N_("whether the initial clone should follow the shallow recommendation")),
 		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
 		OPT_BOOL(0, "progress", &opt.progress,
-			    N_("force cloning progress")),
+			 N_("force cloning progress")),
 		OPT_BOOL(0, "require-init", &opt.require_init,
-			   N_("disallow cloning into non-empty directory")),
+			 N_("disallow cloning into non-empty directory")),
 		OPT_BOOL(0, "single-branch", &opt.single_branch,
 			 N_("clone only one branch, HEAD or --branch")),
 		OPT_END()
@@ -2982,16 +3046,18 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
 		NULL
 	};
-	opt.prefix = prefix;
 
 	update_clone_config_from_gitmodules(&opt.max_jobs);
 	git_config(git_update_clone_config, &opt.max_jobs);
 
 	argc = parse_options(argc, argv, prefix, module_update_clone_options,
 			     git_submodule_helper_usage, 0);
+	oidcpy(&opt.oid, null_oid());
+	oidcpy(&opt.suboid, null_oid());
 
-	if (update)
-		if (parse_submodule_update_strategy(update, &opt.update) < 0)
+	if (opt.update_default)
+		if (parse_submodule_update_strategy(opt.update_default,
+						    &opt.update_strategy) < 0)
 			die(_("bad value for update parameter"));
 
 	if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)
@@ -3413,9 +3479,7 @@ static struct cmd_struct commands[] = {
 	{"name", module_name, 0},
 	{"clone", module_clone, 0},
 	{"add", module_add, SUPPORT_SUPER_PREFIX},
-	{"update-clone", update_clone, 0},
-	{"run-update-procedure", run_update_procedure, 0},
-	{"relative-path", resolve_relative_path, 0},
+	{"update", module_update, 0},
 	{"resolve-relative-url-test", resolve_relative_url_test, 0},
 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
 	{"init", module_init, SUPPORT_SUPER_PREFIX},
diff --git a/git-submodule.sh b/git-submodule.sh
index 3ccf2388bf..d176469fb1 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -50,6 +50,7 @@ single_branch=
 jobs=
 recommend_shallow=
 
+# NEEDSWORK this is now unused
 die_if_unmatched ()
 {
 	if test "$1" = "#unmatched"
@@ -347,108 +348,28 @@ cmd_update()
 		shift
 	done
 
-	{
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update-clone \
+	# NEEDSWORK --super-prefix isn't actually supported by this
+	# command - we just pass the $prefix to --recursive-prefix.
+	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
 		${GIT_QUIET:+--quiet} \
-		${progress:+"--progress"} \
+		${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"
-
-		displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
-
-		if test $just_cloned -eq 0
-		then
-			just_cloned=
-		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"} \
-			  ${remote:+--remote} \
-			  "--" \
-			  "$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.33.GIT


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

* [PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (16 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 17/20] submodule: move core cmd_update() logic to C Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:41               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote Glen Choo
                               ` (3 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b895e88a64..98d8910930 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2886,14 +2886,11 @@ static int update_submodule(struct update_data *update_data)
 					    update_data->sm_path, update_data->update_default,
 					    &update_data->update_strategy);
 
-	/* NEEDSWORK: fix the style issues e.g. braces */
-	if (update_data->just_cloned) {
+	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);
-	}
+	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);
-- 
2.33.GIT


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

* [PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (17 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:43               ` Ævar Arnfjörð Bjarmason
  2022-02-10  9:28             ` [PATCH v7 20/20] fixup! submodule: move core cmd_update() logic to C Glen Choo
                               ` (2 subsequent siblings)
  21 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 19 -------------------
 1 file changed, 19 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 98d8910930..5d5302b50b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2516,23 +2516,6 @@ static const char *remote_submodule_branch(const char *path)
 	return branch;
 }
 
-static int resolve_remote_submodule_branch(int argc, const char **argv,
-		const char *prefix)
-{
-	const char *ret;
-	struct strbuf sb = STRBUF_INIT;
-	if (argc != 2)
-		die("submodule--helper remote-branch takes exactly one arguments, got %d", argc);
-
-	ret = remote_submodule_branch(argv[1]);
-	if (!ret)
-		die("submodule %s doesn't exist", argv[1]);
-
-	printf("%s", ret);
-	strbuf_release(&sb);
-	return 0;
-}
-
 static int push_check(int argc, const char **argv, const char *prefix)
 {
 	struct remote *remote;
@@ -3484,8 +3467,6 @@ static struct cmd_struct commands[] = {
 	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
 	{"deinit", module_deinit, 0},
 	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
-	/* NEEDSWORK: remote-branch is also obsolete */
-	{"remote-branch", resolve_remote_submodule_branch, 0},
 	{"push-check", push_check, 0},
 	{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
 	{"is-active", is_active, 0},
-- 
2.33.GIT


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

* [PATCH v7 20/20] fixup! submodule: move core cmd_update() logic to C
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (18 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote Glen Choo
@ 2022-02-10  9:28             ` Glen Choo
  2022-02-12 14:45             ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
  2022-02-13  5:54             ` Junio C Hamano
  21 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:28 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla, Ævar Arnfjörð Bjarmason

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c | 13 +++----------
 git-submodule.sh            | 13 +------------
 2 files changed, 4 insertions(+), 22 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 5d5302b50b..3367997973 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2807,12 +2807,6 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *
 {
 	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
-	/*
-	 * NEEDSWORK: the equivalent code in git-submodule.sh does not
-	 * pass --prefix, so this shouldn't either
-	*/
-	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);
@@ -2980,8 +2974,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 	struct pathspec pathspec;
 	struct update_data opt = UPDATE_DATA_INIT;
 
-	/* NEEDSWORK: update names and strings */
-	struct option module_update_clone_options[] = {
+	struct option module_update_options[] = {
 		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
 			 N_("initialize uninitialized submodules before update")),
@@ -3023,14 +3016,14 @@ static int module_update(int argc, const char **argv, const char *prefix)
 	};
 
 	const char *const git_submodule_helper_usage[] = {
-		N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
+		N_("git submodule--helper update [--prefix=<path>] [<path>...]"),
 		NULL
 	};
 
 	update_clone_config_from_gitmodules(&opt.max_jobs);
 	git_config(git_update_clone_config, &opt.max_jobs);
 
-	argc = parse_options(argc, argv, prefix, module_update_clone_options,
+	argc = parse_options(argc, argv, prefix, module_update_options,
 			     git_submodule_helper_usage, 0);
 	oidcpy(&opt.oid, null_oid());
 	oidcpy(&opt.suboid, null_oid());
diff --git a/git-submodule.sh b/git-submodule.sh
index d176469fb1..89f5cf393e 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -50,15 +50,6 @@ single_branch=
 jobs=
 recommend_shallow=
 
-# NEEDSWORK this is now unused
-die_if_unmatched ()
-{
-	if test "$1" = "#unmatched"
-	then
-		exit ${2:-1}
-	fi
-}
-
 isnumber()
 {
 	n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
@@ -348,9 +339,7 @@ cmd_update()
 		shift
 	done
 
-	# NEEDSWORK --super-prefix isn't actually supported by this
-	# command - we just pass the $prefix to --recursive-prefix.
-	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update \
 		${GIT_QUIET:+--quiet} \
 		${force:+--force} \
 		${progress:+--progress} \
-- 
2.33.GIT


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

* Re: [PATCH v7 17/20] submodule: move core cmd_update() logic to C
  2022-02-10  9:28             ` [PATCH v7 17/20] submodule: move core cmd_update() logic to C Glen Choo
@ 2022-02-10  9:34               ` Glen Choo
  0 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-10  9:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason


Here is the diff between this tree (+) and that of v5's [1] (-).

[1] https://lore.kernel.org/git/patch-v5-9.9-e8e57606ee9-20220128T125206Z-avarab@gmail.com

----- >8 --------- >8 --------- >8 --------- >8 --------- >8 ----

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1c28b6f479..b895e88a64 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2003,6 +2003,7 @@ struct update_data {
 	const char *recursive_prefix;
 	const char *sm_path;
 	const char *displaypath;
+	const char *update_default;
 	struct object_id oid;
 	struct object_id suboid;
 	struct submodule_update_strategy update_strategy;
@@ -2355,15 +2356,8 @@ static int run_update_command(struct update_data *ud, int subforce)
 	struct child_process cp = CHILD_PROCESS_INIT;
 	char *oid = oid_to_hex(&ud->oid);
 	int must_die_on_failure = 0;
-	struct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;
 
-	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) {
+	switch (ud->update_strategy.type) {
 	case SM_UPDATE_CHECKOUT:
 		cp.git_cmd = 1;
 		strvec_pushl(&cp.args, "checkout", "-q", NULL);
@@ -2386,45 +2380,41 @@ static int run_update_command(struct update_data *ud, int subforce)
 		break;
 	case SM_UPDATE_COMMAND:
 		cp.use_shell = 1;
-		strvec_push(&cp.args, strategy.command);
+		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(&strategy));
+		    submodule_strategy_to_string(&ud->update_strategy));
 	}
 	strvec_push(&cp.args, oid);
 
 	cp.dir = xstrdup(ud->sm_path);
 	prepare_submodule_repo_env(&cp.env_array);
 	if (run_command(&cp)) {
-		switch (strategy.type) {
+		switch (ud->update_strategy.type) {
 		case SM_UPDATE_CHECKOUT:
 			die_message(_("Unable to checkout '%s' in submodule path '%s'"),
 				    oid, ud->displaypath);
 			break;
 		case SM_UPDATE_REBASE:
-			if (!must_die_on_failure)
-				break;
-			die(_("Unable to rebase '%s' in submodule path '%s'"),
+			die_message(_("Unable to rebase '%s' in submodule path '%s'"),
 			    oid, ud->displaypath);
 			break;
 		case SM_UPDATE_MERGE:
-			if (!must_die_on_failure)
-				break;
-			die(_("Unable to merge '%s' in submodule path '%s'"),
+			die_message(_("Unable to merge '%s' in submodule path '%s'"),
 			    oid, ud->displaypath);
 			break;
 		case SM_UPDATE_COMMAND:
-			if (!must_die_on_failure)
-				break;
-			die(_("Execution of '%s %s' failed in submodule path '%s'"),
-			    strategy.command, oid, ud->displaypath);
+			die_message(_("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(&strategy));
+			    submodule_strategy_to_string(&ud->update_strategy));
 		}
+		if (must_die_on_failure)
+			exit(128);
 
 		/* the command failed, but update must continue */
 		return 1;
@@ -2433,7 +2423,7 @@ static int run_update_command(struct update_data *ud, int subforce)
 	if (ud->quiet)
 		return 0;
 
-	switch (strategy.type) {
+	switch (ud->update_strategy.type) {
 	case SM_UPDATE_CHECKOUT:
 		printf(_("Submodule path '%s': checked out '%s'\n"),
 		       ud->displaypath, oid);
@@ -2448,11 +2438,11 @@ static int run_update_command(struct update_data *ud, int subforce)
 		break;
 	case SM_UPDATE_COMMAND:
 		printf(_("Submodule path '%s': '%s %s'\n"),
-		       ud->displaypath, strategy.command, oid);
+		       ud->displaypath, ud->update_strategy.command, oid);
 		break;
 	default:
 		BUG("unexpected update strategy type: %s",
-		    submodule_strategy_to_string(&strategy));
+		    submodule_strategy_to_string(&ud->update_strategy));
 	}
 
 	return 0;
@@ -2832,10 +2822,12 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
 
 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);
+	/*
+	 * NEEDSWORK: the equivalent code in git-submodule.sh does not
+	 * pass --prefix, so this shouldn't either
+	*/
 	if (update_data->prefix)
 		strvec_pushl(args, "--prefix", update_data->prefix, NULL);
 	if (update_data->recursive_prefix)
@@ -2859,8 +2851,8 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *
 		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->update_default)
+		strvec_pushl(args, "--update", update_data->update_default, NULL);
 	if (update_data->references.nr) {
 		struct string_list_item *item;
 		for_each_string_list_item(item, &update_data->references)
@@ -2890,6 +2882,11 @@ static int update_submodule(struct update_data *update_data)
 							     update_data->prefix);
 	free(prefixed_path);
 
+	determine_submodule_update_strategy(the_repository, update_data->just_cloned,
+					    update_data->sm_path, update_data->update_default,
+					    &update_data->update_strategy);
+
+	/* NEEDSWORK: fix the style issues e.g. braces */
 	if (update_data->just_cloned) {
 		oidcpy(&update_data->suboid, null_oid());
 	} else {
@@ -3000,10 +2997,10 @@ static int update_submodules(struct update_data *update_data)
 
 static int module_update(int argc, const char **argv, const char *prefix)
 {
-	const char *update = NULL;
 	struct pathspec pathspec;
 	struct update_data opt = UPDATE_DATA_INIT;
 
+	/* NEEDSWORK: update names and strings */
 	struct option module_update_clone_options[] = {
 		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
@@ -3021,7 +3018,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 			   N_("path"),
 			   N_("path into the working tree, across nested "
 			      "submodule boundaries")),
-		OPT_STRING(0, "update", &update,
+		OPT_STRING(0, "update", &opt.update_default,
 			   N_("string"),
 			   N_("rebase, merge, checkout or none")),
 		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
@@ -3058,8 +3055,8 @@ static int module_update(int argc, const char **argv, const char *prefix)
 	oidcpy(&opt.oid, null_oid());
 	oidcpy(&opt.suboid, null_oid());
 
-	if (update)
-		if (parse_submodule_update_strategy(update,
+	if (opt.update_default)
+		if (parse_submodule_update_strategy(opt.update_default,
 						    &opt.update_strategy) < 0)
 			die(_("bad value for update parameter"));
 
@@ -3490,6 +3487,7 @@ static struct cmd_struct commands[] = {
 	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
 	{"deinit", module_deinit, 0},
 	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
+	/* NEEDSWORK: remote-branch is also obsolete */
 	{"remote-branch", resolve_remote_submodule_branch, 0},
 	{"push-check", push_check, 0},
 	{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --git a/git-submodule.sh b/git-submodule.sh
index bcd8b92aab..d176469fb1 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -50,6 +50,7 @@ single_branch=
 jobs=
 recommend_shallow=
 
+# NEEDSWORK this is now unused
 die_if_unmatched ()
 {
 	if test "$1" = "#unmatched"
@@ -347,6 +348,8 @@ cmd_update()
 		shift
 	done
 
+	# NEEDSWORK --super-prefix isn't actually supported by this
+	# command - we just pass the $prefix to --recursive-prefix.
 	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper update \
 		${GIT_QUIET:+--quiet} \
 		${force:+--force} \

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

* Re: [PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath()
  2022-02-10  9:28             ` [PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath() Glen Choo
@ 2022-02-12 14:24               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:24 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> From: Atharva Raykar <raykar.ath@gmail.com>
>
> 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>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.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 4c7c1e1432..5efceb9d46 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)

Nit: overly long line (also in my v5, but since we're applying some
final polishing touches...)

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

* Re: [PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule()
  2022-02-10  9:28             ` [PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule() Glen Choo
@ 2022-02-12 14:30               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:30 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> From: Atharva Raykar <raykar.ath@gmail.com>
>
> 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>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>  builtin/submodule--helper.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 5efceb9d46..09cda67c1e 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 { 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)

Note/nit on existing (pre this series) code, I wonder why we ended up
with this init_submodule() v.s. init_submodule_cb() indirection,
v.s. just doing:

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 09cda67c1ea..aa82abeb37a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -611,9 +611,14 @@ struct init_cb {
 };
 #define INIT_CB_INIT { 0 }
 
-static void init_submodule(const char *path, const char *prefix,
-			   const char *superprefix, unsigned int flags)
+static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 {
+	const char *path = list_item->name;
+	struct init_cb *info = cb_data;
+	const char *prefix = info->prefix;
+	const char *superprefix = info->superprefix ? info->superprefix :
+		get_super_prefix();
+	unsigned int flags = info->flags;
 	const struct submodule *sub;
 	struct strbuf sb = STRBUF_INIT;
 	char *upd = NULL, *url = NULL, *displaypath;
@@ -692,12 +697,6 @@ static void init_submodule(const char *path, const char *prefix,
 	free(upd);
 }
 
-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->superprefix, info->flags);
-}
-
 static int module_init(int argc, const char **argv, const char *prefix)
 {
 	struct init_cb info = INIT_CB_INIT;

Maybe it's worth it to declare the variables in the argument list
v.s. the function.

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

* Re: [PATCH v7 04/20] submodule--helper: run update using child process struct
  2022-02-10  9:28             ` [PATCH v7 04/20] submodule--helper: run update using child process struct Glen Choo
@ 2022-02-12 14:33               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:33 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> From: Atharva Raykar <raykar.ath@gmail.com>
>
> 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>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.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 09cda67c1e..db71e6f4ec 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -2344,47 +2344,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'"),

If this series is re-arranged so that this comes first, this compiles
just fine & passes all tests.

So I wonder if we can peel this and perhaps other such easy to review
prep changes off into its own series, since this one has grown to 20
patches.

We could then hopefully fast-track those easy-to-review prep changes,
which would make the "real" series to follow smaller and easier to
review/grok.

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

* Re: [PATCH v7 09/20] submodule--helper: remove update-module-mode
  2022-02-10  9:28             ` [PATCH v7 09/20] submodule--helper: remove update-module-mode Glen Choo
@ 2022-02-12 14:35               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:35 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> This is dead code - it has not been used since c51f8f94e5
> (submodule--helper: run update procedures from C, 2021-08-24).
>
> Signed-off-by: Glen Choo <chooglen@google.com>
> ---
>  builtin/submodule--helper.c | 24 ------------------------
>  1 file changed, 24 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 4a0890954e..e0cc1c1b79 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -1965,29 +1965,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;
> @@ -3388,7 +3365,6 @@ static struct cmd_struct commands[] = {
>  	{"name", module_name, 0},
>  	{"clone", module_clone, 0},
>  	{"add", module_add, SUPPORT_SUPER_PREFIX},
> -	{"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},

Nice catch!

Re my comment on 04/20 in <220212.86y22gxig0.gmgdl@evledraar.gmail.com>
at least 04..09/20 could be split into such a "trivial refactors for
later changes" series, and it would make sense to lead with this (and
any other deletions of already-dead code).

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

* Re: [PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote
  2022-02-10  9:28             ` [PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote Glen Choo
@ 2022-02-12 14:38               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:38 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

>  #define UPDATE_DATA_INIT { \
>  	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
> @@ -2585,6 +2571,8 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
>  		OPT_CALLBACK_F(0, "oid", &opt.oid, N_("sha1"),
>  			       N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
>  			       parse_opt_object_id),
> +		OPT_BOOL(0, "remote", &opt.remote,
> +			 N_("use SHA-1 of submodule's remote tracking branch")),

For some things the references to SHA-1 are faithfully copying existing
test, but for new things let's use "object" instead.

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

* Re: [PATCH v7 15/20] submodule--helper: move functions around
  2022-02-10  9:28             ` [PATCH v7 15/20] submodule--helper: move functions around Glen Choo
@ 2022-02-12 14:41               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:41 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> A subsequent commit will change the internals of several functions and
> arrange them in a more logical manner. Move these functions to their
> final positions so that the diff is smaller.

Shouldn't we do this earlier & avoid the FIXME comment in 10/20? (maybe
a subsequent fixup addresses it, haven't checked...)

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

* Re: [PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid
  2022-02-10  9:28             ` [PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid Glen Choo
@ 2022-02-12 14:41               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:41 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> Signed-off-by: Glen Choo <chooglen@google.com>
> ---
>  builtin/submodule--helper.c | 11 ++++-------
>  1 file changed, 4 insertions(+), 7 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index b895e88a64..98d8910930 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -2886,14 +2886,11 @@ static int update_submodule(struct update_data *update_data)
>  					    update_data->sm_path, update_data->update_default,
>  					    &update_data->update_strategy);
>  
> -	/* NEEDSWORK: fix the style issues e.g. braces */
> -	if (update_data->just_cloned) {
> +	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);
> -	}
> +	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);

This fixup looks good, let's apply this fix-up to the relevant preceding
commit.

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

* Re: [PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote
  2022-02-10  9:28             ` [PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote Glen Choo
@ 2022-02-12 14:43               ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:43 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> Signed-off-by: Glen Choo <chooglen@google.com>
> ---
>  builtin/submodule--helper.c | 19 -------------------
>  1 file changed, 19 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 98d8910930..5d5302b50b 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -2516,23 +2516,6 @@ static const char *remote_submodule_branch(const char *path)
>  	return branch;
>  }
>  
> -static int resolve_remote_submodule_branch(int argc, const char **argv,
> -		const char *prefix)
> -{
> -	const char *ret;
> -	struct strbuf sb = STRBUF_INIT;
> -	if (argc != 2)
> -		die("submodule--helper remote-branch takes exactly one arguments, got %d", argc);
> -
> -	ret = remote_submodule_branch(argv[1]);
> -	if (!ret)
> -		die("submodule %s doesn't exist", argv[1]);
> -
> -	printf("%s", ret);
> -	strbuf_release(&sb);
> -	return 0;
> -}
> -
>  static int push_check(int argc, const char **argv, const char *prefix)
>  {
>  	struct remote *remote;
> @@ -3484,8 +3467,6 @@ static struct cmd_struct commands[] = {
>  	{"sync", module_sync, SUPPORT_SUPER_PREFIX},
>  	{"deinit", module_deinit, 0},
>  	{"summary", module_summary, SUPPORT_SUPER_PREFIX},
> -	/* NEEDSWORK: remote-branch is also obsolete */
> -	{"remote-branch", resolve_remote_submodule_branch, 0},
>  	{"push-check", push_check, 0},
>  	{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
>  	{"is-active", is_active, 0},

Ditto good fix-up, should squash this into the relevant commit.

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (19 preceding siblings ...)
  2022-02-10  9:28             ` [PATCH v7 20/20] fixup! submodule: move core cmd_update() logic to C Glen Choo
@ 2022-02-12 14:45             ` Ævar Arnfjörð Bjarmason
  2022-02-17  5:44               ` Glen Choo
  2022-02-13  5:54             ` Junio C Hamano
  21 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-12 14:45 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 10 2022, Glen Choo wrote:

> This reroll contains another 'easy' preparatory patch and the fixups I
> alluded to in v6 [1]. This isn't the split-up I described in the
> footnote of v6, but it gets the big patch (patch 17) to what I think is
> a reviewable state.
>
> The diff between v7 and v5 is no longer just NEEDSWORK comments, but I
> think it is easier to reason about. Patch 17 resembles v5 the most (I
> will include a diff in a reply to that patch); everything after patch 17
> is fixups (I did not squash them in because they would grow the diff
> even more).
>
> I will also leave a review on patch 17 since the changes were not
> originally authored by me.
>
> [1] https://lore.kernel.org/git/20220208083952.35036-1-chooglen@google.com
>
> Changes in v7:
> - Split the last patch of v6 (the big one) into patches 16-17.
> - Patch 16 moves logic out of run_update_procedure() (because the
>   command is going away), removing some noise from patch 17. This makes
>   the update_strategy parsing easier to reason about, but at the cost of
>   growing the diff vis-a-vis v5
> - Patches 18-20 are fixups that address NEEDSWORK comments from earlier
>   patches. Once maintaining a small diff vis-a-vis v5 stops making
>   sense, I will squash them in.
>
> Atharva Raykar (6):
>   submodule--helper: get remote names from any repository
>   submodule--helper: refactor get_submodule_displaypath()
>   submodule--helper: allow setting superprefix for init_submodule()
>   submodule--helper: run update using child process struct
>   builtin/submodule--helper.c: reformat designated initializers
>   submodule: move core cmd_update() logic to C
>
> Glen Choo (11):
>   submodule--helper: remove update-module-mode
>   submodule--helper: reorganize code for sh to C conversion
>   submodule--helper run-update-procedure: remove --suboid
>   submodule--helper run-update-procedure: learn --remote
>   submodule--helper: remove ensure-core-worktree
>   submodule--helper update-clone: learn --init
>   submodule--helper: move functions around
>   submodule--helper: reduce logic in run_update_procedure()
>   fixup! submodule--helper run-update-procedure: remove --suboid
>   fixup! submodule--helper run-update-procedure: learn --remote
>   fixup! submodule: move core cmd_update() logic to C
>
> Ævar Arnfjörð Bjarmason (3):
>   builtin/submodule--helper.c: rename option variables to "opt"
>   submodule--helper: don't use bitfield indirection for parse_options()
>   submodule tests: test for init and update failure output

Thanks a lot for picking this up! This split-up is much easier to read
than my v5, particularly with the end diff-stat of the "main" patch
being:

 2 files changed, 201 insertions(+), 216 deletions(-)

Instead of:

 2 files changed, 356 insertions(+), 388 deletions(-)

I think sending a version of this with the fixups squashed in as a v8
would be good, and perhaps addressing some of my comments.

I don't know if my suggested split-up of "prep fixes" into another
series would be a good thing to pursue overall, perhaps Junio will chime
in on how he'd be most comfortable in merging this down. I'd think
splitting such trivial fixes into their own series be easier to review,
but perhaps not.

For the Signed-off-by question on v6, I think you should add your SOB to
all the patches you submit. See this in SubmittingPatches:
    
    Notice that you can place your own `Signed-off-by` trailer when
    forwarding somebody else's patch with the above rules for
    D-C-O.  Indeed you are encouraged to do so.

Just running "git rebase -i -x 'git commit --amend --no-edit -s'" should
do it.
    

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
                               ` (20 preceding siblings ...)
  2022-02-12 14:45             ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
@ 2022-02-13  5:54             ` Junio C Hamano
  2022-02-13  6:14               ` Junio C Hamano
  21 siblings, 1 reply; 142+ messages in thread
From: Junio C Hamano @ 2022-02-13  5:54 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

Glen Choo <chooglen@google.com> writes:

> This reroll contains another 'easy' preparatory patch and the fixups I
> alluded to in v6 [1]. This isn't the split-up I described in the
> footnote of v6, but it gets the big patch (patch 17) to what I think is
> a reviewable state.

Thanks.

This seems to heavily conflict with "clone, submodule: pass partial
clone filters to submodules, 2022-02-04" by Josh Steadmon
<690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>
in both builtins/submodule--helper.c and git-submodule.sh.

It also removes the code that "submodule: record superproject gitdir
during 'update', 2022-02-03" by Emily Shaffer
<20220203215914.683922-5-emilyshaffer@google.com>, so what the other
topic ends up adding to the shell script needs to eventually be
redone in the C code.

I think "superproject aware" topic would see a reroll due to a
slight redesign.  I am not sure how solid the design of the
"pass down partial clone filter" topic is at this moment.

I may try to eject them tentatively and see how well this topic
plays with the rest of the topics in flight.

Thanks.



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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-13  5:54             ` Junio C Hamano
@ 2022-02-13  6:14               ` Junio C Hamano
  2022-02-14 16:37                 ` Glen Choo
  0 siblings, 1 reply; 142+ messages in thread
From: Junio C Hamano @ 2022-02-13  6:14 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

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

> Glen Choo <chooglen@google.com> writes:
>
>> This reroll contains another 'easy' preparatory patch and the fixups I
>> alluded to in v6 [1]. This isn't the split-up I described in the
>> footnote of v6, but it gets the big patch (patch 17) to what I think is
>> a reviewable state.
>
> Thanks.
>
> This seems to heavily conflict with "clone, submodule: pass partial
> clone filters to submodules, 2022-02-04" by Josh Steadmon
> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>
> in both builtins/submodule--helper.c and git-submodule.sh.
>
> It also removes the code that "submodule: record superproject gitdir
> during 'update', 2022-02-03" by Emily Shaffer
> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other
> topic ends up adding to the shell script needs to eventually be
> redone in the C code.
>
> I think "superproject aware" topic would see a reroll due to a
> slight redesign.  I am not sure how solid the design of the
> "pass down partial clone filter" topic is at this moment.
>
> I may try to eject them tentatively and see how well this topic
> plays with the rest of the topics in flight.
>
> Thanks.

I can merge this to seen minus the above two topics and get it
compile, but it also seems to have some interaction with 961b130d
(branch: add --recurse-submodules option for branch creation,
2022-01-28) and makes the t3207, tests added by that other topic,
fail X-<.









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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-13  6:14               ` Junio C Hamano
@ 2022-02-14 16:37                 ` Glen Choo
  2022-02-14 17:19                   ` Ævar Arnfjörð Bjarmason
                                     ` (2 more replies)
  0 siblings, 3 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-14 16:37 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

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

>> This seems to heavily conflict with "clone, submodule: pass partial
>> clone filters to submodules, 2022-02-04" by Josh Steadmon
>> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>
>> in both builtins/submodule--helper.c and git-submodule.sh.
>>
>> It also removes the code that "submodule: record superproject gitdir
>> during 'update', 2022-02-03" by Emily Shaffer
>> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other
>> topic ends up adding to the shell script needs to eventually be
>> redone in the C code.
>>
>> I think "superproject aware" topic would see a reroll due to a
>> slight redesign.  I am not sure how solid the design of the
>> "pass down partial clone filter" topic is at this moment.

Hm, I haven't looked at where the conflicts are yet, but I'll get to it
as I'm reviewing the rest of the feedback.

And on that note, what do you think of Ævar's suggestion to split off
the 'easy to review' and 'obvious' patches into their own preparatory
series? I wonder if this would make it harder or easier to manage the
conflicts.

> I can merge this to seen minus the above two topics and get it
> compile, but it also seems to have some interaction with 961b130d
> (branch: add --recurse-submodules option for branch creation,
> 2022-01-28) and makes the t3207, tests added by that other topic,
> fail X-<.

Oof, that's embarrassing of me, let me take a look at that. There's a
nontrivial chance that the "branch --recurse-submodules" tests caught an
actual regression.

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-14 16:37                 ` Glen Choo
@ 2022-02-14 17:19                   ` Ævar Arnfjörð Bjarmason
  2022-02-15  9:34                     ` Glen Choo
  2022-02-14 17:34                   ` Junio C Hamano
  2022-02-15  9:47                   ` Glen Choo
  2 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-14 17:19 UTC (permalink / raw)
  To: Glen Choo
  Cc: Junio C Hamano, git, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Tue, Feb 15 2022, Glen Choo wrote:

> Junio C Hamano <gitster@pobox.com> writes:
>
>>> This seems to heavily conflict with "clone, submodule: pass partial
>>> clone filters to submodules, 2022-02-04" by Josh Steadmon
>>> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>
>>> in both builtins/submodule--helper.c and git-submodule.sh.
>>>
>>> It also removes the code that "submodule: record superproject gitdir
>>> during 'update', 2022-02-03" by Emily Shaffer
>>> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other
>>> topic ends up adding to the shell script needs to eventually be
>>> redone in the C code.
>>>
>>> I think "superproject aware" topic would see a reroll due to a
>>> slight redesign.  I am not sure how solid the design of the
>>> "pass down partial clone filter" topic is at this moment.
>
> Hm, I haven't looked at where the conflicts are yet, but I'll get to it
> as I'm reviewing the rest of the feedback.

To save you some time, my v4 CL summarizes the semantic conflict between
the two:
https://lore.kernel.org/git/cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com/

I.e. Atharva Raykar had working C code to do what an older version of
that superproject config series was doing, but the semantics changed in
a later version. It needs some new usage of path.c (or similar) API
adjusted, but I didn't (and still don't) have time to look into it.

> [...]
>> I can merge this to seen minus the above two topics and get it
>> compile, but it also seems to have some interaction with 961b130d
>> (branch: add --recurse-submodules option for branch creation,
>> 2022-01-28) and makes the t3207, tests added by that other topic,
>> fail X-<.
>
> Oof, that's embarrassing of me, let me take a look at that. There's a
> nontrivial chance that the "branch --recurse-submodules" tests caught an
> actual regression.

FWIW one thing I did as an extra sanity check was to run the whole test
suite with --tee with/without this series (or rather, my earlier
version), and diffing the full test-results output (which you'll need to
save in-between the two runs, and IIRC hack t/Makefile to stop removing
it on successful runs).

There's a lot of differences in output due to general issues in the test
suite output not being reproducable (writing timestamps etc.), but I
could not find any issues with the "git submodule" output being
different, of course we may not have tests, or it may be piped to
/dev/null....

But I've found it to be a helpful additional validation technique for
this series & others where I'm not as confident in the test coverage.


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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-14 16:37                 ` Glen Choo
  2022-02-14 17:19                   ` Ævar Arnfjörð Bjarmason
@ 2022-02-14 17:34                   ` Junio C Hamano
  2022-02-15  9:31                     ` Glen Choo
  2022-02-15  9:47                   ` Glen Choo
  2 siblings, 1 reply; 142+ messages in thread
From: Junio C Hamano @ 2022-02-14 17:34 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

Glen Choo <chooglen@google.com> writes:

> Hm, I haven't looked at where the conflicts are yet, but I'll get to it
> as I'm reviewing the rest of the feedback.
>
> And on that note, what do you think of Ævar's suggestion to split off
> the 'easy to review' and 'obvious' patches into their own preparatory
> series? I wonder if this would make it harder or easier to manage the
> conflicts.

It depends on how small an interaction the "obvious and easy" part
has with topics in flight.  In the best case, if there aren't any
the preparatory series may even graduate before the other topics
that interfere with the main part of this series becomes ready.

In a worse case, what the preparatory work to lay more solid
foundation wants to do may contradict what some of these topics in
flight want to do.  Such semantic conflicts need to be resolved
before the main part (and these interfering topics) can move
forward, and with "split off", the core of the contradicting wish
may become easier to see and what needs to be resolved may become
clearer.

So, I do not think of a way for such a split to make things harder
for later.  Of course, the "easy to review" and "obvious" part has
to be justifiable on its own, i.e. "a larger series wants to build
on this foundation and for it to work this part must be done in this
way", when the other topics wants to do the part in question
differently, becomes a much weaker justification.  But if it is
truly "obvious", it is unlikely that the benefit of the change
becomes harder to justify.


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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-14 17:34                   ` Junio C Hamano
@ 2022-02-15  9:31                     ` Glen Choo
  0 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-15  9:31 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla,
	Ævar Arnfjörð Bjarmason

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

> Glen Choo <chooglen@google.com> writes:
>
>> Hm, I haven't looked at where the conflicts are yet, but I'll get to it
>> as I'm reviewing the rest of the feedback.
>>
>> And on that note, what do you think of Ævar's suggestion to split off
>> the 'easy to review' and 'obvious' patches into their own preparatory
>> series? I wonder if this would make it harder or easier to manage the
>> conflicts.
>
> It depends on how small an interaction the "obvious and easy" part
> has with topics in flight.  In the best case, if there aren't any
> the preparatory series may even graduate before the other topics
> that interfere with the main part of this series becomes ready.
>
> In a worse case, what the preparatory work to lay more solid
> foundation wants to do may contradict what some of these topics in
> flight want to do.  Such semantic conflicts need to be resolved
> before the main part (and these interfering topics) can move
> forward, and with "split off", the core of the contradicting wish
> may become easier to see and what needs to be resolved may become
> clearer.
>
> So, I do not think of a way for such a split to make things harder
> for later.  Of course, the "easy to review" and "obvious" part has
> to be justifiable on its own, i.e. "a larger series wants to build
> on this foundation and for it to work this part must be done in this
> way", when the other topics wants to do the part in question
> differently, becomes a much weaker justification.  But if it is
> truly "obvious", it is unlikely that the benefit of the change
> becomes harder to justify.

Thanks for sharing your thought process. That makes sense, I'll do
that :)

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-14 17:19                   ` Ævar Arnfjörð Bjarmason
@ 2022-02-15  9:34                     ` Glen Choo
  0 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-15  9:34 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Junio C Hamano, git, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla

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

> On Tue, Feb 15 2022, Glen Choo wrote:
>
>> Junio C Hamano <gitster@pobox.com> writes:
>>
>>>> This seems to heavily conflict with "clone, submodule: pass partial
>>>> clone filters to submodules, 2022-02-04" by Josh Steadmon
>>>> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>
>>>> in both builtins/submodule--helper.c and git-submodule.sh.
>>>>
>>>> It also removes the code that "submodule: record superproject gitdir
>>>> during 'update', 2022-02-03" by Emily Shaffer
>>>> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other
>>>> topic ends up adding to the shell script needs to eventually be
>>>> redone in the C code.
>>>>
>>>> I think "superproject aware" topic would see a reroll due to a
>>>> slight redesign.  I am not sure how solid the design of the
>>>> "pass down partial clone filter" topic is at this moment.
>>
>> Hm, I haven't looked at where the conflicts are yet, but I'll get to it
>> as I'm reviewing the rest of the feedback.
>
> To save you some time, my v4 CL summarizes the semantic conflict between
> the two:
> https://lore.kernel.org/git/cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com/
>
> I.e. Atharva Raykar had working C code to do what an older version of
> that superproject config series was doing, but the semantics changed in
> a later version. It needs some new usage of path.c (or similar) API
> adjusted, but I didn't (and still don't) have time to look into it.

Ah, thanks for the reminder. That should help.

>>> I can merge this to seen minus the above two topics and get it
>>> compile, but it also seems to have some interaction with 961b130d
>>> (branch: add --recurse-submodules option for branch creation,
>>> 2022-01-28) and makes the t3207, tests added by that other topic,
>>> fail X-<.
>>
>> Oof, that's embarrassing of me, let me take a look at that. There's a
>> nontrivial chance that the "branch --recurse-submodules" tests caught an
>> actual regression.
>
> FWIW one thing I did as an extra sanity check was to run the whole test
> suite with --tee with/without this series (or rather, my earlier
> version), and diffing the full test-results output (which you'll need to
> save in-between the two runs, and IIRC hack t/Makefile to stop removing
> it on successful runs).
>
> There's a lot of differences in output due to general issues in the test
> suite output not being reproducable (writing timestamps etc.), but I
> could not find any issues with the "git submodule" output being
> different, of course we may not have tests, or it may be piped to
> /dev/null....
>
> But I've found it to be a helpful additional validation technique for
> this series & others where I'm not as confident in the test coverage.

Thanks for the tip! I hadn't considered trying this, but this makes a
lot of sense. I can see this being even more useful for this series
since it's supposed to be a faithful conversion of sh->c.

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-14 16:37                 ` Glen Choo
  2022-02-14 17:19                   ` Ævar Arnfjörð Bjarmason
  2022-02-14 17:34                   ` Junio C Hamano
@ 2022-02-15  9:47                   ` Glen Choo
  2 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-15  9:47 UTC (permalink / raw)
  To: Junio C Hamano, Ævar Arnfjörð Bjarmason
  Cc: git, Atharva Raykar, Christian Couder, Emily Shaffer,
	Jonathan Nieder, Kaartic Sivaraam, pc44800, Shourya Shukla

Glen Choo <chooglen@google.com> writes:

> Junio C Hamano <gitster@pobox.com> writes:
>
>> I can merge this to seen minus the above two topics and get it
>> compile, but it also seems to have some interaction with 961b130d
>> (branch: add --recurse-submodules option for branch creation,
>> 2022-01-28) and makes the t3207, tests added by that other topic,
>> fail X-<.
>
> Oof, that's embarrassing of me, let me take a look at that. There's a
> nontrivial chance that the "branch --recurse-submodules" tests caught an
> actual regression.

Looks like this is the case - t3207 caught a regression in how "git
submodule update" sets the refspec of nested submodules.

Looks like our concerns about the test suite are well-founded..

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-12 14:45             ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
@ 2022-02-17  5:44               ` Glen Choo
  2022-02-17  9:17                 ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 142+ messages in thread
From: Glen Choo @ 2022-02-17  5:44 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla

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

> On Thu, Feb 10 2022, Glen Choo wrote:
>
>> Atharva Raykar (6):
>>   submodule--helper: get remote names from any repository
>>   submodule--helper: refactor get_submodule_displaypath()
>>   submodule--helper: allow setting superprefix for init_submodule()
>>   submodule--helper: run update using child process struct
>>   builtin/submodule--helper.c: reformat designated initializers
>>   submodule: move core cmd_update() logic to C
>>
>> Glen Choo (11):
>>   submodule--helper: remove update-module-mode
>>   submodule--helper: reorganize code for sh to C conversion
>>   submodule--helper run-update-procedure: remove --suboid
>>   submodule--helper run-update-procedure: learn --remote
>>   submodule--helper: remove ensure-core-worktree
>>   submodule--helper update-clone: learn --init
>>   submodule--helper: move functions around
>>   submodule--helper: reduce logic in run_update_procedure()
>>   fixup! submodule--helper run-update-procedure: remove --suboid
>>   fixup! submodule--helper run-update-procedure: learn --remote
>>   fixup! submodule: move core cmd_update() logic to C
>>
>> Ævar Arnfjörð Bjarmason (3):
>>   builtin/submodule--helper.c: rename option variables to "opt"
>>   submodule--helper: don't use bitfield indirection for parse_options()
>>   submodule tests: test for init and update failure output
>
> I think sending a version of this with the fixups squashed in as a v8
> would be good, and perhaps addressing some of my comments.
>
> I don't know if my suggested split-up of "prep fixes" into another
> series would be a good thing to pursue overall, perhaps Junio will chime
> in on how he'd be most comfortable in merging this down. I'd think
> splitting such trivial fixes into their own series be easier to review,
> but perhaps not.

Combing through the patches again, I couldn't really convince myself
that the patch 4..9 prep fixes make sense as obvious standalone fixes,
except maybe:

- patch 4 submodule--helper: run update using child process struct
- patch 8 submodule tests: test for init and update failure output
- patch 9:  087bf43aba submodule--helper: remove update-module-mode

But, since the 'final' patch (ignoring the fixup!-s) is consuming a huge
chunk of the work anyway, here's an alternative patch organization with
the fixup!-s squashed:

= Move 'easy' and 'obviously correct' code from sh->C
- patches 8-9   Cleanup and introduce tests
- patches 1-4   Refactor existing functions, which enables..
- patches 10-14 Move 'obviously correct' pieces of logic from sh-> C

= Finalize move from sh->C
i.e. combine "run-update-procedure" and "update-clone" into "update"
- patches 5,7     Cleanup and prep
- patches 6,15-16 Shrinking the diff
- patch 17        Implement "git submodule--helper update" 

I'll send this if there are no objections :)

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-17  5:44               ` Glen Choo
@ 2022-02-17  9:17                 ` Ævar Arnfjörð Bjarmason
  2022-02-17 16:14                   ` Glen Choo
  0 siblings, 1 reply; 142+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-17  9:17 UTC (permalink / raw)
  To: Glen Choo
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla


On Thu, Feb 17 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> On Thu, Feb 10 2022, Glen Choo wrote:
>>
>>> Atharva Raykar (6):
>>>   submodule--helper: get remote names from any repository
>>>   submodule--helper: refactor get_submodule_displaypath()
>>>   submodule--helper: allow setting superprefix for init_submodule()
>>>   submodule--helper: run update using child process struct
>>>   builtin/submodule--helper.c: reformat designated initializers
>>>   submodule: move core cmd_update() logic to C
>>>
>>> Glen Choo (11):
>>>   submodule--helper: remove update-module-mode
>>>   submodule--helper: reorganize code for sh to C conversion
>>>   submodule--helper run-update-procedure: remove --suboid
>>>   submodule--helper run-update-procedure: learn --remote
>>>   submodule--helper: remove ensure-core-worktree
>>>   submodule--helper update-clone: learn --init
>>>   submodule--helper: move functions around
>>>   submodule--helper: reduce logic in run_update_procedure()
>>>   fixup! submodule--helper run-update-procedure: remove --suboid
>>>   fixup! submodule--helper run-update-procedure: learn --remote
>>>   fixup! submodule: move core cmd_update() logic to C
>>>
>>> Ævar Arnfjörð Bjarmason (3):
>>>   builtin/submodule--helper.c: rename option variables to "opt"
>>>   submodule--helper: don't use bitfield indirection for parse_options()
>>>   submodule tests: test for init and update failure output
>>
>> I think sending a version of this with the fixups squashed in as a v8
>> would be good, and perhaps addressing some of my comments.
>>
>> I don't know if my suggested split-up of "prep fixes" into another
>> series would be a good thing to pursue overall, perhaps Junio will chime
>> in on how he'd be most comfortable in merging this down. I'd think
>> splitting such trivial fixes into their own series be easier to review,
>> but perhaps not.
>
> Combing through the patches again, I couldn't really convince myself
> that the patch 4..9 prep fixes make sense as obvious standalone fixes,
> except maybe:
>
> - patch 4 submodule--helper: run update using child process struct
> - patch 8 submodule tests: test for init and update failure output
> - patch 9:  087bf43aba submodule--helper: remove update-module-mode
>
> But, since the 'final' patch (ignoring the fixup!-s) is consuming a huge
> chunk of the work anyway, here's an alternative patch organization with
> the fixup!-s squashed:
>
> = Move 'easy' and 'obviously correct' code from sh->C
> - patches 8-9   Cleanup and introduce tests
> - patches 1-4   Refactor existing functions, which enables..
> - patches 10-14 Move 'obviously correct' pieces of logic from sh-> C
>
> = Finalize move from sh->C
> i.e. combine "run-update-procedure" and "update-clone" into "update"
> - patches 5,7     Cleanup and prep
> - patches 6,15-16 Shrinking the diff
> - patch 17        Implement "git submodule--helper update" 
>
> I'll send this if there are no objections :)

Yes that sounds good, or rather, I haven't re-looked at that in detail,
but I think if you think it makes sense we should go for it.

Or rather, we should really be aiming to produce a patch series that
makes sense in its current iteration, as opposed to optimizing for a
diff against some ad-hoc re-roll I produced a few versions ago :)

Thanks again for working on this & picking this up. It's great to see
progress in this area!

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

* Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C
  2022-02-17  9:17                 ` Ævar Arnfjörð Bjarmason
@ 2022-02-17 16:14                   ` Glen Choo
  0 siblings, 0 replies; 142+ messages in thread
From: Glen Choo @ 2022-02-17 16:14 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Atharva Raykar, Christian Couder,
	Emily Shaffer, Jonathan Nieder, Kaartic Sivaraam, pc44800,
	Shourya Shukla

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

> On Thu, Feb 17 2022, Glen Choo wrote:
>
>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>
>>> On Thu, Feb 10 2022, Glen Choo wrote:
>>>
>>>> Atharva Raykar (6):
>>>>   submodule--helper: get remote names from any repository
>>>>   submodule--helper: refactor get_submodule_displaypath()
>>>>   submodule--helper: allow setting superprefix for init_submodule()
>>>>   submodule--helper: run update using child process struct
>>>>   builtin/submodule--helper.c: reformat designated initializers
>>>>   submodule: move core cmd_update() logic to C
>>>>
>>>> Glen Choo (11):
>>>>   submodule--helper: remove update-module-mode
>>>>   submodule--helper: reorganize code for sh to C conversion
>>>>   submodule--helper run-update-procedure: remove --suboid
>>>>   submodule--helper run-update-procedure: learn --remote
>>>>   submodule--helper: remove ensure-core-worktree
>>>>   submodule--helper update-clone: learn --init
>>>>   submodule--helper: move functions around
>>>>   submodule--helper: reduce logic in run_update_procedure()
>>>>   fixup! submodule--helper run-update-procedure: remove --suboid
>>>>   fixup! submodule--helper run-update-procedure: learn --remote
>>>>   fixup! submodule: move core cmd_update() logic to C
>>>>
>>>> Ævar Arnfjörð Bjarmason (3):
>>>>   builtin/submodule--helper.c: rename option variables to "opt"
>>>>   submodule--helper: don't use bitfield indirection for parse_options()
>>>>   submodule tests: test for init and update failure output
>>>
>>> I think sending a version of this with the fixups squashed in as a v8
>>> would be good, and perhaps addressing some of my comments.
>>>
>>> I don't know if my suggested split-up of "prep fixes" into another
>>> series would be a good thing to pursue overall, perhaps Junio will chime
>>> in on how he'd be most comfortable in merging this down. I'd think
>>> splitting such trivial fixes into their own series be easier to review,
>>> but perhaps not.
>>
>> Combing through the patches again, I couldn't really convince myself
>> that the patch 4..9 prep fixes make sense as obvious standalone fixes,
>> except maybe:
>>
>> - patch 4 submodule--helper: run update using child process struct
>> - patch 8 submodule tests: test for init and update failure output
>> - patch 9:  087bf43aba submodule--helper: remove update-module-mode
>>
>> But, since the 'final' patch (ignoring the fixup!-s) is consuming a huge
>> chunk of the work anyway, here's an alternative patch organization with
>> the fixup!-s squashed:
>>
>> = Move 'easy' and 'obviously correct' code from sh->C
>> - patches 8-9   Cleanup and introduce tests
>> - patches 1-4   Refactor existing functions, which enables..
>> - patches 10-14 Move 'obviously correct' pieces of logic from sh-> C
>>
>> = Finalize move from sh->C
>> i.e. combine "run-update-procedure" and "update-clone" into "update"
>> - patches 5,7     Cleanup and prep
>> - patches 6,15-16 Shrinking the diff
>> - patch 17        Implement "git submodule--helper update" 
>>
>> I'll send this if there are no objections :)
>
> Yes that sounds good, or rather, I haven't re-looked at that in detail,
> but I think if you think it makes sense we should go for it.
>
> Or rather, we should really be aiming to produce a patch series that
> makes sense in its current iteration, as opposed to optimizing for a
> diff against some ad-hoc re-roll I produced a few versions ago :)

Agreed, makes sense.

> Thanks again for working on this & picking this up. It's great to see
> progress in this area!

Thanks to you too for getting the ball rolling and lending me your
thoughts :)

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

end of thread, other threads:[~2022-02-17 16:14 UTC | newest]

Thread overview: 142+ 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-12-03 19:00         ` Junio C Hamano
2021-12-03 20:15           ` Ævar Arnfjörð Bjarmason
2021-12-04 10:38           ` Atharva Raykar
2022-01-27 16:22     ` [PATCH v4 0/7] " Ævar Arnfjörð Bjarmason
2022-01-27 16:22       ` [PATCH v4 1/7] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
2022-01-27 18:45         ` Glen Choo
2022-01-27 16:22       ` [PATCH v4 2/7] submodule--helper: refactor get_submodule_displaypath() Ævar Arnfjörð Bjarmason
2022-01-27 16:22       ` [PATCH v4 3/7] submodule--helper: allow setting superprefix for init_submodule() Ævar Arnfjörð Bjarmason
2022-01-27 16:22       ` [PATCH v4 4/7] submodule--helper: run update using child process struct Ævar Arnfjörð Bjarmason
2022-01-27 16:22       ` [PATCH v4 5/7] builtin/submodule--helper.c: reformat designated initializers Ævar Arnfjörð Bjarmason
2022-01-27 16:22       ` [PATCH v4 6/7] builtin/submodule--helper.c: rename "suc" variable to "opt" Ævar Arnfjörð Bjarmason
2022-01-27 16:22       ` [PATCH v4 7/7] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
2022-01-27 21:55         ` Glen Choo
2022-01-28 12:56       ` [PATCH v5 0/9] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 1/9] submodule--helper: get remote names from any repository Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 2/9] submodule--helper: refactor get_submodule_displaypath() Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 3/9] submodule--helper: allow setting superprefix for init_submodule() Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 4/9] submodule--helper: run update using child process struct Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 5/9] builtin/submodule--helper.c: reformat designated initializers Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 6/9] builtin/submodule--helper.c: rename option variables to "opt" Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 7/9] submodule--helper: don't use bitfield indirection for parse_options() Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 8/9] submodule tests: test for init and update failure output Ævar Arnfjörð Bjarmason
2022-01-28 12:56         ` [PATCH v5 9/9] submodule: move core cmd_update() logic to C Ævar Arnfjörð Bjarmason
2022-02-03  0:18           ` Glen Choo
2022-02-03  2:26             ` Ævar Arnfjörð Bjarmason
2022-02-03  8:15               ` Ævar Arnfjörð Bjarmason
2022-02-03 17:35                 ` Glen Choo
2022-02-08  8:39         ` [PATCH v6 00/16] submodule: convert the rest of 'update' " Glen Choo
2022-02-08  8:39           ` [PATCH v6 01/16] submodule--helper: get remote names from any repository Glen Choo
2022-02-08  8:39           ` [PATCH v6 02/16] submodule--helper: refactor get_submodule_displaypath() Glen Choo
2022-02-08  8:39           ` [PATCH v6 03/16] submodule--helper: allow setting superprefix for init_submodule() Glen Choo
2022-02-08  8:39           ` [PATCH v6 04/16] submodule--helper: run update using child process struct Glen Choo
2022-02-08  8:39           ` [PATCH v6 05/16] builtin/submodule--helper.c: reformat designated initializers Glen Choo
2022-02-08  8:39           ` [PATCH v6 06/16] builtin/submodule--helper.c: rename option variables to "opt" Glen Choo
2022-02-08  8:39           ` [PATCH v6 07/16] submodule--helper: don't use bitfield indirection for parse_options() Glen Choo
2022-02-08  8:39           ` [PATCH v6 08/16] submodule tests: test for init and update failure output Glen Choo
2022-02-08  8:39           ` [PATCH v6 09/16] submodule--helper: remove update-module-mode Glen Choo
2022-02-08  8:39           ` [PATCH v6 10/16] submodule--helper: reorganize code for sh to C conversion Glen Choo
2022-02-08  8:39           ` [PATCH v6 11/16] submodule--helper run-update-procedure: remove --suboid Glen Choo
2022-02-08  8:39           ` [PATCH v6 12/16] submodule--helper run-update-procedure: learn --remote Glen Choo
2022-02-08  8:39           ` [PATCH v6 13/16] submodule--helper: remove ensure-core-worktree Glen Choo
2022-02-08  8:39           ` [PATCH v6 14/16] submodule--helper update-clone: learn --init Glen Choo
2022-02-08  8:39           ` [PATCH v6 15/16] submodule--helper: move functions around Glen Choo
2022-02-08  8:39           ` [PATCH v6 16/16] submodule: move core cmd_update() logic to C Glen Choo
2022-02-10  9:28           ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Glen Choo
2022-02-10  9:28             ` [PATCH v7 01/20] submodule--helper: get remote names from any repository Glen Choo
2022-02-10  9:28             ` [PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath() Glen Choo
2022-02-12 14:24               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule() Glen Choo
2022-02-12 14:30               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 04/20] submodule--helper: run update using child process struct Glen Choo
2022-02-12 14:33               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 05/20] builtin/submodule--helper.c: reformat designated initializers Glen Choo
2022-02-10  9:28             ` [PATCH v7 06/20] builtin/submodule--helper.c: rename option variables to "opt" Glen Choo
2022-02-10  9:28             ` [PATCH v7 07/20] submodule--helper: don't use bitfield indirection for parse_options() Glen Choo
2022-02-10  9:28             ` [PATCH v7 08/20] submodule tests: test for init and update failure output Glen Choo
2022-02-10  9:28             ` [PATCH v7 09/20] submodule--helper: remove update-module-mode Glen Choo
2022-02-12 14:35               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 10/20] submodule--helper: reorganize code for sh to C conversion Glen Choo
2022-02-10  9:28             ` [PATCH v7 11/20] submodule--helper run-update-procedure: remove --suboid Glen Choo
2022-02-10  9:28             ` [PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote Glen Choo
2022-02-12 14:38               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 13/20] submodule--helper: remove ensure-core-worktree Glen Choo
2022-02-10  9:28             ` [PATCH v7 14/20] submodule--helper update-clone: learn --init Glen Choo
2022-02-10  9:28             ` [PATCH v7 15/20] submodule--helper: move functions around Glen Choo
2022-02-12 14:41               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 16/20] submodule--helper: reduce logic in run_update_procedure() Glen Choo
2022-02-10  9:28             ` [PATCH v7 17/20] submodule: move core cmd_update() logic to C Glen Choo
2022-02-10  9:34               ` Glen Choo
2022-02-10  9:28             ` [PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid Glen Choo
2022-02-12 14:41               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote Glen Choo
2022-02-12 14:43               ` Ævar Arnfjörð Bjarmason
2022-02-10  9:28             ` [PATCH v7 20/20] fixup! submodule: move core cmd_update() logic to C Glen Choo
2022-02-12 14:45             ` [PATCH v7 00/20] submodule: convert the rest of 'update' " Ævar Arnfjörð Bjarmason
2022-02-17  5:44               ` Glen Choo
2022-02-17  9:17                 ` Ævar Arnfjörð Bjarmason
2022-02-17 16:14                   ` Glen Choo
2022-02-13  5:54             ` Junio C Hamano
2022-02-13  6:14               ` Junio C Hamano
2022-02-14 16:37                 ` Glen Choo
2022-02-14 17:19                   ` Ævar Arnfjörð Bjarmason
2022-02-15  9:34                     ` Glen Choo
2022-02-14 17:34                   ` Junio C Hamano
2022-02-15  9:31                     ` Glen Choo
2022-02-15  9:47                   ` Glen Choo
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 public 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).