threads / bug / 63163

bug: git shows hints that should be suppressed

Subject: bug: git shows hints that should be suppressed

## tl;dr

32 messages between Mar 19, 2025 and Mar 25, 2025.

replies: 31people: 6as markdown or json

alan@norbauer.com· Mar 19, 2025, 09:53 UTC · lore

Thank you for filling out a Git bug report! Please answer the following questions to help us understand your issue.

What did you do before the bug happened? (Steps to reproduce your issue) `GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=0 GIT_ADVICE=0 git clone --quiet /Volumes/sourcecode/npm-packages/packages/repository-tools/node_modules/.cache/@altano/repository-tools/2078b9db1d71a4f4a5422e25a7016c75/git.bundle .`

What did you expect to happen? (Expected behavior) I would expect the clone to happen without any hints because I provided both `GIT_ADVICE=0` _and_ `--quiet` to the command. Both should suppress the hint.

What happened instead? (Actual behavior) I received the "hint: Using 'master' as the name for the initial branch. This default branch name" on stderr, which caused my tests to fail (I am using git programmatically in a test).

What's different between what you expected and what actually happened? The hint on stderr was displayed.

Anything else you want to add: This behavior is NOT observed on git v2.44.0 and is observed on git v2.48.1. So the bug started occurring somewhere in between those versions. I can find the exact version the bug was introduced manually with some effort if that would be helpful.

Please review the rest of the bug report below. You can delete any lines you don't wish to share.

[System Info]
git version:
git version 2.48.1
cpu: aarch64
no commit associated with this build
sizeof-long: 8
sizeof-size_t: 8
shell-path: /nix/store/hmffg6n6ylbl4c30pqc9i71mwqzrd0iv-bash-5.2p37/bin/bash
feature: fsmonitor--daemon
libcurl: 8.12.1
OpenSSL: OpenSSL 3.4.1 11 Feb 2025
zlib: 1.3.1
uname: Darwin 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan  2 20:24:23 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6020 arm64
compiler info: clang: 19.1.7 
libc info: no libc information available
$SHELL (typically, interactive shell): /bin/zsh
[Enabled Hooks]
alan@norbauer.com· Mar 19, 2025, 09:58 UTC · re: alan@norbauer.com · lore

Re: bug: git shows hints that should be suppressed

I went ahead and narrowed the range a bit:

✅ 2.44.1 = NO bug ❌ 2.45.1 = bug reproduces

Thanks, alan

Show 43 quoted lines
> On Mar 19, 2025, at 2:53 AM, alan@norbauer.com wrote:
> 
> Thank you for filling out a Git bug report!
> Please answer the following questions to help us understand your issue.
> 
> What did you do before the bug happened? (Steps to reproduce your issue)
> `GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=0 GIT_ADVICE=0 git clone --quiet /Volumes/sourcecode/npm-packages/packages/repository-tools/node_modules/.cache/@altano/repository-tools/2078b9db1d71a4f4a5422e25a7016c75/git.bundle .`
> 
> What did you expect to happen? (Expected behavior)
> I would expect the clone to happen without any hints because I provided both `GIT_ADVICE=0` _and_ `--quiet` to the command. Both should suppress the hint.
> 
> What happened instead? (Actual behavior)
> I received the "hint: Using 'master' as the name for the initial branch. This default branch name" on stderr, which caused my tests to fail (I am using git programmatically in a test).
> 
> What's different between what you expected and what actually happened?
> The hint on stderr was displayed.
> 
> Anything else you want to add:
> This behavior is NOT observed on git v2.44.0 and is observed on git v2.48.1. So the bug started occurring somewhere in between those versions. I can find the exact version the bug was introduced manually with some effort if that would be helpful.
> 
> Please review the rest of the bug report below.
> You can delete any lines you don't wish to share.
> 
> 
> [System Info]
> git version:
> git version 2.48.1
> cpu: aarch64
> no commit associated with this build
> sizeof-long: 8
> sizeof-size_t: 8
> shell-path: /nix/store/hmffg6n6ylbl4c30pqc9i71mwqzrd0iv-bash-5.2p37/bin/bash
> feature: fsmonitor--daemon
> libcurl: 8.12.1
> OpenSSL: OpenSSL 3.4.1 11 Feb 2025
> zlib: 1.3.1
> uname: Darwin 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan  2 20:24:23 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6020 arm64
> compiler info: clang: 19.1.7 
> libc info: no libc information available
> $SHELL (typically, interactive shell): /bin/zsh
> 
> 
> [Enabled Hooks]
Elijah Newren· Mar 19, 2025, 14:45 UTC · re: alan@norbauer.com · lore

Re: bug: git shows hints that should be suppressed

On Wed, Mar 19, 2025 at 2:59 AM <alan@norbauer.com> wrote:
Show 18 quoted lines
>
> Thank you for filling out a Git bug report!
> Please answer the following questions to help us understand your issue.
>
> What did you do before the bug happened? (Steps to reproduce your issue)
> `GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=0 GIT_ADVICE=0 git clone --quiet /Volumes/sourcecode/npm-packages/packages/repository-tools/node_modules/.cache/@altano/repository-tools/2078b9db1d71a4f4a5422e25a7016c75/git.bundle .`
>
> What did you expect to happen? (Expected behavior)
> I would expect the clone to happen without any hints because I provided both `GIT_ADVICE=0` _and_ `--quiet` to the command. Both should suppress the hint.
>
> What happened instead? (Actual behavior)
> I received the "hint: Using 'master' as the name for the initial branch. This default branch name" on stderr, which caused my tests to fail (I am using git programmatically in a test).
>
> What's different between what you expected and what actually happened?
> The hint on stderr was displayed.
>
> Anything else you want to add:
> This behavior is NOT observed on git v2.44.0 and is observed on git v2.48.1. So the bug started occurring somewhere in between those versions. I can find the exact version the bug was introduced manually with some effort if that would be helpful.

