From d5d284df910b5f03681b480ae061bb1435b3b4b2 Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Mon, 24 Mar 2025 19:51:46 -0500 Subject: [PATCH 1/3] remote: allow `guess_remote_head()` to suppress advice The `repo_default_branch_name()` invoked through `guess_remote_head()` is configured to always display the default branch advice message. Adapt `guess_remote_head()` to accept flags and convert the `all` parameter to a flag. Add the `REMOTE_GUESS_HEAD_QUIET` flag to to enable suppression of advice messages. Call sites are updated accordingly. Signed-off-by: Justin Tobler Acked-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/fetch.c | 2 +- builtin/remote.c | 2 +- remote.c | 10 ++++++---- remote.h | 11 +++++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 95fd0018b9..763314bfcb 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1638,7 +1638,7 @@ static int set_head(const struct ref *remote_refs, struct remote *remote) get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), - fetch_map, 1); + fetch_map, REMOTE_GUESS_HEAD_ALL); for (ref = matches; ref; ref = ref->next) { string_list_append(&heads, strip_refshead(ref->name)); } diff --git a/builtin/remote.c b/builtin/remote.c index 1b7aad8838..d2aeb5ba1f 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -511,7 +511,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), - fetch_map, 1); + fetch_map, REMOTE_GUESS_HEAD_ALL); for (ref = matches; ref; ref = ref->next) string_list_append(&states->heads, abbrev_branch(ref->name)); diff --git a/remote.c b/remote.c index e609cf5c56..1db88beaf3 100644 --- a/remote.c +++ b/remote.c @@ -2297,7 +2297,7 @@ struct ref *get_local_heads(void) struct ref *guess_remote_head(const struct ref *head, const struct ref *refs, - int all) + unsigned flags) { const struct ref *r; struct ref *list = NULL; @@ -2315,8 +2315,10 @@ struct ref *guess_remote_head(const struct ref *head, return copy_ref(find_ref_by_name(refs, head->symref)); /* If a remote branch exists with the default branch name, let's use it. */ - if (!all) { - char *default_branch = repo_default_branch_name(the_repository, 0); + if (!(flags & REMOTE_GUESS_HEAD_ALL)) { + char *default_branch = + repo_default_branch_name(the_repository, + flags & REMOTE_GUESS_HEAD_QUIET); char *ref = xstrfmt("refs/heads/%s", default_branch); r = find_ref_by_name(refs, ref); @@ -2339,7 +2341,7 @@ struct ref *guess_remote_head(const struct ref *head, oideq(&r->old_oid, &head->old_oid)) { *tail = copy_ref(r); tail = &((*tail)->next); - if (!all) + if (!(flags & REMOTE_GUESS_HEAD_ALL)) break; } } diff --git a/remote.h b/remote.h index 6be5031f64..7e4943ae3a 100644 --- a/remote.h +++ b/remote.h @@ -387,15 +387,18 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb, int show_divergence_advice); struct ref *get_local_heads(void); + /* * Find refs from a list which are likely to be pointed to by the given HEAD - * ref. If 'all' is false, returns the most likely ref; otherwise, returns a - * list of all candidate refs. If no match is found (or 'head' is NULL), - * returns NULL. All returns are newly allocated and should be freed. + * ref. If REMOTE_GUESS_HEAD_ALL is set, return a list of all candidate refs; + * otherwise, return the most likely ref. If no match is found (or 'head' is + * NULL), returns NULL. All returns are newly allocated and should be freed. */ +#define REMOTE_GUESS_HEAD_ALL (1 << 0) +#define REMOTE_GUESS_HEAD_QUIET (1 << 1) struct ref *guess_remote_head(const struct ref *head, const struct ref *refs, - int all); + unsigned flags); /* Return refs which no longer exist on remote */ struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map); From c039a46e99541042554c52bdad2fb10ac5a1e97d Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Mon, 24 Mar 2025 19:51:47 -0500 Subject: [PATCH 2/3] builtin/clone: suppress unexpected default branch advice In 199f44cb2ead (builtin/clone: allow remote helpers to detect repo, 2024-02-27), clones started partially initializing the refdb before executing the remote helpers by creating a HEAD file and "refs/" directory. This has resulted in some scenarios where git-clone(1) now prints the default branch name advice message where it previously did not. A side-effect of the HEAD file already existing, is that computation of the default branch name is handled later in execution. This matters because prior to 97abaab5f6 (refs: drop `git_default_branch_name()`, 2024-05-17), the default branch value would be computed during its first execution and cached. Subsequent invocations would simply return the cached value. Since the next `git_default_branch_name()` call site, which is invoked through `guess_remote_head()`, is not configured to suppress the advice message, computing the default branch name results in the advice message being printed. Configure `guess_remote_head()` to suppress the advice message, restoring the previous behavior. Signed-off-by: Justin Tobler Acked-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/clone.c | 7 +++++-- t/t5607-clone-bundle.sh | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/builtin/clone.c b/builtin/clone.c index f14229abf4..baa76f88c3 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -450,7 +450,9 @@ static struct ref *wanted_peer_refs(struct clone_opts *opts, if (head) tail_link_ref(head, &tail); if (option_single_branch) - refs = to_free = guess_remote_head(head, refs, 0); + refs = to_free = + guess_remote_head(head, refs, + REMOTE_GUESS_HEAD_QUIET); } else if (option_single_branch) { local_refs = NULL; tail = &local_refs; @@ -1523,7 +1525,8 @@ int cmd_clone(int argc, } remote_head = find_ref_by_name(refs, "HEAD"); - remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0); + remote_head_points_at = guess_remote_head(remote_head, mapped_refs, + REMOTE_GUESS_HEAD_QUIET); if (option_branch) { our_head_points_at = find_remote_branch(mapped_refs, option_branch); diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh index 82e3621ec5..d709bea753 100755 --- a/t/t5607-clone-bundle.sh +++ b/t/t5607-clone-bundle.sh @@ -211,4 +211,16 @@ test_expect_success 'git bundle v3 rejects unknown capabilities' ' test_grep "unknown capability .unknown=silly." output ' +test_expect_success 'cloning bundle suppresses default branch name advice' ' + test_when_finished "rm -rf bundle-repo clone-repo" && + + git init bundle-repo && + git -C bundle-repo commit --allow-empty -m init && + git -C bundle-repo bundle create repo.bundle --all && + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \ + git clone --single-branch bundle-repo/repo.bundle clone-repo 2>err && + + test_grep ! "hint: " err +' + test_done From ec0f362e869fc74c3c9f011ae2097daa1c938833 Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Mon, 24 Mar 2025 19:51:48 -0500 Subject: [PATCH 3/3] advice: allow disabling default branch name advice The default branch name advice message is displayed when `repo_default_branch_name()` is invoked and the `init.defaultBranch` config is not set. In this scenario, the advice message is always shown even if the `--no-advice` option is used. Adapt `repo_default_branch_name()` to allow the default branch name advice message to be disabled with the `--no-advice` option and corresponding configuration. Signed-off-by: Justin Tobler Acked-by: Phillip Wood Signed-off-by: Junio C Hamano --- advice.c | 1 + advice.h | 1 + refs.c | 3 ++- t/t0001-init.sh | 8 ++++++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/advice.c b/advice.c index 1df43b7536..e5f0ff8449 100644 --- a/advice.c +++ b/advice.c @@ -51,6 +51,7 @@ static struct { [ADVICE_AM_WORK_DIR] = { "amWorkDir" }, [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName" }, [ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge" }, + [ADVICE_DEFAULT_BRANCH_NAME] = { "defaultBranchName" }, [ADVICE_DETACHED_HEAD] = { "detachedHead" }, [ADVICE_DIVERGING] = { "diverging" }, [ADVICE_FETCH_SET_HEAD_WARN] = { "fetchRemoteHEADWarn" }, diff --git a/advice.h b/advice.h index d233cfc693..727dcecf4a 100644 --- a/advice.h +++ b/advice.h @@ -18,6 +18,7 @@ enum advice_type { ADVICE_AM_WORK_DIR, ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME, ADVICE_COMMIT_BEFORE_MERGE, + ADVICE_DEFAULT_BRANCH_NAME, ADVICE_DETACHED_HEAD, ADVICE_DIVERGING, ADVICE_FETCH_SET_HEAD_WARN, diff --git a/refs.c b/refs.c index 118465271d..bf9a40d6af 100644 --- a/refs.c +++ b/refs.c @@ -664,7 +664,8 @@ char *repo_default_branch_name(struct repository *r, int quiet) if (!ret) { ret = xstrdup("master"); if (!quiet) - advise(_(default_branch_name_advice), ret); + advise_if_enabled(ADVICE_DEFAULT_BRANCH_NAME, + _(default_branch_name_advice), ret); } full_ref = xstrfmt("refs/heads/%s", ret); diff --git a/t/t0001-init.sh b/t/t0001-init.sh index c49d9e0d38..f11a40811f 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -830,6 +830,14 @@ test_expect_success 'advice on unconfigured init.defaultBranch' ' test_grep "hint: " decoded ' +test_expect_success 'advice on unconfigured init.defaultBranch disabled' ' + test_when_finished "rm -rf no-advice" && + + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \ + git -c advice.defaultBranchName=false init no-advice 2>err && + test_grep ! "hint: " err +' + test_expect_success 'overridden default main branch name (env)' ' test_config_global init.defaultBranch nmb && GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&