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>
pull/1191/merge
Alex Henrie 9 months ago committed by Junio C Hamano
parent dab1b7905d
commit 808213ba36
  1. 3
      Documentation/config/advice.txt
  2. 1
      advice.c
  3. 1
      advice.h
  4. 30
      builtin/checkout.c
  5. 11
      t/t2060-switch.sh

@ -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]

@ -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 },

@ -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,

@ -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)

@ -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 &&

Loading…
Cancel
Save