Bisects to 199f44cb2ead (builtin/clone: allow remote helpers to detect repo, 2024-02-27); cc'ing its author.

Justin Tobler· Mar 20, 2025, 01:36 UTC · re: Elijah Newren · lore

Re: bug: git shows hints that should be suppressed

On 25/03/19 07:45AM, Elijah Newren wrote:
Show 22 quoted lines
> On Wed, Mar 19, 2025 at 2:59 AM <alan@norbauer.com> wrote:
> >
> > Thank you for filling out a Git bug report!
> > Please answer the following questions to help us understand your issue.
> >
> > What did you do before the bug happened? (Steps to reproduce your issue)
> > `GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=0 GIT_ADVICE=0 git clone --quiet /Volumes/sourcecode/npm-packages/packages/repository-tools/node_modules/.cache/@altano/repository-tools/2078b9db1d71a4f4a5422e25a7016c75/git.bundle .`
> >
> > What did you expect to happen? (Expected behavior)
> > I would expect the clone to happen without any hints because I provided both `GIT_ADVICE=0` _and_ `--quiet` to the command. Both should suppress the hint.
> >
> > What happened instead? (Actual behavior)
> > I received the "hint: Using 'master' as the name for the initial branch. This default branch name" on stderr, which caused my tests to fail (I am using git programmatically in a test).
> >
> > What's different between what you expected and what actually happened?
> > The hint on stderr was displayed.
> >
> > Anything else you want to add:
> > This behavior is NOT observed on git v2.44.0 and is observed on git v2.48.1. So the bug started occurring somewhere in between those versions. I can find the exact version the bug was introduced manually with some effort if that would be helpful.
> 
> Bisects to 199f44cb2ead (builtin/clone: allow remote helpers to detect
> repo, 2024-02-27); cc'ing its author.

It looks like prior to 199f44cb2ead (builtin/clone: allow remote helpers to detect repo, 2024-02-27), the default branch name advice message would never be printed when cloning from a bundle regardless of whether `--quiet` option was set. This particual advice message also doesn't respect `GIT_ADVICE` either. So something about the change has made the message start printing when it previously did not.

Digging a bit further, this change started partially initializing the refdb with a HEAD file which had a side-effect of changing the location where the first `git_default_branch_name()` was invoked. This matters because `git_default_branch_name()` only computes the default branch name once and uses a cached value for subsequent invocations.

Previously, `create_reference_database()` was the first `git_default_branch_name()` call site and was configured to always suppress the advice message. Due to the refdb being partially initialized with a HEAD file, `create_reference_database()` stopped invoking `git_default_branch_name()` altogether and the default branch name computation was defferred to a subsequent potential call site `guess_remote_head()`. At this location, `git_default_branch_name()` is configured to not suppress advice messages.

Also, `guess_remote_head()` only invokes `git_default_branch_name()` in cases where the transport is unable to figure out the remote HEAD and must guess. This explains why the advice message gets printed for bundle clones, but not all clones.

One option to fix this would be to adapt `guess_remote_head()` to support configuring the underlying `git_default_branch_name()`, which has since been renamed to `repo_default_branch_name()`, to be quiet and suppress the advice message. The call site in clone could then be updated accordingly.

I'll submit a patch that does this.
-Justin
Justin Tobler· Mar 20, 2025, 01:46 UTC · re: Justin Tobler · lore

[PATCH 0/2] clone: suppress unexpected advice message during clone

It has been reported[1] that starting in Git v2.45.0, cloning from a bundle results in the default branch name advice message always being displayed when it was previously not. It can be reproduced by the following:

        git init bundle-repo &&
        git -C bundle-repo --allow-empty -m init &&
        git -C bundle-repo bundle create ../repo.bundle --all &&
        git clone bundle.repo bundle-clone

This issue bisects to 199f44cb2ead (builtin/clone: allow remote helpers to detect repo, 2024-02-27) where the refdb is partially initialized during clones before remote helpers are executed. This partial initilization creates the HEAD file and "refs/" directory.

A side-effect of this change is that the location of the first `git_default_branch_name()` gets deferred to a later point of execution. This matters because `git_default_branch_name()` only computes the default branch name once and returns a cached value for subsequent invocations. After this change, the `git_default_branch_name()` call site that actually computes the value becomes `guess_remote_head()` and is configured to always show the advice message.

Also, `guess_remote_head()` only invokes `git_default_branch_name()` in cases where the transport is unable to figure out the remote HEAD and must guess. This explains why the advice message gets printed for bundle clones, but not all clones.

This series addresses the issue by adapting `guess_remote_head()` to support configuring the underlying `git_default_branch_name()`, which has since been renamed to `repo_default_branch_name()`, to be quiet and suppress the advice message.

Thanks, -Justin

[1]: <7EC98E2F-144D-4974-94F6-FC24B443651D@norbauer.com>
Justin Tobler (2):
  remote: allow `guess_remote_head()` to suppress advice
  clone: suppress unexpected default branch advice
 builtin/clone.c  | 4 ++--
 builtin/fetch.c  | 2 +-
 builtin/remote.c | 2 +-
 remote.c         | 4 ++--
 remote.h         | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
-- 
2.49.0
Justin Tobler· Mar 20, 2025, 01:46 UTC · re: Justin Tobler · lore

