* [PATCH v2] switch: mention the --detach option when dying due to lack of a branch
@ 2022-02-24 6:47 Alex Henrie
2022-02-24 8:53 ` Ævar Arnfjörð Bjarmason
2022-02-24 19:02 ` Junio C Hamano
0 siblings, 2 replies; 6+ messages in thread
From: Alex Henrie @ 2022-02-24 6:47 UTC (permalink / raw)
To: git, gitster, avarab, pclouds; +Cc: Alex Henrie
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>
---
v2:
- Rephrase advice
- Print advice after error message
- Create a new config variable to suppress the advice
- Add tests
---
Documentation/config/advice.txt | 3 +++
advice.c | 1 +
advice.h | 1 +
builtin/checkout.c | 30 +++++++++++++++++++-----------
t/t2060-switch.sh | 11 +++++++++++
5 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index adee26fbbb..c40eb09cb7 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -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]
diff --git a/advice.c b/advice.c
index e00d30254c..2e1fd48304 100644
--- 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 },
diff --git a/advice.h b/advice.h
index a7521d6087..a3957123a1 100644
--- 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,
diff --git a/builtin/checkout.c b/builtin/checkout.c
index d9b31bbb6d..9244827ca0 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -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)
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index ebb961be29..f54691bac9 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -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 &&
+ test_i18ngrep "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 &&
+ test_i18ngrep ! "try again with the --detach option" stderr
+'
+
test_expect_success 'switch and detach current branch' '
test_when_finished git switch main &&
git switch main &&
--
2.35.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2] switch: mention the --detach option when dying due to lack of a branch
2022-02-24 6:47 [PATCH v2] switch: mention the --detach option when dying due to lack of a branch Alex Henrie
@ 2022-02-24 8:53 ` Ævar Arnfjörð Bjarmason
2022-02-24 19:02 ` Junio C Hamano
1 sibling, 0 replies; 6+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-24 8:53 UTC (permalink / raw)
To: Alex Henrie; +Cc: git, gitster, pclouds
On Wed, Feb 23 2022, Alex Henrie wrote:
> 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.
Thanks, this looks good to me! FWIW while testing this v2 I came up with
this on top, which you may or may not want (some unrelated changes):
1. We had a to_free but didn't free it, now we do. Didn't matter with
SANITIZE=leak, but FWIW valgrind with "valgrind --leak-check=full
--show-leak-kinds=all" is marginally happier
2. Maybe s/code = /return / with a helper is easier to read, maybe not.
3. That #2 makes the code/advice wrapper simpler (also with the to_free)
4. Used test_cmp in the test to check the actual output we got, and added
a missing test for the "tag" case.
In any case s/test_i18ngrep/grep/ is the right thing nowadays for new code.
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 9244827ca02..9e4d03343fa 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1393,34 +1393,39 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
return status;
}
-static void die_expecting_a_branch(const struct branch_info *branch_info)
+static int die_expecting_a_branch_message(const struct branch_info *branch_info, char **to_free)
{
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 (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))
- code = die_message(_("a branch is expected, got tag '%s'"), ref);
+ return 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);
+ return die_message(_("a branch is expected, got remote branch '%s'"), ref);
else
- code = die_message(_("a branch is expected, got '%s'"), ref);
+ return die_message(_("a branch is expected, got '%s'"), ref);
}
else if (branch_info->commit)
- code = die_message(_("a branch is expected, got commit '%s'"), branch_info->name);
+ return 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);
+ return die_message(_("a branch is expected, got '%s'"), branch_info->name);
+}
+
+static void die_expecting_a_branch(const struct branch_info *branch_info)
+{
+ char *to_free = NULL;
+ int code = die_expecting_a_branch_message(branch_info, &to_free);
if (advice_enabled(ADVICE_SUGGEST_DETACHING_HEAD))
advise(_("If you want to detach HEAD at the commit, try again with the --detach option."));
+ free(to_free);
exit(code);
}
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index f54691bac9f..0708359ee24 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -32,15 +32,31 @@ 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 &&
- test_i18ngrep "try again with the --detach option" stderr
+test_expect_success 'suggestion to detach commit' '
+ test_must_fail git switch main^{commit} 2>actual &&
+ cat >expect <<-\EOF &&
+ fatal: a branch is expected, got commit '\''main^{commit}'\''
+ hint: If you want to detach HEAD at the commit, try again with the --detach option.
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'suggestion to detach tag' '
+ test_must_fail git switch first 2>actual &&
+ cat >expect <<-\EOF &&
+ fatal: a branch is expected, got tag '\''first'\''
+ hint: If you want to detach HEAD at the commit, try again with the --detach option.
+ EOF
+ test_cmp expect actual
'
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 &&
- test_i18ngrep ! "try again with the --detach option" stderr
+ test_must_fail git switch main^{commit} 2>actual &&
+ cat >expect <<-\EOF &&
+ fatal: a branch is expected, got commit '\''main^{commit}'\''
+ EOF
+ test_cmp expect actual
'
test_expect_success 'switch and detach current branch' '
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2] switch: mention the --detach option when dying due to lack of a branch
2022-02-24 6:47 [PATCH v2] switch: mention the --detach option when dying due to lack of a branch Alex Henrie
2022-02-24 8:53 ` Ævar Arnfjörð Bjarmason
@ 2022-02-24 19:02 ` Junio C Hamano
2022-02-25 11:57 ` Ævar Arnfjörð Bjarmason
1 sibling, 1 reply; 6+ messages in thread
From: Junio C Hamano @ 2022-02-24 19:02 UTC (permalink / raw)
To: Alex Henrie; +Cc: git, avarab, pclouds
Alex Henrie <alexhenrie24@gmail.com> writes:
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index d9b31bbb6d..9244827ca0 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -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);
In the original code, when dwim_ref() said there is a unique hit, we
died with varying messages. So it was OK to have this check not as
a part of if/elseif/... cascade.
> - /*
> - * 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)
But now, new code only sets code without dying, so we avoid
overwriting the code (and calling die_message() twice) by turning it
"else if". OK.
> + 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);
OK. So "code" gets assigned exactly once in the above
if/elseif/... cascade. Not defining the variable with
initialization at the beginning of this function is correct.
> + 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);
> }
OK.
> diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
> index ebb961be29..f54691bac9 100755
> --- a/t/t2060-switch.sh
> +++ b/t/t2060-switch.sh
> @@ -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 &&
> + test_i18ngrep "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 &&
> + test_i18ngrep ! "try again with the --detach option" stderr
> +'
OK, we try to be consistent with other tests in the file, and leave
s/test_i18n// to a file-wide clean-up outside the topic.
> test_expect_success 'switch and detach current branch' '
> test_when_finished git switch main &&
> git switch main &&
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] switch: mention the --detach option when dying due to lack of a branch
2022-02-24 19:02 ` Junio C Hamano
@ 2022-02-25 11:57 ` Ævar Arnfjörð Bjarmason
2022-02-25 17:20 ` Alex Henrie
2022-02-25 17:26 ` Junio C Hamano
0 siblings, 2 replies; 6+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-25 11:57 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Alex Henrie, git, pclouds
On Thu, Feb 24 2022, Junio C Hamano wrote:
> Alex Henrie <alexhenrie24@gmail.com> writes:
>> diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
>> index ebb961be29..f54691bac9 100755
>> --- a/t/t2060-switch.sh
>> +++ b/t/t2060-switch.sh
>> @@ -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 &&
>> + test_i18ngrep "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 &&
>> + test_i18ngrep ! "try again with the --detach option" stderr
>> +'
>
> OK, we try to be consistent with other tests in the file, and leave
> s/test_i18n// to a file-wide clean-up outside the topic.
FWIW that's not the case here. This is the first use of test_i18ngrep in
this file.
But better to use test_cmp as noted in
<220224.86sfs8abj6.gmgdl@evledraar.gmail.com> in the sid-thread.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] switch: mention the --detach option when dying due to lack of a branch
2022-02-25 11:57 ` Ævar Arnfjörð Bjarmason
@ 2022-02-25 17:20 ` Alex Henrie
2022-02-25 17:26 ` Junio C Hamano
1 sibling, 0 replies; 6+ messages in thread
From: Alex Henrie @ 2022-02-25 17:20 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: Junio C Hamano, Git mailing list,
Nguyễn Thái Ngọc Duy
On Fri, Feb 25, 2022 at 4:57 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> On Thu, Feb 24 2022, Junio C Hamano wrote:
>
> > Alex Henrie <alexhenrie24@gmail.com> writes:
> >> diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
> >> index ebb961be29..f54691bac9 100755
> >> --- a/t/t2060-switch.sh
> >> +++ b/t/t2060-switch.sh
> >> @@ -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 &&
> >> + test_i18ngrep "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 &&
> >> + test_i18ngrep ! "try again with the --detach option" stderr
> >> +'
> >
> > OK, we try to be consistent with other tests in the file, and leave
> > s/test_i18n// to a file-wide clean-up outside the topic.
>
> FWIW that's not the case here. This is the first use of test_i18ngrep in
> this file.
>
> But better to use test_cmp as noted in
> <220224.86sfs8abj6.gmgdl@evledraar.gmail.com> in the sid-thread.
Why is test_cmp preferable to grep in tests like this?
-Alex
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] switch: mention the --detach option when dying due to lack of a branch
2022-02-25 11:57 ` Ævar Arnfjörð Bjarmason
2022-02-25 17:20 ` Alex Henrie
@ 2022-02-25 17:26 ` Junio C Hamano
1 sibling, 0 replies; 6+ messages in thread
From: Junio C Hamano @ 2022-02-25 17:26 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason; +Cc: Alex Henrie, git, pclouds
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>> + test_i18ngrep ! "try again with the --detach option" stderr
>>> +'
>>
>> OK, we try to be consistent with other tests in the file, and leave
>> s/test_i18n// to a file-wide clean-up outside the topic.
>
> FWIW that's not the case here. This is the first use of test_i18ngrep in
> this file.
Oh, thanks for pointing it out---I remembered that somebody gave a
similar suggestion and blindly assumed that there are other
instances already. If so, picking, between grep and test_cmp,
whichever requires the least amount of boilerplate code is fine by
me.
Thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2022-02-25 17:26 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-24 6:47 [PATCH v2] switch: mention the --detach option when dying due to lack of a branch Alex Henrie
2022-02-24 8:53 ` Ævar Arnfjörð Bjarmason
2022-02-24 19:02 ` Junio C Hamano
2022-02-25 11:57 ` Ævar Arnfjörð Bjarmason
2022-02-25 17:20 ` Alex Henrie
2022-02-25 17:26 ` Junio C Hamano
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).