This v5 should address all the comments to v4. Thanks all! It's one
patch less because the struct isn't being moved around anymore.
tbdiff:
1: 16d656ee3b ! 1: ab4529d9f5 checkout tests: index should be clean after
dwim checkout
@@ -29,6 +29,10 @@
"checkout", that's being done with "-uno" because there's going to
be
some untracked files related to the test itself which we don't care
about.
+
+ In all these tests (DWIM or otherwise) we start with a clean
index, so
+ these tests are asserting that that's still the case after the
+ "checkout", failed or otherwise.
Then if we ever run into this sort of regression, either in the
existing code or with a new feature, we'll know.
@@ -65,12 +69,8 @@
test_must_fail git checkout foo &&
+ status_uno_is_clean &&
test_must_fail git rev-parse --verify refs/heads/foo &&
-- test_branch master
-+ test_branch master &&
-+ status_uno_is_clean
- '
-
- test_expect_success 'checkout of branch from a single remote succeeds
#1' '
+ test_branch master
+ '
@@
test_might_fail git branch -D bar &&
2: 159cc0634b = 2: c8bbece403 checkout.h: wrap the arguments to
unique_tracking_name()
3: 3df4594e2d < -: ------- checkout.[ch]: move struct declaration into *.h
4: 35c6481208 < -: ------- checkout.[ch]: introduce an *_INIT macro
-: ------- > 3: 4fc5ab27fa checkout.[ch]: introduce an *_INIT macro
5: 69a834f010 ! 4: fbce6df584 checkout.[ch]: change "unique" member to
"num_matches"
@@ -11,6 +11,19 @@
diff --git a/checkout.c b/checkout.c
--- a/checkout.c
+++ b/checkout.c
+@@
+ /* const */ char *src_ref;
+ char *dst_ref;
+ struct object_id *dst_oid;
+- int unique;
++ int num_matches;
+ };
+
+-#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 1 }
++#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 0 }
+
+ static int check_tracking_name(struct remote *remote, void *cb_data)
+ {
@@
free(query.dst);
return 0;
@@ -31,20 +44,3 @@
return cb_data.dst_ref;
free(cb_data.dst_ref);
return NULL;
-
-diff --git a/checkout.h b/checkout.h
---- a/checkout.h
-+++ b/checkout.h
-@@
- /* const */ char *src_ref;
- char *dst_ref;
- struct object_id *dst_oid;
-- int unique;
-+ int num_matches;
- };
-
--#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 1 }
-+#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 0 }
-
- /*
- * Check if the branch name uniquely matches a branch name on a remote
6: 13547824dc ! 5: 6e016d43d7 checkout: pass the "num_matches" up to callers
@@ -11,16 +11,6 @@
diff --git a/builtin/checkout.c b/builtin/checkout.c
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
-@@
- }
-
- static int checkout_paths(const struct checkout_opts *opts,
-- const char *revision)
-+ const char *revision,
-+ int *dwim_remotes_matched)
- {
- int pos;
- struct checkout state = CHECKOUT_INIT;
@@
int dwim_new_local_branch_ok,
struct branch_info *new_branch_info,
@@ -59,16 +49,6 @@
argv += n;
argc -= n;
}
-@@
-
- UNLEAK(opts);
- if (opts.patch_mode || opts.pathspec.nr)
-- return checkout_paths(&opts, new_branch_info.name);
-+ return checkout_paths(&opts, new_branch_info.name,
-+ &dwim_remotes_matched);
- else
- return checkout_branch(&opts, &new_branch_info);
- }
diff --git a/builtin/worktree.c b/builtin/worktree.c
--- a/builtin/worktree.c
7: 6895b5c903 ! 6: 07b11b133d builtin/checkout.c: use "ret" variable for
return
@@ -16,12 +16,10 @@
UNLEAK(opts);
- if (opts.patch_mode || opts.pathspec.nr)
-- return checkout_paths(&opts, new_branch_info.name,
-- &dwim_remotes_matched);
+- return checkout_paths(&opts, new_branch_info.name);
- else
+ if (opts.patch_mode || opts.pathspec.nr) {
-+ int ret = checkout_paths(&opts, new_branch_info.name,
-+ &dwim_remotes_matched);
++ int ret = checkout_paths(&opts, new_branch_info.name);
+ return ret;
+ } else {
return checkout_branch(&opts, &new_branch_info);
8: 5cfc0896e5 ! 7: 97e84f6e1c checkout: add advice for ambiguous "checkout
<branch>"
@@ -8,9 +8,9 @@
exactly one remote (call it <remote>) with a matching name,
treat
as equivalent to [...] <remote>/<branch.
- This is a really useful feature, the problem is that when you
another
- remote (e.g. a fork) git won't find a unique branch name anymore,
and
- will instead print this nondescript message:
+ This is a really useful feature. The problem is that when you and
+ another remote (e.g. a fork) git won't find a unique branch name
+ anymore, and will instead print this nondescript message:
$ git checkout master
error: pathspec 'master' did not match any file(s) known to git
@@ -23,8 +23,10 @@
hint: We found 26 remotes with a reference that matched. So we
fell back
hint: on trying to resolve the argument as a path, but failed
there too!
hint:
- hint: Perhaps you meant fully qualify the branch name? E.g.
origin/<name>
- hint: instead of <name>?
+ hint: If you meant to check out a remote tracking branch on
e.g. 'origin'
+ hint: you can do so by fully-qualifying the name with the
--track option:
+ hint:
+ hint: git checkout --track origin/<name>
Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]>
@@ -90,17 +92,19 @@
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
@@
+ UNLEAK(opts);
if (opts.patch_mode || opts.pathspec.nr) {
- int ret = checkout_paths(&opts, new_branch_info.name,
- &dwim_remotes_matched);
+ int ret = checkout_paths(&opts, new_branch_info.name);
+ if (ret && dwim_remotes_matched > 1 &&
+ advice_checkout_ambiguous_remote_branch_name)
+ advise(_("The argument '%s' matched more than
one remote tracking branch.\n"
+ "We found %d remotes with a reference
that matched. So we fell back\n"
+ "on trying to resolve the argument as
a path, but failed there too!\n"
+ "\n"
-+ "Perhaps you meant fully qualify the
branch name? E.g. origin/<name>\n"
-+ "instead of <name>?"),
++ "If you meant to check out a remote
tracking branch on e.g. 'origin'\n"
++ "you can do so by fully-qualifying the
name with the --track option:\n"
++ "\n"
++ " git checkout --track
origin/<name>"),
+ argv[0],
+ dwim_remotes_matched);
return ret;
@@ -111,7 +115,7 @@
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@
- status_uno_is_clean
+ test_branch master
'
+test_expect_success 'checkout of branch from multiple remotes fails
with advice' '
9: fad1df1edd ! 8: a5cc070ebf checkout & worktree: introduce
checkout.defaultRemote
@@ -57,12 +57,14 @@
hint: We found 26 remotes with a reference that matched. So we
fell back
hint: on trying to resolve the argument as a path, but failed
there too!
hint:
- hint: Perhaps you meant fully qualify the branch name? E.g.
origin/<name>
- hint: instead of <name>?
+ hint: If you meant to check out a remote tracking branch on
e.g. 'origin'
+ hint: you can do so by fully-qualifying the name with the
--track option:
hint:
- hint: If you'd like to always have checkouts of 'master'
prefer one remote,
- hint: e.g. the 'origin' remote, consider setting
checkout.defaultRemote=origin
- hint: in your config. See the 'git-config' manual page for
details.
+ hint: git checkout --track origin/<name>
+ hint:
+ hint: If you'd like to always have checkouts of an ambiguous
<name> prefer
+ hint: one remote, e.g. the 'origin' remote, consider setting
+ hint: checkout.defaultRemote=origin in your config.
I considered splitting this into checkout.defaultRemote and
worktree.defaultRemote, but it's probably less confusing to break
our
@@ -128,7 +130,7 @@
+one for the purposes of disambiguation, even if the `<branch>` isn't
+unique across all remotes. Set it to
+e.g. `checkout.defaultRemote=origin` to always checkout remote
-+branches from there if `<branch> is ambiguous but exists on the
++branches from there if `<branch>` is ambiguous but exists on the
+'origin' remote. See also `checkout.defaultRemote` in
+linkgit:git-config[1].
++
@@ -148,7 +150,7 @@
+one for the purposes of disambiguation, even if the `<branch>` isn't
+unique across all remotes. Set it to
+e.g. `checkout.defaultRemote=origin` to always checkout remote
-+branches from there if `<branch> is ambiguous but exists on the
++branches from there if `<branch>` is ambiguous but exists on the
+'origin' remote. See also `checkout.defaultRemote` in
+linkgit:git-config[1].
++
@@ -173,22 +175,18 @@
* (c) Otherwise, if "--" is present, treat it like case (1).
*
@@
- "on trying to resolve the argument as
a path, but failed there too!\n"
+ "If you meant to check out a remote
tracking branch on e.g. 'origin'\n"
+ "you can do so by fully-qualifying the
name with the --track option:\n"
"\n"
- "Perhaps you meant fully qualify the
branch name? E.g. origin/<name>\n"
-- "instead of <name>?"),
-+ "instead of <name>?\n"
+- " git checkout --track
origin/<name>"),
++ " git checkout --track
origin/<name>\n"
+ "\n"
-+ "If you'd like to always have
checkouts of '%s' prefer one remote,\n"
-+ "e.g. the 'origin' remote, consider
setting checkout.defaultRemote=origin\n"
-+ "in your config. See the 'git-config'
manual page for details."),
++ "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."),
argv[0],
-- dwim_remotes_matched);
-+ dwim_remotes_matched,
-+ argv[0]);
+ dwim_remotes_matched);
return ret;
- } else {
- return checkout_branch(&opts, &new_branch_info);
diff --git a/checkout.c b/checkout.c
--- a/checkout.c
@@ -198,6 +196,19 @@
#include "refspec.h"
#include "checkout.h"
+#include "config.h"
+
+ struct tracking_name_data {
+ /* const */ char *src_ref;
+ char *dst_ref;
+ struct object_id *dst_oid;
+ int num_matches;
++ const char *default_remote;
++ char *default_dst_ref;
++ struct object_id *default_dst_oid;
+ };
+
+-#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 0 }
++#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 0, NULL, NULL,
NULL }
static int check_tracking_name(struct remote *remote, void *cb_data)
{
@@ -243,31 +254,21 @@
return NULL;
}
-diff --git a/checkout.h b/checkout.h
---- a/checkout.h
-+++ b/checkout.h
-@@
- char *dst_ref;
- struct object_id *dst_oid;
- int num_matches;
-+ const char *default_remote;
-+ char *default_dst_ref;
-+ struct object_id *default_dst_oid;
- };
-
--#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 0 }
-+#define TRACKING_NAME_DATA_INIT { NULL, NULL, NULL, 0, NULL, NULL,
NULL }
-
- /*
- * Check if the branch name uniquely matches a branch name on a remote
-
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@
- test_i18ngrep ! "^hint: " stderr
- '
-
+ checkout foo 2>stderr &&
+ test_branch master &&
+ status_uno_is_clean &&
+- test_i18ngrep ! "^hint: " stderr
++ test_i18ngrep ! "^hint: " stderr &&
++ # Make sure the likes of checkout -p don not print this hint
++ git checkout -p foo 2>stderr &&
++ test_i18ngrep ! "^hint: " stderr &&
++ status_uno_is_clean
++'
++
+test_expect_success 'checkout of branch from multiple remotes
succeeds with checkout.defaultRemote #1' '
+ git checkout -B master &&
+ status_uno_is_clean &&
@@ -278,11 +279,9 @@
+ test_branch foo &&
+ test_cmp_rev remotes/repo_a/foo HEAD &&
+ test_branch_upstream foo repo_a foo
-+'
-+
+ '
+
test_expect_success 'checkout of branch from a single remote succeeds
#1' '
- git checkout -B master &&
- test_might_fail git branch -D bar &&
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
--- a/t/t2025-worktree-add.sh
Ævar Arnfjörð Bjarmason (8):
checkout tests: index should be clean after dwim checkout
checkout.h: wrap the arguments to unique_tracking_name()
checkout.[ch]: introduce an *_INIT macro
checkout.[ch]: change "unique" member to "num_matches"
checkout: pass the "num_matches" up to callers
builtin/checkout.c: use "ret" variable for return
checkout: add advice for ambiguous "checkout <branch>"
checkout & worktree: introduce checkout.defaultRemote
Documentation/config.txt | 26 +++++++++++++++
Documentation/git-checkout.txt | 9 ++++++
Documentation/git-worktree.txt | 9 ++++++
advice.c | 2 ++
advice.h | 1 +
builtin/checkout.c | 41 ++++++++++++++++++-----
builtin/worktree.c | 4 +--
checkout.c | 37 ++++++++++++++++++---
checkout.h | 4 ++-
t/t2024-checkout-dwim.sh | 59 ++++++++++++++++++++++++++++++++++
t/t2025-worktree-add.sh | 21 ++++++++++++
11 files changed, 197 insertions(+), 16 deletions(-)
--
2.17.0.290.gded63e768a