[PATCH 1/2] 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.

Add an additional parameter to the `guess_remote_head()` function signature to enable suppression of advice messages and update call sites accordingly.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
---
 builtin/clone.c  | 4 ++--
 builtin/fetch.c  | 2 +-
 builtin/remote.c | 2 +-
 remote.c         | 4 ++--
 remote.h         | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index f14229abf4..9eb66234bc 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -450,7 +450,7 @@ 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, 0, 0);
 	} else if (option_single_branch) {
 		local_refs = NULL;
 		tail = &local_refs;
@@ -1523,7 +1523,7 @@ 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, 0, 0);
 
 	if (option_branch) {
 		our_head_points_at = find_remote_branch(mapped_refs, option_branch);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 95fd0018b9..a4f5b3e683 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, 1, 0);
 	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..ebd1a796d2 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, 1, 0);
 	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..e9e55ecdbf 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)
+			      int all, int quiet)
 {
 	const struct ref *r;
 	struct ref *list = NULL;
@@ -2316,7 +2316,7 @@ struct ref *guess_remote_head(const struct ref *head,
 
 	/* 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);
+		char *default_branch = repo_default_branch_name(the_repository, quiet);
 		char *ref = xstrfmt("refs/heads/%s", default_branch);
 
 		r = find_ref_by_name(refs, ref);
diff --git a/remote.h b/remote.h
index 6be5031f64..49c7b644bb 100644
--- a/remote.h
+++ b/remote.h
@@ -395,7 +395,7 @@ struct ref *get_local_heads(void);
  */
 struct ref *guess_remote_head(const struct ref *head,
 			      const struct ref *refs,
-			      int all);
+			      int all, int quiet);
 
 /* Return refs which no longer exist on remote */
 struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map);
-- 
2.49.0
Patrick Steinhardt· Mar 20, 2025, 05:13 UTC · re: Justin Tobler · lore

Re: [PATCH 1/2] remote: allow `guess_remote_head()` to suppress advice

On Wed, Mar 19, 2025 at 08:46:45PM -0500, Justin Tobler wrote:
Show 10 quoted lines
> diff --git a/remote.h b/remote.h
> index 6be5031f64..49c7b644bb 100644
> --- a/remote.h
> +++ b/remote.h
> @@ -395,7 +395,7 @@ struct ref *get_local_heads(void);
>   */
>  struct ref *guess_remote_head(const struct ref *head,
>  			      const struct ref *refs,
> -			      int all);
> +			      int all, int quiet);

I think instead of introducing another boolean parameter it would be preferable to have a preparatory commit that turns `all` into `flags`.

Patrick
Justin Tobler· Mar 20, 2025, 23:30 UTC · re: Patrick Steinhardt · lore

Re: [PATCH 1/2] remote: allow `guess_remote_head()` to suppress advice

On 25/03/20 06:13AM, Patrick Steinhardt wrote:
Show 14 quoted lines
> On Wed, Mar 19, 2025 at 08:46:45PM -0500, Justin Tobler wrote:
> > diff --git a/remote.h b/remote.h
> > index 6be5031f64..49c7b644bb 100644
> > --- a/remote.h
> > +++ b/remote.h
> > @@ -395,7 +395,7 @@ struct ref *get_local_heads(void);
> >   */
> >  struct ref *guess_remote_head(const struct ref *head,
> >  			      const struct ref *refs,
> > -			      int all);
> > +			      int all, int quiet);
> 
> I think instead of introducing another boolean parameter it would be
> preferable to have a preparatory commit that turns `all` into `flags`.
That makes sense. I'll adapt the next version accordingly.

Thanks, -Justin

Junio C Hamano· Mar 21, 2025, 08:52 UTC · re: Patrick Steinhardt · lore

Re: [PATCH 1/2] remote: allow `guess_remote_head()` to suppress advice

Patrick Steinhardt <ps@pks.im> writes:
Show 14 quoted lines
> On Wed, Mar 19, 2025 at 08:46:45PM -0500, Justin Tobler wrote:
>> diff --git a/remote.h b/remote.h
>> index 6be5031f64..49c7b644bb 100644
>> --- a/remote.h
>> +++ b/remote.h
>> @@ -395,7 +395,7 @@ struct ref *get_local_heads(void);
>>   */
>>  struct ref *guess_remote_head(const struct ref *head,
>>  			      const struct ref *refs,
>> -			      int all);
>> +			      int all, int quiet);
>
> I think instead of introducing another boolean parameter it would be
> preferable to have a preparatory commit that turns `all` into `flags`.

Good. And when we turn that into a set of bits "flags", make sure we make it unsigned, not signed int.

Thanks.
Justin Tobler· Mar 20, 2025, 01:46 UTC · re: Justin Tobler · lore

[PATCH 2/2] 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 <jltobler@gmail.com>
---
 builtin/clone.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index 9eb66234bc..3b166b05e3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1523,7 +1523,7 @@ 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, 0);
