Skip to content

worktree add: improve message for ambiguous remote branch name - #2197

Open
yoichi wants to merge 1 commit into
gitgitgadget:masterfrom
yoichi:improve-worktree-add-error-message
Open

worktree add: improve message for ambiguous remote branch name#2197
yoichi wants to merge 1 commit into
gitgitgadget:masterfrom
yoichi:improve-worktree-add-error-message

Conversation

@yoichi

@yoichi yoichi commented Aug 8, 2026

Copy link
Copy Markdown

No description provided.

@yoichi
yoichi force-pushed the improve-worktree-add-error-message branch from 40835c8 to 63d9b6b Compare August 8, 2026 06:17
Display a descriptive message when DWIM fails.

Add advice on how to work around this by specifying the fully
qualified name or by setting checkout.defaultRemote.

Signed-off-by: Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>
@yoichi
yoichi force-pushed the improve-worktree-add-error-message branch from 63d9b6b to 00b814f Compare August 8, 2026 06:34
@yoichi

yoichi commented Aug 8, 2026

Copy link
Copy Markdown
Author

/submit

@gitgitgadget

gitgitgadget Bot commented Aug 8, 2026

Copy link
Copy Markdown

Submitted as pull.2197.git.1786177301832.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-2197/yoichi/improve-worktree-add-error-message-v1

To fetch this version to local tag pr-2197/yoichi/improve-worktree-add-error-message-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-2197/yoichi/improve-worktree-add-error-message-v1

@gitgitgadget

gitgitgadget Bot commented Aug 8, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

"Yoichi NAKAYAMA via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>
>
> Display a descriptive message when DWIM fails.
>
> Add advice on how to work around this by specifying the fully
> qualified name or by setting checkout.defaultRemote.
>
> Signed-off-by: Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>
> ---
>     worktree add: improve message for ambiguous remote branch name
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2197%2Fyoichi%2Fimprove-worktree-add-error-message-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2197/yoichi/improve-worktree-add-error-message-v1
> Pull-Request: https://github.com/gitgitgadget/git/pull/2197
>
>  builtin/worktree.c      | 30 ++++++++++++++++++++++++++----
>  t/t2400-worktree-add.sh | 21 +++++++++++++++++++--
>  2 files changed, 45 insertions(+), 6 deletions(-)
>
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 654d27c3e1..46bc305116 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -116,6 +116,16 @@ static const char * const git_worktree_unlock_usage[] = {
>  	NULL
>  };
>  
> +static const char message_advice_ambiguous_remote_tracking_branch[] =
> +	N_("If you meant to create a worktree from a remote tracking branch on,\n"
> +	   "e.g. 'origin', you can do so by fully qualifying the name:\n"
> +	   "\n"
> +	   "    git worktree add <path> origin/<name>\n"
> +	   "\n"

This is shown in two places, but what did the user exactly type in
these two situations?  Can their intent be different, in which case
different suggestions might be more appropriate to each of them?

Let's see.

> @@ -781,8 +791,14 @@ static char *dwim_branch(const char *path, char **new_branch)
>  
>  	*new_branch = branchname;
>  	if (guess_remote) {
> +		int num_matches = 0;
>  		struct object_id oid;
> -		char *remote = unique_tracking_name(*new_branch, &oid, NULL);
> +		char *remote = unique_tracking_name(*new_branch, &oid, &num_matches);
> +		if (!opts->quiet && !remote && num_matches > 1) {
> +			if (advice_enabled(ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME))
> +				advise(_(message_advice_ambiguous_remote_tracking_branch));
> +			warning(_("'%s' matched multiple (%d) remote tracking branches\n"), branchname, num_matches);
> +		}
>  		return remote;
>  	}

The worktree.guessremote configuration is set.  dwim_branch() is
called when "git worktree add A/B/X" is run with a single argument
"A/B/X", which comes here as "path", and that is munged into the
branchname "X".

We used to pass NULL as the second parameter to unique_tracking_name(),
so we were only interested in the case where we have exactly one
matching remote, and if there is 0 or multiple remotes with the
named branch, we returned NULL from here.

The patch does not change that, but using the branch name, we try to
see if there are multiple matches, in that case, we give the advice
message to say "hey, don't be so lazy, as X appears in more than one
remote, so tell me which one you mean".

> @@ -890,7 +906,7 @@ static int add(int ac, const char **av, const char *prefix,
>  		opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
>  	} else if (ac < 2) {
>  		/* DWIM: Guess branch name from path. */
> -		char *s = dwim_branch(path, &new_branch_to_free);
> +		char *s = dwim_branch(&opts, path, &new_branch_to_free);
>  		if (s)
>  			branch = branch_to_free = s;
>  		new_branch = new_branch_to_free;

But shouldn't we do a bit better than 

    git worktree add <path> origin/<name>

The above makes the user think that just like 'git', 'worktree' and
'add', 'origin/' is a fixed part, and they would need to substitute
<path> and <name>, but that is not really what we want to tell them.
The most crucial part to correct is 'origin/', as that is what we
could not guess from the given information.

We know that the user gave us "A/B/X" (path) and probably they want
to create local "X" from it.  Or not.  We also should know, in
caller's opt_track and used_new_branch_options, that the user gave
us "-t -b Y" from the command line.

> @@ -904,10 +920,16 @@ static int add(int ac, const char **av, const char *prefix,
>  
>  		commit = lookup_commit_reference_by_name(branch);
>  		if (!commit) {
> -			remote = unique_tracking_name(branch, &oid, NULL);
> +			int num_matches = 0;
> +			remote = unique_tracking_name(branch, &oid, &num_matches);
>  			if (remote) {
>  				new_branch = branch;
>  				branch = new_branch_to_free = remote;
> +			} else if (num_matches > 1) {
> +				if (!opts.quiet && advice_enabled(ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME)) {
> +					advise(_(message_advice_ambiguous_remote_tracking_branch));
> +				}
> +				die(_("'%s' matched multiple (%d) remote tracking branches"), branch, num_matches);

Style: overly long line, with {braces} around a single statement block.

What does this case handle?  Can you make a similar analysis to come
up with the list of things we know the user gave us, to give a bit
better command line to suggest here?

>  			}
>  		}

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant