Merge branch 'vv/branch-recurse-no-start-ref' into jch

The --recurse-submodules option in 'git branch' has been fixed to
avoid a crash when the start point is not a reference (e.g., a raw
object ID).  The creation path now skips setting up tracking and
properly forwards the absent tracking name to the submodule helper.

* vv/branch-recurse-no-start-ref:
  branch: allow recursion with no tracking name
  branch: do not track a start point with no ref
jch
Junio C Hamano 2026-08-31 11:12:01 -07:00
commit 230c2c87f5
3 changed files with 44 additions and 5 deletions

View File

@ -760,7 +760,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;
@ -840,7 +848,7 @@ void create_branches_recursively(struct repository *r, const char *name,
* tedious to determine whether or not tracking was set up in the
* superproject.
*/
if (track)
if (tracking_name && track)
setup_tracking(name, tracking_name, track, quiet);

for (i = 0; i < submodule_entry_list.entry_nr; i++) {

View File

@ -3336,7 +3336,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);
@ -3345,13 +3345,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;
}

View File

@ -98,6 +98,36 @@ test_expect_success 'should respect submodule.recurse when creating branches' '
)
'

test_expect_success 'should move a branch to a start point that names no ref' '
test_when_finished "rm -rf no-submodules" &&
git init no-submodules &&
(
cd no-submodules &&
test_commit one &&
test_commit two &&
git remote add origin . &&
git config submodule.propagateBranches true &&
git config submodule.recurse true &&
git branch branch-a HEAD~1 &&
oid=$(git rev-parse HEAD) &&
git branch -f branch-a "$oid" &&
test_cmp_rev HEAD branch-a
)
'

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" &&
(