+	remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0, 1);
 
 	if (option_branch) {
 		our_head_points_at = find_remote_branch(mapped_refs, option_branch);
-- 
2.49.0
Patrick Steinhardt· Mar 20, 2025, 05:13 UTC · re: Justin Tobler · lore

Re: [PATCH 2/2] clone: suppress unexpected default branch advice

On Wed, Mar 19, 2025 at 08:46:46PM -0500, Justin Tobler wrote:
Show 13 quoted lines
> diff --git a/builtin/clone.c b/builtin/clone.c
> index 9eb66234bc..3b166b05e3 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -1523,7 +1523,7 @@ 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, 0);
> +	remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0, 1);
>  
>  	if (option_branch) {
>  		our_head_points_at = find_remote_branch(mapped_refs, option_branch);

Makes sense. You don't have control over the branch name anyway when cloning, so it's nonsensical to print that advise. Another subsequent step could be to turn the `advise()` into `advise_if_enabled()`, but that change isn't really needed for git-clone(1) because there wouldn't ever be a reason to print it.

Do we want to add a test somewhere that demonstrates that we don't print the advise anymore?

Thanks for fixing this!
Patrick
Justin Tobler· Mar 20, 2025, 23:36 UTC · re: Patrick Steinhardt · lore

Re: [PATCH 2/2] clone: suppress unexpected default branch advice

On 25/03/20 06:13AM, Patrick Steinhardt wrote:
Show 20 quoted lines
> On Wed, Mar 19, 2025 at 08:46:46PM -0500, Justin Tobler wrote:
> > diff --git a/builtin/clone.c b/builtin/clone.c
> > index 9eb66234bc..3b166b05e3 100644
> > --- a/builtin/clone.c
> > +++ b/builtin/clone.c
> > @@ -1523,7 +1523,7 @@ 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, 0);
> > +	remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0, 1);
> >  
> >  	if (option_branch) {
> >  		our_head_points_at = find_remote_branch(mapped_refs, option_branch);
> 
> Makes sense. You don't have control over the branch name anyway when
> cloning, so it's nonsensical to print that advise. Another subsequent
> step could be to turn the `advise()` into `advise_if_enabled()`, but
> that change isn't really needed for git-clone(1) because there wouldn't
> ever be a reason to print it.

As you mentioned, in this specific situation printing the advice doesn't make much sense. It would probably be a good idea to allow this message to be suppressed from other call sites if requested to do so though. I'll add another patch that turns it into `advise_if_enabled()` to support this.

> Do we want to add a test somewhere that demonstrates that we don't print
> the advise anymore?
Ya, I'll go ahead and include this in my next version.

Thanks, -Justin

Phillip Wood· Mar 20, 2025, 11:10 UTC · re: Justin Tobler · lore

Re: [PATCH 0/2] clone: suppress unexpected advice message during clone

Hi Justin
On 20/03/2025 01:46, Justin Tobler wrote:
Show 8 quoted lines
> 
> A side-effect of this change is that the location of the first
> `git_default_branch_name()` gets deferred to a later point of execution.
> This matters because `git_default_branch_name()` only computes the
> default branch name once and returns a cached value for subsequent
> invocations. After this change, the `git_default_branch_name()` call
> site that actually computes the value becomes `guess_remote_head()` and
> is configured to always show the advice message.

Isn't the fundamental cause of this bug that advise() ignores GIT_ADVICE? I'm not really clear why "git --no-advice" only applies to advice that is guarded by advice_enabled() when it is documented as disabling all advice hints.

Best Wishes
Phillip
Justin Tobler· Mar 20, 2025, 23:48 UTC · re: Phillip Wood · lore

Re: [PATCH 0/2] clone: suppress unexpected advice message during clone

On 25/03/20 11:10AM, Phillip Wood wrote:
Show 16 quoted lines
> Hi Justin
> 
> On 20/03/2025 01:46, Justin Tobler wrote:
> > 
> > A side-effect of this change is that the location of the first
> > `git_default_branch_name()` gets deferred to a later point of execution.
> > This matters because `git_default_branch_name()` only computes the
> > default branch name once and returns a cached value for subsequent
> > invocations. After this change, the `git_default_branch_name()` call
> > site that actually computes the value becomes `guess_remote_head()` and
> > is configured to always show the advice message.
> 
> Isn't the fundamental cause of this bug that advise() ignores GIT_ADVICE?
> I'm not really clear why "git --no-advice" only applies to advice that is
> guarded by advice_enabled() when it is documented as disabling all advice
> hints.

From my point of view, this advice message should never be presented in this particular scenario regardless of the configuration as it doesn't make much sense here. This also happens to be the original behavior so I think we should probably return to that state.

I was also a bit suprised to see that not all advice messages respect the `--no-advice` option. I'm not sure if there is a reason for this, or if `advise_if_enabled()` just came later and not everything was converted.

In general though, other users of the default branch name advice message should probably follow the `--no-advice` option. I'll add another patch that does this in the next version.

Thanks, -Justin

Phillip Wood· Mar 21, 2025, 16:42 UTC · re: Justin Tobler · lore

Re: [PATCH 0/2] clone: suppress unexpected advice message during clone

On 20/03/2025 23:48, Justin Tobler wrote:
Show 22 quoted lines
> On 25/03/20 11:10AM, Phillip Wood wrote:
>> Hi Justin
>>
>> On 20/03/2025 01:46, Justin Tobler wrote:
>>>
>>> A side-effect of this change is that the location of the first
>>> `git_default_branch_name()` gets deferred to a later point of execution.
>>> This matters because `git_default_branch_name()` only computes the
>>> default branch name once and returns a cached value for subsequent
>>> invocations. After this change, the `git_default_branch_name()` call
>>> site that actually computes the value becomes `guess_remote_head()` and
>>> is configured to always show the advice message.
>>
>> Isn't the fundamental cause of this bug that advise() ignores GIT_ADVICE?
>> I'm not really clear why "git --no-advice" only applies to advice that is
>> guarded by advice_enabled() when it is documented as disabling all advice
>> hints.
> 
>  From my point of view, this advice message should never be presented in
> this particular scenario regardless of the configuration as it doesn't
> make much sense here. This also happens to be the original behavior so I
> think we should probably return to that state.

Oh, good point. So the original report actually highlights two bugs - the regression you're fixing here and the fact that "--no-advice" does not suppress the advice.

Show 7 quoted lines
> I was also a bit suprised to see that not all advice messages respect
> the `--no-advice` option. I'm not sure if there is a reason for this, or if
> `advise_if_enabled()` just came later and not everything was converted.
> 
> In general though, other users of the default branch name advice message
> should probably follow the `--no-advice` option. I'll add another patch
> that does this in the next version.
That would be great,
Thanks
Phillip
> Thanks,
> -Justin
> 
Justin Tobler· Mar 21, 2025, 23:16 UTC · re: Justin Tobler · lore

[PATCH v2 0/3] clone: suppress unexpected advice message during clone

It has been reported[1] that starting in Git v2.45.0, cloning from a bundle results in the default branch name advice message always being displayed when it was previously not. It can be reproduced by the following:

        git init bundle-repo &&
        git -C bundle-repo --allow-empty -m init &&
        git -C bundle-repo bundle create ../repo.bundle --all &&
        git clone repo.bundle bundle-clone

This issue bisects to 199f44cb2ead (builtin/clone: allow remote helpers to detect repo, 2024-02-27) where the refdb is partially initialized during clones before remote helpers are executed. This partial initilization creates the HEAD file and "refs/" directory.

A side-effect of this change is that the location of the first `git_default_branch_name()` gets deferred to a later point of execution. This matters because `git_default_branch_name()` only computes the default branch name once and returns a cached value for subsequent invocations. After this change, the `git_default_branch_name()` call site that actually computes the value becomes `guess_remote_head()` and is configured to always show the advice message.

Also, `guess_remote_head()` only invokes `git_default_branch_name()` in cases where the transport is unable to figure out the remote HEAD and must guess. This explains why the advice message gets printed for bundle clones, but not all clones.

This series addresses the issue by adapting `guess_remote_head()` to support configuring the underlying `git_default_branch_name()`, which has since been renamed to `repo_default_branch_name()`, to be quiet and suppress the advice message.

Changes since V1:
        - Instead of adding an additional boolean to
          `guess_remote_head()` to suppress the advice message, the
          function is adapted to accepts flags that accoplish the same
          thing.
        - Added a test to validate that the advice message is not being
          printed.
        - While we are here, added another patch to allow the default
          branch name advice message to be suppressrd by the
          `--no-advice` option.

Thanks, -Justin

[1]: <7EC98E2F-144D-4974-94F6-FC24B443651D@norbauer.com>
Justin Tobler (3):
  remote: allow `guess_remote_head()` to suppress advice
  builtin/clone: suppress unexpected default branch advice
  advice: allow disabling default branch name advice
 advice.c                |  1 +
 advice.h                |  1 +
 builtin/clone.c         |  3 ++-
 builtin/fetch.c         |  2 +-
 builtin/remote.c        |  2 +-
 refs.c                  |  3 ++-
 remote.c                | 10 ++++++----
 remote.h                | 11 +++++++----
 t/t0001-init.sh         |  8 ++++++++
 t/t5607-clone-bundle.sh | 12 ++++++++++++
 10 files changed, 41 insertions(+), 12 deletions(-)
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
-- 
2.49.0
Justin Tobler· Mar 21, 2025, 23:16 UTC · re: Justin Tobler · lore

[PATCH v2 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 <jltobler@gmail.com>
---
 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);
-- 
2.49.0
Phillip Wood· Mar 24, 2025, 09:31 UTC · re: Justin Tobler · lore

Re: [PATCH v2 1/3] remote: allow `guess_remote_head()` to suppress advice

Hi Justin
On 21/03/2025 23:16, Justin Tobler wrote:
Show 5 quoted lines
> 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. 

This makes sense if we want to convert the boolean argument to a flags argument. However the only callers that do not set `all` when calling this function are in git clone where we don't want to emit the warning. It is probably not worth a re-roll but I wonder if we really need to do this conversion or if we should just hard code guess_remote_head() to be quiet when it calls repo_default_branch_name()

Best Wishes
Phillip
Show 98 quoted lines
> Add the `REMOTE_GUESS_HEAD_QUIET` flag to to enable
> suppression of advice messages. Call sites are updated accordingly.
> > Signed-off-by: Justin Tobler <jltobler@gmail.com>
> ---
>   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);
Justin Tobler· Mar 24, 2025, 15:21 UTC · re: Phillip Wood · lore

