Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions builtin/worktree.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
"If you'd like to always have checkouts of an ambiguous <name> prefer\n"
"one remote, e.g. the 'origin' remote, consider setting\n"
"checkout.defaultRemote=origin in your config.");

struct add_opts {
int force;
int detach;
Expand Down Expand Up @@ -764,7 +774,7 @@ static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
return 1;
}

static char *dwim_branch(const char *path, char **new_branch)
static char *dwim_branch(const struct add_opts *opts, const char *path, char **new_branch)
{
int n;
int branch_exists;
Expand All @@ -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;
}
return NULL;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand Down
21 changes: 19 additions & 2 deletions t/t2400-worktree-add.sh
Original file line number Diff line number Diff line change
Expand Up @@ -624,12 +624,12 @@ test_expect_success '"add" <path> <branch> dwims' '
test_expect_success '"add" <path> <branch> dwims with checkout.defaultRemote' '
test_when_finished rm -rf repo_upstream repo_dwim foo &&
setup_remote_repo repo_upstream repo_dwim &&
git init repo_dwim &&
(
cd repo_dwim &&
git remote add repo_upstream2 ../repo_upstream &&
git fetch repo_upstream2 &&
test_must_fail git worktree add ../foo foo &&
test_must_fail git worktree add ../foo foo 2>error.actual &&
test_grep "matched multiple (2) remote tracking branches" error.actual &&
git -c checkout.defaultRemote=repo_upstream worktree add ../foo foo &&
git status -uno --porcelain >status.actual &&
test_must_be_empty status.actual
Expand Down Expand Up @@ -669,6 +669,23 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' '
test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
)
'
test_expect_success 'git worktree add --guess-remote with ambiguous name' '
test_when_finished rm -rf repo_a repo_b foo &&
setup_remote_repo repo_a repo_b &&
(
cd repo_b &&
git remote add upstream2 ../repo_a &&
git fetch upstream2 &&
git worktree add --guess-remote ../foo 2>actual &&
test_grep "matched multiple (2) remote tracking branches" actual
) &&
(
cd foo &&
test_must_fail git config "branch.foo.remote" &&
test_must_fail git config "branch.foo.merge" &&
test_cmp_rev refs/heads/main refs/heads/foo
)
'
test_expect_success 'git worktree add --guess-remote sets up tracking (quiet)' '
test_when_finished rm -rf repo_a repo_b foo &&
setup_remote_repo repo_a repo_b &&
Expand Down
Loading