[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