Re: [PATCH v2 1/3] remote: allow `guess_remote_head()` to suppress advice

On 25/03/24 09:31AM, Phillip Wood wrote:
Show 15 quoted lines
> Hi Justin
> 
> On 21/03/2025 23:16, Justin Tobler wrote:
> > 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.
> 
> This makes sense if we want to convert the boolean argument to a flags
> argument. However the only callers that do not set `all` when calling this
> function are in git clone where we don't want to emit the warning. It is
> probably not worth a re-roll but I wonder if we really need to do this
> conversion or if we should just hard code guess_remote_head() to be quiet
> when it calls repo_default_branch_name()

Good point. We could just rely on the fact that all current `guess_remote_head()` callers that do not set `all` also do not want the advice to be printed.

I have a slight preference to keep this as-is and favor the explicit configuration, but ultimately I don't feel strongly either way. I am open to change in a followup version though. :)

Thanks, -Justin

phillip.wood123@gmail.com· Mar 24, 2025, 19:29 UTC · re: Justin Tobler · lore

Re: [PATCH v2 1/3] remote: allow `guess_remote_head()` to suppress advice

Hi Justin
On 24/03/2025 15:21, Justin Tobler wrote:
Show 22 quoted lines
> On 25/03/24 09:31AM, Phillip Wood wrote:
>> On 21/03/2025 23:16, Justin Tobler wrote:
>>> 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.
>>
>> This makes sense if we want to convert the boolean argument to a flags
>> argument. However the only callers that do not set `all` when calling this
>> function are in git clone where we don't want to emit the warning. It is
>> probably not worth a re-roll but I wonder if we really need to do this
>> conversion or if we should just hard code guess_remote_head() to be quiet
>> when it calls repo_default_branch_name()
> 
> Good point. We could just rely on the fact that all current
> `guess_remote_head()` callers that do not set `all` also do not want the
> advice to be printed.
> 
> I have a slight preference to keep this as-is and favor the explicit
> configuration, but ultimately I don't feel strongly either way. I am
> open to change in a followup version though. :)
I'm fine either way so lets keep it as-is if you want
Thanks
Phillip
Justin Tobler· Mar 21, 2025, 23:16 UTC · re: Justin Tobler · lore

