]> Kevux Git Server - rit/commitdiff
switch: mention the --detach option when dying due to lack of a branch
authorAlex Henrie <alexhenrie24@gmail.com>
Sat, 26 Feb 2022 06:12:13 +0000 (23:12 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 26 Feb 2022 06:21:48 +0000 (22:21 -0800)
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>
Documentation/config/advice.txt
advice.c
advice.h
builtin/checkout.c
t/t2060-switch.sh

index adee26f..c40eb09 100644 (file)
@@ -85,6 +85,9 @@ advice.*::
                linkgit:git-switch[1] or linkgit:git-checkout[1]
                to move to the detach HEAD state, to instruct how to
                create a local branch after the fact.
+       suggestDetachingHead::
+               Advice shown when linkgit:git-switch[1] refuses to detach HEAD
+               without the explicit `--detach` option.
        checkoutAmbiguousRemoteBranchName::
                Advice shown when the argument to
                linkgit:git-checkout[1] and linkgit:git-switch[1]
index e00d302..2e1fd48 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -42,6 +42,7 @@ static struct {
        [ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME]  = { "checkoutAmbiguousRemoteBranchName", 1 },
        [ADVICE_COMMIT_BEFORE_MERGE]                    = { "commitBeforeMerge", 1 },
        [ADVICE_DETACHED_HEAD]                          = { "detachedHead", 1 },
+       [ADVICE_SUGGEST_DETACHING_HEAD]                 = { "suggestDetachingHead", 1 },
        [ADVICE_FETCH_SHOW_FORCED_UPDATES]              = { "fetchShowForcedUpdates", 1 },
        [ADVICE_GRAFT_FILE_DEPRECATED]                  = { "graftFileDeprecated", 1 },
        [ADVICE_IGNORED_HOOK]                           = { "ignoredHook", 1 },
index a7521d6..a395712 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -20,6 +20,7 @@ struct string_list;
        ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
        ADVICE_COMMIT_BEFORE_MERGE,
        ADVICE_DETACHED_HEAD,
+       ADVICE_SUGGEST_DETACHING_HEAD,
        ADVICE_FETCH_SHOW_FORCED_UPDATES,
        ADVICE_GRAFT_FILE_DEPRECATED,
        ADVICE_IGNORED_HOOK,
index d9b31bb..9244827 100644 (file)
@@ -1397,23 +1397,31 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
 {
        struct object_id oid;
        char *to_free;
+       int code;
 
        if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
                const char *ref = to_free;
 
                if (skip_prefix(ref, "refs/tags/", &ref))
-                       die(_("a branch is expected, got tag '%s'"), ref);
-               if (skip_prefix(ref, "refs/remotes/", &ref))
-                       die(_("a branch is expected, got remote branch '%s'"), ref);
-               die(_("a branch is expected, got '%s'"), ref);
+                       code = die_message(_("a branch is expected, got tag '%s'"), ref);
+               else if (skip_prefix(ref, "refs/remotes/", &ref))
+                       code = die_message(_("a branch is expected, got remote branch '%s'"), ref);
+               else
+                       code = die_message(_("a branch is expected, got '%s'"), ref);
        }
-       if (branch_info->commit)
-               die(_("a branch is expected, got commit '%s'"), branch_info->name);
-       /*
-        * This case should never happen because we already die() on
-        * non-commit, but just in case.
-        */
-       die(_("a branch is expected, got '%s'"), branch_info->name);
+       else if (branch_info->commit)
+               code = die_message(_("a branch is expected, got commit '%s'"), branch_info->name);
+       else
+               /*
+                * This case should never happen because we already die() on
+                * non-commit, but just in case.
+                */
+               code = die_message(_("a branch is expected, got '%s'"), branch_info->name);
+
+       if (advice_enabled(ADVICE_SUGGEST_DETACHING_HEAD))
+               advise(_("If you want to detach HEAD at the commit, try again with the --detach option."));
+
+       exit(code);
 }
 
 static void die_if_some_operation_in_progress(void)
index ebb961b..5a7caf9 100755 (executable)
@@ -32,6 +32,17 @@ test_expect_success 'switch and detach' '
        test_must_fail git symbolic-ref HEAD
 '
 
+test_expect_success 'suggestion to detach' '
+       test_must_fail git switch main^{commit} 2>stderr &&
+       grep "try again with the --detach option" stderr
+'
+
+test_expect_success 'suggestion to detach is suppressed with advice.suggestDetachingHead=false' '
+       test_config advice.suggestDetachingHead false &&
+       test_must_fail git switch main^{commit} 2>stderr &&
+       ! grep "try again with the --detach option" stderr
+'
+
 test_expect_success 'switch and detach current branch' '
        test_when_finished git switch main &&
        git switch main &&