Merge branch 'nd/checkout-dwim-fix'

"git checkout frotz" (without any double-dash) avoids ambiguity by
making sure 'frotz' cannot be interpreted as a revision and as a
path at the same time.  This safety has been updated to check also
a unique remote-tracking branch 'frotz' in a remote, when dwimming
to create a local branch 'frotz' out of a remote-tracking branch
'frotz' from a remote.

* nd/checkout-dwim-fix:
  checkout: disambiguate dwim tracking branches and local files
This commit is contained in:
Junio C Hamano 2019-01-04 13:33:34 -08:00
Родитель 0a84724bf8 be4908f103
Коммит 8d7f9dbf84
4 изменённых файлов: 50 добавлений и 6 удалений

Просмотреть файл

@ -276,6 +276,10 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
Just like linkgit:git-submodule[1], this will detach the
submodules HEAD.
--no-guess::
Do not attempt to create a branch if a remote tracking branch
of the same name exists.
<branch>::
Branch to checkout; if it refers to a branch (i.e., a name that,
when prepended with "refs/heads/", is a valid ref), then that

Просмотреть файл

@ -1080,9 +1080,12 @@ static int parse_branchname_arg(int argc, const char **argv,
*/
int recover_with_dwim = dwim_new_local_branch_ok;
if (!has_dash_dash &&
(check_filename(opts->prefix, arg) || !no_wildcard(arg)))
int could_be_checkout_paths = !has_dash_dash &&
check_filename(opts->prefix, arg);
if (!has_dash_dash && !no_wildcard(arg))
recover_with_dwim = 0;
/*
* Accept "git checkout foo" and "git checkout foo --"
* as candidates for dwim.
@ -1095,6 +1098,10 @@ static int parse_branchname_arg(int argc, const char **argv,
const char *remote = unique_tracking_name(arg, rev,
dwim_remotes_matched);
if (remote) {
if (could_be_checkout_paths)
die(_("'%s' could be both a local file and a tracking branch.\n"
"Please use -- (and optionally --no-guess) to disambiguate"),
arg);
*new_branch = arg;
arg = remote;
/* DWIMmed to create local branch, case (3).(b) */
@ -1229,7 +1236,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
struct checkout_opts opts;
struct branch_info new_branch_info;
char *conflict_style = NULL;
int dwim_new_local_branch = 1;
int dwim_new_local_branch, no_dwim_new_local_branch = 0;
int dwim_remotes_matched = 0;
struct option options[] = {
OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
@ -1259,8 +1266,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")),
OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
N_("second guess 'git checkout <no-such-branch>'")),
OPT_BOOL(0, "no-guess", &no_dwim_new_local_branch,
N_("do not second guess 'git checkout <no-such-branch>'")),
OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
N_("do not check if another worktree is holding the given ref")),
{ OPTION_CALLBACK, 0, "recurse-submodules", NULL,
@ -1283,6 +1290,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
dwim_new_local_branch = !no_dwim_new_local_branch;
if (opts.show_progress < 0) {
if (opts.quiet)
opts.show_progress = 0;

Просмотреть файл

@ -278,4 +278,35 @@ test_expect_success 'loosely defined local base branch is reported correctly' '
test_cmp expect actual
'
test_expect_success 'reject when arg could be part of dwim branch' '
git remote add foo file://non-existent-place &&
git update-ref refs/remotes/foo/dwim-arg HEAD &&
echo foo >dwim-arg &&
git add dwim-arg &&
echo bar >dwim-arg &&
test_must_fail git checkout dwim-arg &&
test_must_fail git rev-parse refs/heads/dwim-arg -- &&
grep bar dwim-arg
'
test_expect_success 'disambiguate dwim branch and checkout path (1)' '
git update-ref refs/remotes/foo/dwim-arg1 HEAD &&
echo foo >dwim-arg1 &&
git add dwim-arg1 &&
echo bar >dwim-arg1 &&
git checkout -- dwim-arg1 &&
test_must_fail git rev-parse refs/heads/dwim-arg1 -- &&
grep foo dwim-arg1
'
test_expect_success 'disambiguate dwim branch and checkout path (2)' '
git update-ref refs/remotes/foo/dwim-arg2 HEAD &&
echo foo >dwim-arg2 &&
git add dwim-arg2 &&
echo bar >dwim-arg2 &&
git checkout dwim-arg2 -- &&
git rev-parse refs/heads/dwim-arg2 -- &&
grep bar dwim-arg2
'
test_done

Просмотреть файл

@ -1434,7 +1434,8 @@ test_expect_success 'double dash "git checkout"' '
--ignore-other-worktrees Z
--recurse-submodules Z
--progress Z
--no-quiet Z
--guess Z
--no-guess Z
--no-... Z
EOF
'