[PATCH v2 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 <jltobler@gmail.com>
---
 builtin/clone.c         |  3 ++-
 t/t5607-clone-bundle.sh | 12 ++++++++++++
 2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index f14229abf4..a4008715ec 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1523,7 +1523,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..f526bb1c69 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 bundle-repo/repo.bundle clone-repo 2>err &&
+
+	test_grep ! "hint: " err
+'
+
 test_done
-- 
2.49.0
Phillip Wood· Mar 24, 2025, 09:32 UTC · re: Justin Tobler · lore

Re: [PATCH v2 2/3] builtin/clone: suppress unexpected default branch advice

Hi Justin
On 21/03/2025 23:16, Justin Tobler wrote:
Show 37 quoted lines
> 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 <jltobler@gmail.com>
> ---
>   builtin/clone.c         |  3 ++-
>   t/t5607-clone-bundle.sh | 12 ++++++++++++
>   2 files changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/builtin/clone.c b/builtin/clone.c
> index f14229abf4..a4008715ec 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -1523,7 +1523,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);

There is another caller of guess_remote_head() in wanted_peer_refs() which I think we probably want to be quiet as well. I don't see how it is helpful to the user to prompt them about setting the default branch name used when creating local repositories during a clone of a remote repository.

Best Wishes
Phillip
Show 24 quoted lines
>   
>   	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..f526bb1c69 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 bundle-repo/repo.bundle clone-repo 2>err &&
> +
> +	test_grep ! "hint: " err
> +'
> +
>   test_done
Justin Tobler· Mar 24, 2025, 15:35 UTC · re: Phillip Wood · lore

Re: [PATCH v2 2/3] builtin/clone: suppress unexpected default branch advice

On 25/03/24 09:32AM, Phillip Wood wrote:
Show 44 quoted lines
> Hi Justin
> 
> On 21/03/2025 23:16, Justin Tobler wrote:
> > 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 <jltobler@gmail.com>
> > ---
> >   builtin/clone.c         |  3 ++-
> >   t/t5607-clone-bundle.sh | 12 ++++++++++++
> >   2 files changed, 14 insertions(+), 1 deletion(-)
> > 
> > diff --git a/builtin/clone.c b/builtin/clone.c
> > index f14229abf4..a4008715ec 100644
> > --- a/builtin/clone.c
> > +++ b/builtin/clone.c
> > @@ -1523,7 +1523,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);
> 
> There is another caller of guess_remote_head() in wanted_peer_refs() which I
> think we probably want to be quiet as well. I don't see how it is helpful to
> the user to prompt them about setting the default branch name used when
> creating local repositories during a clone of a remote repository.

For `wanted_peer_refs()` to invoke `guess_remote_head()`, the `--single-branch` option must be set. This means, outside of the bundle clone example, there is another way to get unexpected advice message to print. Interestingly, if you perform a bundle clone with the `--single-branch` option, the same advice message prints twice.

I'll send a followup version that also suppresses the unwanted advice message from `wanted_peer_refs()`.

Thanks, -Justin

Justin Tobler· Mar 21, 2025, 23:16 UTC · re: Justin Tobler · lore

