git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4 3/3] fetch --negotiate-only: do not update submodules

From
Glen Choo <chooglen@google.com>
Date
Jan 13, 2022, 00:45 UTC
Message-ID
<20220113004501.78822-4-chooglen@google.com>
In-Reply-To
<20220113004501.78822-1-chooglen@google.com>

`git fetch --negotiate-only` is an implementation detail of push negotiation and, unlike most `git fetch` invocations, does not actually update the main repository. Thus it should not update submodules even if submodule recursion is enabled.

This is not just slow, it is wrong e.g. push negotiation with "submodule.recurse=true" will cause submodules to be updated because it invokes `git fetch --negotiate-only`.

Fix this by disabling submodule recursion if --negotiate-only was given. Since this makes --negotiate-only and --recurse-submodules incompatible, check for this invalid combination and die.

This does not use the "goto cleanup" introduced in the previous commit because we want to recurse through submodules whenever a ref is fetched, and this can happen without introducing new objects.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 Documentation/fetch-options.txt |  1 +
 builtin/fetch.c                 | 24 +++++++++++++++++++++++-
 t/t5516-fetch-push.sh           | 12 ++++++++++++
 t/t5702-protocol-v2.sh          | 12 ++++++++++++
 4 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index e967ff1874..f903683189 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -71,6 +71,7 @@ configuration variables documented in linkgit:git-config[1], and the
 	ancestors of the provided `--negotiation-tip=*` arguments,
 	which we have in common with the server.
 +
+This is incompatible with `--recurse-submodules=[yes|on-demand]`.
 Internally this is used to implement the `push.negotiate` option, see
 linkgit:git-config[1].
 
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7bbff5a029..8b8bde8809 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -76,6 +76,7 @@ static struct transport *gtransport;
 static struct transport *gsecondary;
 static const char *submodule_prefix = "";
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
 static int shown_url = 0;
 static struct refspec refmap = REFSPEC_INIT_FETCH;
@@ -167,7 +168,7 @@ static struct option builtin_fetch_options[] = {
 		 N_("prune remote-tracking branches no longer on remote")),
 	OPT_BOOL('P', "prune-tags", &prune_tags,
 		 N_("prune local tags no longer on remote and clobber changed tags")),
-	OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules, N_("on-demand"),
+	OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
 		    N_("control recursive fetching of submodules"),
 		    PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
 	OPT_BOOL(0, "dry-run", &dry_run,
@@ -2014,6 +2015,27 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, prefix,
 			     builtin_fetch_options, builtin_fetch_usage, 0);
+
+	if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+		recurse_submodules = recurse_submodules_cli;
+
+	if (negotiate_only) {
+		switch (recurse_submodules_cli) {
+		case RECURSE_SUBMODULES_OFF:
+		case RECURSE_SUBMODULES_DEFAULT: {
+			/*
+			 * --negotiate-only should never recurse into
+			 * submodules. Skip it by setting recurse_submodules to
+			 * RECURSE_SUBMODULES_OFF.
+			 */
+			recurse_submodules = RECURSE_SUBMODULES_OFF;
+			break;
+		}
+		default:
+			die(_("--negotiate-only and --recurse-submodules cannot be used together"));
+		}
+	}
+
 	if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
 		int *sfjc = submodule_fetch_jobs_config == -1
 			    ? &submodule_fetch_jobs_config : NULL;
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 2f04cf9a1c..87881726ed 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -229,6 +229,18 @@ test_expect_success 'push with negotiation proceeds anyway even if negotiation f
 	test_i18ngrep "push negotiation failed" err
 '
 
+test_expect_success 'push with negotiation does not attempt to fetch submodules' '
+	mk_empty submodule_upstream &&
+	test_commit -C submodule_upstream submodule_commit &&
+	git submodule add ./submodule_upstream submodule &&
+	mk_empty testrepo &&
+	git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
+	test_commit -C testrepo unrelated_commit &&
+	git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
+	git -c submodule.recurse=true -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&
+	! grep "Fetching submodule" err
+'
+
 test_expect_success 'push without wildcard' '
 	mk_empty testrepo &&
 
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 710f33e2aa..1b9023d3f0 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -628,6 +628,18 @@ test_expect_success 'usage: --negotiate-only without --negotiation-tip' '
 	test_cmp err.expect err.actual
 '
 
