{"thread":{"id":"61230","subject":"Bug: `git switch --detach` gives inapplicable advice","startedAt":"2024-03-30T07:50:11Z","lastAt":"2024-04-05T17:07:44Z","messageCount":4,"participants":["mirth hickford","Junio C Hamano","M Hickford"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"491869","messageId":"CAKcCxfAVGr2QoaXiT81gVZ0mfq3zJs7TywRhJzevwKX7wChJ4w@mail.gmail.com","threadId":"61230","inReplyTo":null,"subject":"Bug: `git switch --detach` gives inapplicable advice","fromName":"mirth hickford","fromEmail":"mirth.hickford@gmail.com","sentAt":"2024-03-30T07:49:58Z","receivedAt":"2024-03-30T07:50:11Z","isPatch":false,"sender":{"key":"mirth.hickford@gmail.com","avatar":"https://avatars.githubusercontent.com/u/105314?v=4"},"body":"Is this a bug? \"Your branch can be fast-forwarded\" doesn't apply to a\ndetached HEAD.\n\n> git switch main\n> git reset --hard origin/main~1\n> git switch --detach main\nHEAD is now at 5a07c3bde Refactor...\nYour branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.\n  (use \"git pull\" to update your local branch)\n\n> git pull\nYou are not currently on a branch.\n"},{"id":"491900","messageId":"xmqqa5mfl7ud.fsf@gitster.g","threadId":"61230","inReplyTo":"CAKcCxfAVGr2QoaXiT81gVZ0mfq3zJs7TywRhJzevwKX7wChJ4w@mail.gmail.com","subject":"[PATCH] checkout: do not bother \"tracking\" report on detached HEAD","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-03-30T21:37:14Z","receivedAt":"2024-03-30T21:37:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"By definition, a detached HEAD state is tentative and there is no\nconfigured \"upstream\" that it always wants to integrate with.  But\nif you detach from a branch that is behind its upstream, e.g.,\n\n    $ git checkout -t -b main origin/main\n    $ git checkout main\n    $ git reset --hard HEAD^\n    $ git checkout --detach main\n\nyou'd see \"you are behind your upstream origin/main\".  This does not\nhappen when you replace the last step in the above with any of these\n\n    $ git checkout HEAD^0\n    $ git checkout --detach HEAD\n    $ git checkout --detach origin/main\n\nBefore 32669671 (checkout: introduce --detach synonym for \"git\ncheckout foo^{commit}\", 2011-02-08) introduced the \"--detach\"\noption, the rule to decide if we show the tracking information\nused to be:\n\n    If --quiet is not given, and if the given branch name is a real\n    local branch (i.e. the one we can compute the file path under\n    .git/, like 'refs/heads/master' or \"HEAD\" which stand for the\n    name of the current branch\", then give the tracking information.\n\nto exclude things like \"git checkout master^0\" (which was the\nofficial way to detach HEAD at the commit before that commit) and\n\"git checkout origin/master^0\" from showing tracking information,\nbut still do show the tracking information for the current branch\nfor \"git checkout HEAD\".  The introduction of an explicit option\n\"--detach\" broke this subtley.  The new rule should have been\n\n    If --quiet is given, do not bother with tracking info.\n    If --detach is given, do not bother with tracking info.\n\n    Otherwise, if we know that the branch name given is a real local\n    branch, or if we were given \"HEAD\" and \"HEAD\" is not detached,\n    then attempt to show the tracking info.\n\nbut it allowed \"git checkout --detach master\" to also show the\ntracking info by mistake.  Let's tighten the rule to fix this.\n\nReported-by: mirth hickford <mirth.hickford@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n    mirth hickford <mirth.hickford@gmail.com> writes:\n\n    >> git switch --detach main\n    > HEAD is now at 5a07c3bde Refactor...\n    > Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.\n    >   (use \"git pull\" to update your local branch)\n    >\n    >> git pull\n    > You are not currently on a branch.\n\n    I think the instruction meant to say \"use 'git pull' with\n    appropriate options to update\" but had to ellide the details due\n    to limited screen real estate.  And it is quite expected that a\n    \"git pull\" from a detached HEAD would not do anything.\n\n    Because my local branches do not track any upstream branches, I\n    have little experience with the message in question.  Given\n    that, I doubt that I am the best person to comment on this\n    issue, but having said that, I observe that this is shared\n    between \"checkout\" and \"switch\".\n\n    Having said that, I think that the instruction is what is wrong.\n    What is wrong is the fact that the command assumed that you want\n    to keep up with the upstream of the branch you detached from.\n\n builtin/checkout.c         | 3 ++-\n t/t2020-checkout-detach.sh | 5 ++++-\n 2 files changed, 6 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2e8b0d18f4..26e1a64569 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1030,7 +1030,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n \tremove_branch_state(the_repository, !opts->quiet);\n \tstrbuf_release(&msg);\n \tif (!opts->quiet &&\n-\t    (new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, \"HEAD\"))))\n+\t    !opts->force_detach &&\n+\t    (new_branch_info->path || !strcmp(new_branch_info->name, \"HEAD\")))\n \t\treport_tracking(new_branch_info);\n }\n \ndiff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh\nindex bce284c297..8d90d02850 100755\n--- a/t/t2020-checkout-detach.sh\n+++ b/t/t2020-checkout-detach.sh\n@@ -176,7 +176,10 @@ test_expect_success 'tracking count is accurate after orphan check' '\n \tgit config branch.child.merge refs/heads/main &&\n \tgit checkout child^ &&\n \tgit checkout child >stdout &&\n-\ttest_cmp expect stdout\n+\ttest_cmp expect stdout &&\n+\n+\tgit checkout --detach child >stdout &&\n+\ttest_grep ! \"can be fast-forwarded\\.\" stdout\n '\n \n test_expect_success 'no advice given for explicit detached head state' '\n-- \n2.44.0-413-gd6fd04375f\n\n\n\n"},{"id":"492281","messageId":"CAGJzqsmE9FDEBn=u3ge4LA3ha4fDbm4OWiuUbMaztwjELBd7ug@mail.gmail.com","threadId":"61230","inReplyTo":"xmqqa5mfl7ud.fsf@gitster.g","subject":"Re: [PATCH] checkout: do not bother \"tracking\" report on detached HEAD","fromName":"M Hickford","fromEmail":"mirth.hickford@gmail.com","sentAt":"2024-04-05T07:00:00Z","receivedAt":"2024-04-05T07:01:26Z","isPatch":true,"sender":{"key":"mirth.hickford@gmail.com","avatar":"https://avatars.githubusercontent.com/u/105314?v=4"},"body":"On Sat, 30 Mar 2024 at 21:37, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> By definition, a detached HEAD state is tentative and there is no\n> configured \"upstream\" that it always wants to integrate with.  But\n> if you detach from a branch that is behind its upstream, e.g.,\n>\n>     $ git checkout -t -b main origin/main\n>     $ git checkout main\n>     $ git reset --hard HEAD^\n>     $ git checkout --detach main\n>\n> you'd see \"you are behind your upstream origin/main\".  This does not\n> happen when you replace the last step in the above with any of these\n>\n>     $ git checkout HEAD^0\n>     $ git checkout --detach HEAD\n>     $ git checkout --detach origin/main\n>\n> Before 32669671 (checkout: introduce --detach synonym for \"git\n> checkout foo^{commit}\", 2011-02-08) introduced the \"--detach\"\n> option, the rule to decide if we show the tracking information\n> used to be:\n>\n>     If --quiet is not given, and if the given branch name is a real\n>     local branch (i.e. the one we can compute the file path under\n>     .git/, like 'refs/heads/master' or \"HEAD\" which stand for the\n>     name of the current branch\", then give the tracking information.\n>\n> to exclude things like \"git checkout master^0\" (which was the\n> official way to detach HEAD at the commit before that commit) and\n> \"git checkout origin/master^0\" from showing tracking information,\n> but still do show the tracking information for the current branch\n> for \"git checkout HEAD\".  The introduction of an explicit option\n> \"--detach\" broke this subtley.  The new rule should have been\n>\n>     If --quiet is given, do not bother with tracking info.\n>     If --detach is given, do not bother with tracking info.\n>\n>     Otherwise, if we know that the branch name given is a real local\n>     branch, or if we were given \"HEAD\" and \"HEAD\" is not detached,\n>     then attempt to show the tracking info.\n>\n> but it allowed \"git checkout --detach master\" to also show the\n> tracking info by mistake.  Let's tighten the rule to fix this.\n>\n> Reported-by: mirth hickford <mirth.hickford@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>\n>     mirth hickford <mirth.hickford@gmail.com> writes:\n>\n>     >> git switch --detach main\n>     > HEAD is now at 5a07c3bde Refactor...\n>     > Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.\n>     >   (use \"git pull\" to update your local branch)\n>     >\n>     >> git pull\n>     > You are not currently on a branch.\n>\n>     I think the instruction meant to say \"use 'git pull' with\n>     appropriate options to update\" but had to ellide the details due\n>     to limited screen real estate.  And it is quite expected that a\n>     \"git pull\" from a detached HEAD would not do anything.\n>\n>     Because my local branches do not track any upstream branches, I\n>     have little experience with the message in question.  Given\n>     that, I doubt that I am the best person to comment on this\n>     issue, but having said that, I observe that this is shared\n>     between \"checkout\" and \"switch\".\n>\n>     Having said that, I think that the instruction is what is wrong.\n>     What is wrong is the fact that the command assumed that you want\n>     to keep up with the upstream of the branch you detached from.\n>\n>  builtin/checkout.c         | 3 ++-\n>  t/t2020-checkout-detach.sh | 5 ++++-\n>  2 files changed, 6 insertions(+), 2 deletions(-)\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 2e8b0d18f4..26e1a64569 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -1030,7 +1030,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n>         remove_branch_state(the_repository, !opts->quiet);\n>         strbuf_release(&msg);\n>         if (!opts->quiet &&\n> -           (new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, \"HEAD\"))))\n> +           !opts->force_detach &&\n> +           (new_branch_info->path || !strcmp(new_branch_info->name, \"HEAD\")))\n>                 report_tracking(new_branch_info);\n>  }\n>\n> diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh\n> index bce284c297..8d90d02850 100755\n> --- a/t/t2020-checkout-detach.sh\n> +++ b/t/t2020-checkout-detach.sh\n> @@ -176,7 +176,10 @@ test_expect_success 'tracking count is accurate after orphan check' '\n>         git config branch.child.merge refs/heads/main &&\n>         git checkout child^ &&\n>         git checkout child >stdout &&\n> -       test_cmp expect stdout\n> +       test_cmp expect stdout &&\n> +\n> +       git checkout --detach child >stdout &&\n> +       test_grep ! \"can be fast-forwarded\\.\" stdout\n>  '\n>\n>  test_expect_success 'no advice given for explicit detached head state' '\n> --\n> 2.44.0-413-gd6fd04375f\n>\n>\n>\n\nThanks Junio for the fix. It works for me.\n\nTested-by: M Hickford <mirth.hickford@gmail.com>\n"},{"id":"492302","messageId":"xmqqzfu7viud.fsf@gitster.g","threadId":"61230","inReplyTo":"CAGJzqsmE9FDEBn=u3ge4LA3ha4fDbm4OWiuUbMaztwjELBd7ug@mail.gmail.com","subject":"Re: [PATCH] checkout: do not bother \"tracking\" report on detached HEAD","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-04-05T17:07:38Z","receivedAt":"2024-04-05T17:07:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"M Hickford <mirth.hickford@gmail.com> writes:\n\n> Thanks Junio for the fix. It works for me.\n>\n> Tested-by: M Hickford <mirth.hickford@gmail.com>\n\nThanks.  It is already on 'next' and will be on 'master' sometime\nnext week, hopefully.\n"}]}