switch: mention the --detach option when dying due to lack of a branch
Users who are accustomed to doing `git checkout <tag>` assume that `git switch <tag>` will do the same thing. Inform them of the --detach option so they aren't left wondering why `git switch` doesn't work but `git checkout` does. Signed-off-by: Alex Henrie <alexhenrie24@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Alex Henrie committed
Feb 25, 2022 at 23:12 UTC
808213ba36ea72408cc45117a825ad9a714535ba
5 files changed
+35
-11
Documentation/config/advice.txt
+3
@@ -85,6 +85,9 @@ advice.*::
85
linkgit:git-switch[1] or linkgit:git-checkout[1]
86
to move to the detach HEAD state, to instruct how to
87
create a local branch after the fact.
88
+ suggestDetachingHead::
89
+ Advice shown when linkgit:git-switch[1] refuses to detach HEAD
90
+ without the explicit `--detach` option.
91
checkoutAmbiguousRemoteBranchName::
92
Advice shown when the argument to
93
linkgit:git-checkout[1] and linkgit:git-switch[1]
advice.c
+1
@@ -42,6 +42,7 @@ static struct {
42
[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
43
[ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
44
[ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },
45
+ [ADVICE_SUGGEST_DETACHING_HEAD] = { "suggestDetachingHead", 1 },
46
[ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates", 1 },
47
[ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated", 1 },
48
[ADVICE_IGNORED_HOOK] = { "ignoredHook", 1 },
advice.h
+1
@@ -20,6 +20,7 @@ struct string_list;
20
ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
21
ADVICE_COMMIT_BEFORE_MERGE,
22
ADVICE_DETACHED_HEAD,
23
+ ADVICE_SUGGEST_DETACHING_HEAD,
24
ADVICE_FETCH_SHOW_FORCED_UPDATES,
25
ADVICE_GRAFT_FILE_DEPRECATED,
26
ADVICE_IGNORED_HOOK,
builtin/checkout.c
+19
-11
@@ -1397,23 +1397,31 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
1397
{
1398
struct object_id oid;
1399
char *to_free;
1400
+ int code;
1401
1402
if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
1403
const char *ref = to_free;
1404
1405
if (skip_prefix(ref, "refs/tags/", &ref))
1405
- die(_("a branch is expected, got tag '%s'"), ref);
1406
- if (skip_prefix(ref, "refs/remotes/", &ref))
1407
- die(_("a branch is expected, got remote branch '%s'"), ref);
1408
- die(_("a branch is expected, got '%s'"), ref);
1406
+ code = die_message(_("a branch is expected, got tag '%s'"), ref);
1407
+ else if (skip_prefix(ref, "refs/remotes/", &ref))
1408
+ code = die_message(_("a branch is expected, got remote branch '%s'"), ref);
1409
+ else
1410
+ code = die_message(_("a branch is expected, got '%s'"), ref);
1411
}
1410
- if (branch_info->commit)
1411
- die(_("a branch is expected, got commit '%s'"), branch_info->name);
1412
- /*
1413
- * This case should never happen because we already die() on
1414
- * non-commit, but just in case.
1415
- */
1416
- die(_("a branch is expected, got '%s'"), branch_info->name);
1412
+ else if (branch_info->commit)
1413
+ code = die_message(_("a branch is expected, got commit '%s'"), branch_info->name);
1414
+ else
1415
+ /*
1416
+ * This case should never happen because we already die() on
1417
+ * non-commit, but just in case.
1418
+ */
1419
+ code = die_message(_("a branch is expected, got '%s'"), branch_info->name);
1420
+
1421
+ if (advice_enabled(ADVICE_SUGGEST_DETACHING_HEAD))
1422
+ advise(_("If you want to detach HEAD at the commit, try again with the --detach option."));
1423
+
1424
+ exit(code);
1425
}
1426
1427
static void die_if_some_operation_in_progress(void)
t/t2060-switch.sh
+11
@@ -32,6 +32,17 @@ test_expect_success 'switch and detach' '
32
test_must_fail git symbolic-ref HEAD
33
'
34
35
+test_expect_success 'suggestion to detach' '
36
+ test_must_fail git switch main^{commit} 2>stderr &&
37
+ grep "try again with the --detach option" stderr
38
+'
39
+
40
+test_expect_success 'suggestion to detach is suppressed with advice.suggestDetachingHead=false' '
41
+ test_config advice.suggestDetachingHead false &&
42
+ test_must_fail git switch main^{commit} 2>stderr &&
43
+ ! grep "try again with the --detach option" stderr
44
+'
45
+
46
test_expect_success 'switch and detach current branch' '
47
test_when_finished git switch main &&
48
git switch main &&