+test_expect_success 'usage: --negotiate-only with --recurse-submodules' '
+	cat >err.expect <<-\EOF &&
+	fatal: --negotiate-only and --recurse-submodules cannot be used together
+	EOF
+
+	test_must_fail git -c protocol.version=2 -C client fetch \
+		--negotiate-only \
+		--recurse-submodules \
+		origin 2>err.actual &&
+	test_cmp err.expect err.actual
+'
+
 test_expect_success 'file:// --negotiate-only' '
 	SERVER="server" &&
 	URI="file://$(pwd)/server" &&
-- 
2.33.GIT
Previous: Glen ChooNext: Junio C Hamano
Message 27 of 50 in “builtin/fetch: skip unnecessary tasks when using --negotiate-only”
  1. builtin/fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Dec 7, 2021
  2. Jonathan TanDec 9, 2021
  3. Glen ChooDec 9, 2021
  4. Jonathan TanDec 13, 2021
  5. Glen ChooDec 16, 2021
  6. builtin/fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Dec 17, 2021
  7. Junio C HamanoDec 17, 2021
  8. Glen ChooDec 20, 2021
  9. Junio C HamanoDec 20, 2021
  10. Glen ChooDec 20, 2021
  11. Junio C HamanoDec 20, 2021
  12. Glen ChooDec 21, 2021
  13. Glen ChooDec 21, 2021
  14. 0/3 builtin/fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Dec 22, 2021
  15. 1/3 builtin/fetch: use goto cleanup in cmd_fetch()Glen Choo, Dec 22, 2021
  16. 2/3 builtin/fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Dec 22, 2021
  17. Junio C HamanoDec 22, 2021
  18. Glen ChooDec 22, 2021
  19. Junio C HamanoDec 22, 2021
  20. Glen ChooDec 22, 2021
  21. 3/3 builtin/fetch: die on --negotiate-only and --recurse-submodulesGlen Choo, Dec 22, 2021
  22. Junio C HamanoDec 22, 2021
  23. Jonathan TanDec 23, 2021
  24. 0/3 fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Jan 13, 2022
  25. 1/3 fetch: use goto cleanup in cmd_fetch()Glen Choo, Jan 13, 2022
  26. 2/3 fetch: skip tasks related to fetching objectsGlen Choo, Jan 13, 2022
  27. 3/3 fetch --negotiate-only: do not update submodulesGlen Choo, Jan 13, 2022
  28. Junio C HamanoJan 13, 2022
  29. 0/3 fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Jan 18, 2022
  30. 1/3 fetch: use goto cleanup in cmd_fetch()Glen Choo, Jan 18, 2022
  31. 2/3 fetch: skip tasks related to fetching objectsGlen Choo, Jan 18, 2022
  32. 3/3 fetch --negotiate-only: do not update submodulesGlen Choo, Jan 18, 2022
  33. Junio C HamanoJan 18, 2022
  34. Glen ChooJan 18, 2022
  35. Junio C HamanoJan 19, 2022
  36. 0/3 fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Jan 19, 2022
  37. 1/3 fetch: use goto cleanup in cmd_fetch()Glen Choo, Jan 19, 2022
  38. 2/3 fetch: skip tasks related to fetching objectsGlen Choo, Jan 19, 2022
  39. 3/3 fetch --negotiate-only: do not update submodulesGlen Choo, Jan 19, 2022
  40. Jiang XinJan 20, 2022
  41. Glen ChooJan 20, 2022
  42. 0/3 fetch: skip unnecessary tasks when using --negotiate-onlyGlen Choo, Jan 20, 2022
  43. 1/3 fetch: use goto cleanup in cmd_fetch()Glen Choo, Jan 20, 2022
  44. 2/3 fetch: skip tasks related to fetching objectsGlen Choo, Jan 20, 2022
  45. 3/3 fetch --negotiate-only: do not update submodulesGlen Choo, Jan 20, 2022
  46. Junio C HamanoJan 20, 2022
  47. Glen ChooJan 20, 2022
  48. Re* [PATCH v7 0/3] fetch: skip unnecessary tasks when using --negotiate-onlyJunio C Hamano, Jan 20, 2022
  49. Glen ChooJan 20, 2022
  50. Jiang XinJan 21, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.