branch: support more tracking modes when recursing

"git branch --recurse-submodules" does not propagate "--track=inherit" or "--no-track" to submodules, which causes submodule branches to use the wrong tracking mode [1]. To fix this, pass the correct options to the "submodule--helper create-branch" child process and test for it. While we are refactoring the same code, replace "--track" with the synonymous, but more consistent-looking "--track=direct" option (introduced at the same time as "--track=inherit", d3115660b4 (branch: add flags and config to inherit tracking, 2021-12-20)). [1] This bug is partially a timing issue: "branch --recurse-submodules" was introduced around the same time as "--track=inherit", and even though I rebased "branch --recurse-submodules" on top of that, I had neglected to support the new tracking mode. Omitting "--no-track" was just a plain old mistake, though. Signed-off-by: Glen Choo <chooglen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Glen Choo committed Mar 29, 2022 at 20:01 UTC 75388bf5b47678c95f24b58007d2b37d744bf0f7
3 files changed +67 -7
branch.c
+26 -3
@@ -233,6 +233,9 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
233 struct string_list tracking_srcs = STRING_LIST_INIT_DUP;
234 int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
235
236 + if (!track)
237 + BUG("asked to set up tracking, but tracking is disallowed");
238 +
239 memset(&tracking, 0, sizeof(tracking));
240 tracking.spec.dst = (char *)orig_ref;
241 tracking.srcs = &tracking_srcs;
@@ -529,8 +532,27 @@ static int submodule_create_branch(struct repository *r,
532 strvec_push(&child.args, "--quiet");
533 if (reflog)
534 strvec_push(&child.args, "--create-reflog");
532 - if (track == BRANCH_TRACK_ALWAYS || track == BRANCH_TRACK_EXPLICIT)
533 - strvec_push(&child.args, "--track");
535 +
536 + switch (track) {
537 + case BRANCH_TRACK_NEVER:
538 + strvec_push(&child.args, "--no-track");
539 + break;
540 + case BRANCH_TRACK_ALWAYS:
541 + case BRANCH_TRACK_EXPLICIT:
542 + strvec_push(&child.args, "--track=direct");
543 + break;
544 + case BRANCH_TRACK_OVERRIDE:
545 + BUG("BRANCH_TRACK_OVERRIDE cannot be used when creating a branch.");
546 + break;
547 + case BRANCH_TRACK_INHERIT:
548 + strvec_push(&child.args, "--track=inherit");
549 + break;
550 + case BRANCH_TRACK_UNSPECIFIED:
551 + /* Default for "git checkout". No need to pass --track. */
552 + case BRANCH_TRACK_REMOTE:
553 + /* Default for "git branch". No need to pass --track. */
554 + break;
555 + }
556
557 strvec_pushl(&child.args, name, start_oid, tracking_name, NULL);
558
@@ -609,7 +631,8 @@ void create_branches_recursively(struct repository *r, const char *name,
631 * tedious to determine whether or not tracking was set up in the
632 * superproject.
633 */
612 - setup_tracking(name, tracking_name, track, quiet);
634 + if (track)
635 + setup_tracking(name, tracking_name, track, quiet);
636
637 for (i = 0; i < submodule_entry_list.entry_nr; i++) {
638 if (submodule_create_branch(
builtin/submodule--helper.c
+4 -3
@@ -2994,9 +2994,10 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
2994 OPT__FORCE(&force, N_("force creation"), 0),
2995 OPT_BOOL(0, "create-reflog", &reflog,
2996 N_("create the branch's reflog")),
2997 - OPT_SET_INT('t', "track", &track,
2998 - N_("set up tracking mode (see git-pull(1))"),
2999 - BRANCH_TRACK_EXPLICIT),
2997 + OPT_CALLBACK_F('t', "track", &track, "(direct|inherit)",
2998 + N_("set branch tracking configuration"),
2999 + PARSE_OPT_OPTARG,
3000 + parse_opt_tracking_mode),
3001 OPT__DRY_RUN(&dry_run,
3002 N_("show whether the branch would be created")),
3003 OPT_END()
t/t3207-branch-submodule.sh
+37 -1
@@ -260,7 +260,7 @@ test_expect_success 'should get fatal error upon branch creation when submodule
260 )
261 '
262
263 -test_expect_success 'should set up tracking of remote-tracking branches' '
263 +test_expect_success 'should set up tracking of remote-tracking branches by default' '
264 test_when_finished "reset_remote_test" &&
265 (
266 cd super-clone &&
@@ -289,4 +289,40 @@ test_expect_success 'should not fail when unable to set up tracking in submodule
289 )
290 '
291
292 +test_expect_success '--track=inherit should set up tracking correctly' '
293 + test_when_finished "reset_remote_test" &&
294 + (
295 + cd super-clone &&
296 + git branch --recurse-submodules branch-a origin/branch-a &&
297 + # Set this manually instead of using branch --set-upstream-to
298 + # to circumvent the "nonexistent upstream" check.
299 + git -C sub config branch.branch-a.remote origin &&
300 + git -C sub config branch.branch-a.merge refs/heads/sub-branch-a &&
301 + git -C sub/sub-sub config branch.branch-a.remote other &&
302 + git -C sub/sub-sub config branch.branch-a.merge refs/heads/sub-sub-branch-a &&
303 +
304 + git branch --recurse-submodules --track=inherit branch-b branch-a &&
305 + test_cmp_config origin branch.branch-b.remote &&
306 + test_cmp_config refs/heads/branch-a branch.branch-b.merge &&
307 + test_cmp_config -C sub origin branch.branch-b.remote &&
308 + test_cmp_config -C sub refs/heads/sub-branch-a branch.branch-b.merge &&
309 + test_cmp_config -C sub/sub-sub other branch.branch-b.remote &&
310 + test_cmp_config -C sub/sub-sub refs/heads/sub-sub-branch-a branch.branch-b.merge
311 + )
312 +'
313 +
314 +test_expect_success '--no-track should not set up tracking' '
315 + test_when_finished "reset_remote_test" &&
316 + (
317 + cd super-clone &&
318 + git branch --recurse-submodules --no-track branch-a origin/branch-a &&
319 + test_cmp_config "" --default "" branch.branch-a.remote &&
320 + test_cmp_config "" --default "" branch.branch-a.merge &&
321 + test_cmp_config -C sub "" --default "" branch.branch-a.remote &&
322 + test_cmp_config -C sub "" --default "" branch.branch-a.merge &&
323 + test_cmp_config -C sub/sub-sub "" --default "" branch.branch-a.remote &&
324 + test_cmp_config -C sub/sub-sub "" --default "" branch.branch-a.merge
325 + )
326 +'
327 +
328 test_done