[PATCH 2/2] branch: allow recursion with no tracking name

Volodymyr Vriukalo <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <20260822-vv-branch-recurse-no-start-ref-v1-2-46dc140acaa8@zitro.id>
Creating a branch across submodules from a commit that no ref points
  at fails, with the helper's usage text reprinted as an error:

    submodule 'sub': usage: git submodule--helper create-branch [...]
    fatal: submodule 'sub': cannot create branch 'branch-a'

`submodule_create_branch()` runs the helper in a child process because
  `install_branch_config_multiple_remotes()` cannot write config into a
  submodule, and passes the branch name, the start oid and the tracking
  name as three positionals.
`dwim_branch_start()` leaves the tracking name NULL where the start
  point named no ref, and `strvec_pushl()` stops at the first NULL, so
  the child receives two positionals.
`module_create_branch()` requires exactly three and prints its usage.

Make the third positional optional, since a start point that named no
  ref has no tracking name to give and the recursion has nothing to
  track in the submodule either.
Push it separately in the caller too: relying on `strvec_pushl()` to
  stop early leaves the argument dropped by accident rather than by
  intent, and a reader has to know where the terminator falls to see
  that it can go missing at all.

961b130d20 (branch: add --recurse-submodules option for branch
  creation, 2022-01-28) introduced both sides.

This is the same NULL tracking name as the previous patch, reached one
  step earlier: the dry-run pass over the submodules runs before the
  superproject's own `setup_tracking()` call, so with a submodule
  present this failure hides the abort that patch removes.
The new test therefore needs that patch under it.

Assisted-by: An LLM.
Signed-off-by: Volodymyr Vriukalo <[email protected]>
---
 branch.c                    | 10 +++++++++-
 builtin/submodule--helper.c |  7 ++++---
 t/t3207-branch-submodule.sh | 13 +++++++++++++
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/branch.c b/branch.c
index 182fc4a3dd..2dab1f1e35 100644
--- a/branch.c
+++ b/branch.c
@@ -726,7 +726,15 @@ static int submodule_create_branch(struct repository *r,
 		break;
 	}
 
-	strvec_pushl(&child.args, name, start_oid, tracking_name, NULL);
+	/*
+	 * The tracking name is absent when the start point named no ref.
+	 * Push it separately: strvec_pushl() stops at the first NULL, so
+	 * passing it inline would drop the argument by accident rather
+	 * than by intent.
+	 */
+	strvec_pushl(&child.args, name, start_oid, NULL);
+	if (tracking_name)
+		strvec_push(&child.args, tracking_name);
 
 	if ((ret = start_command(&child)))
 		return ret;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1cc82a134d..6895216712 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -3335,7 +3335,7 @@ static int module_create_branch(int argc, const char **argv, const char *prefix,
 		OPT_END()
 	};
 	const char *const usage[] = {
-		N_("git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"),
+		N_("git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> [<start-name>]"),
 		NULL
 	};
 	struct repo_config_values *cfg = repo_config_values(the_repository);
@@ -3344,13 +3344,14 @@ static int module_create_branch(int argc, const char **argv, const char *prefix,
 	track = cfg->branch_track;
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
 
-	if (argc != 3)
+	if (argc < 2 || argc > 3)
 		usage_with_options(usage, options);
 
 	if (!quiet && !dry_run)
 		printf_ln(_("creating branch '%s'"), argv[0]);
 
-	create_branches_recursively(the_repository, argv[0], argv[1], argv[2],
+	create_branches_recursively(the_repository, argv[0], argv[1],
+				    argc > 2 ? argv[2] : NULL,
 				    force, reflog, quiet, track, dry_run);
 	return 0;
 }
diff --git a/t/t3207-branch-submodule.sh b/t/t3207-branch-submodule.sh
index 54f7caeb2f..c56cea31cb 100755
--- a/t/t3207-branch-submodule.sh
+++ b/t/t3207-branch-submodule.sh
@@ -115,6 +115,19 @@ test_expect_success 'should move a branch to a start point that names no ref' '
 	)
 '
 
+test_expect_success 'should recurse into submodules from a start point that names no ref' '
+	test_when_finished "reset_test" &&
+	(
+		cd super &&
+		oid=$(git rev-parse HEAD) &&
+		git branch --recurse-submodules branch-a "$oid" &&
+		git rev-parse branch-a &&
+		git -C sub rev-parse branch-a &&
+		git -C sub/sub-sub rev-parse branch-a &&
+		git -C second/sub rev-parse branch-a
+	)
+'
+
 test_expect_success 'should ignore submodule.recurse when not creating branches' '
 	test_when_finished "reset_test" &&
 	(

-- 
2.55.0.2.g927b4b9963
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.