[PATCH v2 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 <jltobler@gmail.com>
---
 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 "<YELLOW>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 &&
-- 
2.49.0
Phillip Wood· Mar 24, 2025, 09:32 UTC · re: Justin Tobler · lore

Re: [PATCH v2 3/3] advice: allow disabling default branch name advice

Hi Justin
On 21/03/2025 23:16, Justin Tobler wrote:
Show 8 quoted lines
> 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.

Thanks for adding this, it has always bothered me that the only way to silence this hint was by setting a default branch name, rather than being able to just accept git's default by setting the appropiate advice variable. The patch looks good to me

Best Wishes
Phillip
Show 65 quoted lines
> Signed-off-by: Justin Tobler <jltobler@gmail.com>
> ---
>   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 "<YELLOW>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 &&
Junio C Hamano· Mar 23, 2025, 19:38 UTC · re: Justin Tobler · lore

Re: [PATCH v2 0/3] clone: suppress unexpected advice message during clone

Justin Tobler <jltobler@gmail.com> writes:
Show 6 quoted lines
> It has been reported[1] that starting in Git v2.45.0, cloning from a bundle
> results in the default branch name advice message always being displayed
> when it was previously not. It can be reproduced by the following:
>
>         git init bundle-repo &&
>         git -C bundle-repo --allow-empty -m init &&

Presumably this is "commit --allow-empty -m init" in the bundle-repo repository?

Show 9 quoted lines
>         git -C bundle-repo bundle create ../repo.bundle --all &&
>         git clone repo.bundle bundle-clone
>
> This issue bisects to 199f44cb2ead (builtin/clone: allow remote helpers
> ...
> This series addresses the issue by adapting `guess_remote_head()` to
> support configuring the underlying `git_default_branch_name()`, which
> has since been renamed to `repo_default_branch_name()`, to be quiet and
> suppress the advice message.
Nicely analyzed and described.
Show 16 quoted lines
> Changes since V1:
>
>         - Instead of adding an additional boolean to
>           `guess_remote_head()` to suppress the advice message, the
>           function is adapted to accepts flags that accoplish the same
>           thing.
>
>         - Added a test to validate that the advice message is not being
>           printed.
>
>         - While we are here, added another patch to allow the default
>           branch name advice message to be suppressrd by the
>           `--no-advice` option.
>
> Thanks,
> -Justin
Show 22 quoted lines
>
> [1]: <7EC98E2F-144D-4974-94F6-FC24B443651D@norbauer.com>
>
> Justin Tobler (3):
>   remote: allow `guess_remote_head()` to suppress advice
>   builtin/clone: suppress unexpected default branch advice
>   advice: allow disabling default branch name advice
>
>  advice.c                |  1 +
>  advice.h                |  1 +
>  builtin/clone.c         |  3 ++-
>  builtin/fetch.c         |  2 +-
>  builtin/remote.c        |  2 +-
>  refs.c                  |  3 ++-
>  remote.c                | 10 ++++++----
>  remote.h                | 11 +++++++----
>  t/t0001-init.sh         |  8 ++++++++
>  t/t5607-clone-bundle.sh | 12 ++++++++++++
>  10 files changed, 41 insertions(+), 12 deletions(-)
>
>
> base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
Justin Tobler· Mar 25, 2025, 00:51 UTC · re: Justin Tobler · lore

[PATCH v3 0/3] clone: suppress unexpected advice message during clone

It has been reported[1] that starting in Git v2.45.0, cloning from a bundle results in the default branch name advice message always being displayed when it was previously not. It can be reproduced by the following:

        git init bundle-repo &&
        git -C bundle-repo commit --allow-empty -m init &&
        git -C bundle-repo bundle create ../repo.bundle --all &&
        git clone repo.bundle bundle-clone

This issue bisects to 199f44cb2ead (builtin/clone: allow remote helpers to detect repo, 2024-02-27) where the refdb is partially initialized during clones before remote helpers are executed. This partial initialization creates the HEAD file and "refs/" directory.

A side-effect of this change is that the location of the first `git_default_branch_name()` gets deferred to a later point of execution. This matters because `git_default_branch_name()` only computes the default branch name once and returns a cached value for subsequent invocations. After this change, the `git_default_branch_name()` call site that actually computes the value becomes `guess_remote_head()` and is configured to always show the advice message.

Also, `guess_remote_head()` only invokes `git_default_branch_name()` in cases where the transport is unable to figure out the remote HEAD and must guess. This explains why the advice message gets printed for bundle clones, but not all clones.

This series addresses the issue by adapting `guess_remote_head()` to support configuring the underlying `git_default_branch_name()`, which has since been renamed to `repo_default_branch_name()`, to be quiet and suppress the advice message.

Changes since V2:
        - The default branch name advice message may also print with the
          `--single-branch` option in certain scenarios. This instance
          is also suppressed by setting the `REMOTE_GUESS_HEAD_QUIET`
          flag for another `guess_remote_head()` call site invoked
          during clones.
Changes since V1:
        - Instead of adding an additional boolean to
          `guess_remote_head()` to suppress the advice message, the
          function is adapted to accepts flags that accoplish the same
          thing.
        - Added a test to validate that the advice message is not being
          printed.
        - While we are here, added another patch to allow the default
          branch name advice message to be suppressrd by the
          `--no-advice` option.

Thanks, -Justin

[1]: <7EC98E2F-144D-4974-94F6-FC24B443651D@norbauer.com>
Justin Tobler (3):
  remote: allow `guess_remote_head()` to suppress advice
  builtin/clone: suppress unexpected default branch advice
  advice: allow disabling default branch name advice
 advice.c                |  1 +
 advice.h                |  1 +
 builtin/clone.c         |  7 +++++--
 builtin/fetch.c         |  2 +-
 builtin/remote.c        |  2 +-
 refs.c                  |  3 ++-
 remote.c                | 10 ++++++----
 remote.h                | 11 +++++++----
 t/t0001-init.sh         |  8 ++++++++
 t/t5607-clone-bundle.sh | 12 ++++++++++++
 10 files changed, 44 insertions(+), 13 deletions(-)
Range-diff against v2:
1:  4dae06d2dd = 1:  4dae06d2dd remote: allow `guess_remote_head()` to suppress advice
2:  1180caabf1 ! 2:  2a69b881c4 builtin/clone: suppress unexpected default branch advice
    @@ Commit message
         Signed-off-by: Justin Tobler <jltobler@gmail.com>
     
      ## builtin/clone.c ##
    +@@ builtin/clone.c: 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;
     @@ builtin/clone.c: int cmd_clone(int argc,
      	}
      
    @@ t/t5607-clone-bundle.sh: test_expect_success 'git bundle v3 rejects unknown capa
     +	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 bundle-repo/repo.bundle clone-repo 2>err &&
    ++		git clone --single-branch bundle-repo/repo.bundle clone-repo 2>err &&
     +
     +	test_grep ! "hint: " err
     +'
3:  6fef1d070c = 3:  98b32cdc99 advice: allow disabling default branch name advice
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
-- 
2.49.0
Justin Tobler· Mar 25, 2025, 00:51 UTC · re: Justin Tobler · lore

[PATCH v3 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 <jltobler@gmail.com>
---
 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);
-- 
2.49.0
Justin Tobler· Mar 25, 2025, 00:51 UTC · re: Justin Tobler · lore

[PATCH v3 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 <jltobler@gmail.com>
---
 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
-- 
2.49.0
Justin Tobler· Mar 25, 2025, 00:51 UTC · re: Justin Tobler · lore

[PATCH v3 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 <jltobler@gmail.com>
---
 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 "<YELLOW>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 &&
-- 
2.49.0
Phillip Wood· Mar 25, 2025, 14:35 UTC · re: Justin Tobler · lore

Re: [PATCH v3 0/3] clone: suppress unexpected advice message during clone

Hi Justin
The range-diff below looks good to me, Thanks for working on this
Phillip
On 25/03/2025 00:51, Justin Tobler wrote:
Show 33 quoted lines
> Range-diff against v2:
> 1:  4dae06d2dd = 1:  4dae06d2dd remote: allow `guess_remote_head()` to suppress advice
> 2:  1180caabf1 ! 2:  2a69b881c4 builtin/clone: suppress unexpected default branch advice
>      @@ Commit message
>           Signed-off-by: Justin Tobler <jltobler@gmail.com>
>       
>        ## builtin/clone.c ##
>      +@@ builtin/clone.c: 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;
>       @@ builtin/clone.c: int cmd_clone(int argc,
>        	}
>        
>      @@ t/t5607-clone-bundle.sh: test_expect_success 'git bundle v3 rejects unknown capa
>       +	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 bundle-repo/repo.bundle clone-repo 2>err &&
>      ++		git clone --single-branch bundle-repo/repo.bundle clone-repo 2>err &&
>       +
>       +	test_grep ! "hint: " err
>       +'
> 3:  6fef1d070c = 3:  98b32cdc99 advice: allow disabling default branch name advice
> 
> base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
alan@norbauer.com· Mar 20, 2025, 04:05 UTC · re: Justin Tobler · lore

Re: bug: git shows hints that should be suppressed

Thank you, Justin and Elijah. I really appreciate you digging in.
Show 62 quoted lines
> On Mar 19, 2025, at 6:40 PM, Justin Tobler <jltobler@gmail.com> wrote:
> 
> On 25/03/19 07:45AM, Elijah Newren wrote:
>>> On Wed, Mar 19, 2025 at 2:59 AM <alan@norbauer.com> wrote:
>>> 
>>> Thank you for filling out a Git bug report!
>>> Please answer the following questions to help us understand your issue.
>>> 
>>> What did you do before the bug happened? (Steps to reproduce your issue)
>>> `GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=0 GIT_ADVICE=0 git clone --quiet /Volumes/sourcecode/npm-packages/packages/repository-tools/node_modules/.cache/@altano/repository-tools/2078b9db1d71a4f4a5422e25a7016c75/git.bundle .`
>>> 
>>> What did you expect to happen? (Expected behavior)
>>> I would expect the clone to happen without any hints because I provided both `GIT_ADVICE=0` _and_ `--quiet` to the command. Both should suppress the hint.
>>> 
>>> What happened instead? (Actual behavior)
>>> I received the "hint: Using 'master' as the name for the initial branch. This default branch name" on stderr, which caused my tests to fail (I am using git programmatically in a test).
>>> 
>>> What's different between what you expected and what actually happened?
>>> The hint on stderr was displayed.
>>> 
>>> Anything else you want to add:
>>> This behavior is NOT observed on git v2.44.0 and is observed on git v2.48.1. So the bug started occurring somewhere in between those versions. I can find the exact version the bug was introduced manually with some effort if that would be helpful.
>> 
>> Bisects to 199f44cb2ead (builtin/clone: allow remote helpers to detect
>> repo, 2024-02-27); cc'ing its author.
> 
> It looks like prior to 199f44cb2ead (builtin/clone: allow remote helpers
> to detect repo, 2024-02-27), the default branch name advice message
> would never be printed when cloning from a bundle regardless of whether
> `--quiet` option was set. This particual advice message also doesn't
> respect `GIT_ADVICE` either. So something about the change has made the
> message start printing when it previously did not.
> 
> Digging a bit further, this change started partially initializing the
> refdb with a HEAD file which had a side-effect of changing the location
> where the first `git_default_branch_name()` was invoked. This matters
> because `git_default_branch_name()` only computes the default branch
> name once and uses a cached value for subsequent invocations.
> 
> Previously, `create_reference_database()` was the first
> `git_default_branch_name()` call site and was configured to always
> suppress the advice message. Due to the refdb being partially
> initialized with a HEAD file, `create_reference_database()` stopped
> invoking `git_default_branch_name()` altogether and the default branch
> name computation was defferred to a subsequent potential call site
> `guess_remote_head()`. At this location, `git_default_branch_name()` is
> configured to not suppress advice messages.
> 
> Also, `guess_remote_head()` only invokes `git_default_branch_name()` in
> cases where the transport is unable to figure out the remote HEAD and
> must guess. This explains why the advice message gets printed for bundle
> clones, but not all clones.
> 
> One option to fix this would be to adapt `guess_remote_head()` to
> support configuring the underlying `git_default_branch_name()`, which
> has since been renamed to `repo_default_branch_name()`, to be quiet and
> suppress the advice message. The call site in clone could then be
> updated accordingly.
> 
> I'll submit a patch that does this.
> 
> -Justin

← back to recent threads