git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Phillip Wood <phillip.wood123@gmail.com>
To: John Cai via GitGitGadget <gitgitgadget@gmail.com>, git@vger.kernel.org
Cc: John Cai <johncai86@gmail.com>, Junio C Hamano <gitster@pobox.com>
Subject: Re: [PATCH] rebase: set REF_HEAD_DETACH in checkout_up_to_date()
Date: Fri, 11 Mar 2022 15:05:27 +0000	[thread overview]
Message-ID: <7c1c0b8e-7895-7a0e-6ab0-e45e21ec7329@gmail.com> (raw)
In-Reply-To: <pull.1226.git.git.1646975144178.gitgitgadget@gmail.com>

Hi John

Thanks for working on this

On 11/03/2022 05:05, John Cai via GitGitGadget wrote:
> From: John Cai <johncai86@gmail.com>
> 
> Fixes a bug whereby rebase updates the deferenced reference HEAD points
> to instead of HEAD directly.
> 
> If HEAD is on main and if the following is a fast-forward operation,
> 
> git rebase $(git rev-parse main) $(git rev-parse topic)
> 
> Instead of HEAD being set to $(git rev-parse topic), rebase erroneously
> dereferences HEAD and sets main to $(git rev-parse topic). This bug was
> reported by Michael McClimon. See [1].

Often we just add a Reported-by: trailer unless the liked email has some 
useful extra info (which arguably should not be the case with a well 
written commit message)

> This is happening because on a fast foward with an oid as a <branch>,
> update_refs() will only call update_ref() with REF_NO_DEREF if
> RESET_HEAD_DETACH is set. This change was made in 176f5d96 (built-in rebase
> --autostash: leave the current branch alone if possible,
> 2018-11-07). In rebase, we are not setting the RESET_HEAD_DETACH flag,
> which means that the update_ref() call ends up dereferencing
> HEAD and updating it to the oid used as <branch>.
> 
> The correct behavior is that git rebase should update HEAD to $(git
> rev-parse topic) without dereferencing it.
> 
> Fix this bug by adding the RESET_HEAD_DETACH flag in checkout_up_to_date

As Junio points out it is confusing that it is always ok to pass that 
flag, I think we should only set it if we are not checking out a branch, 
see below.

> so that once reset_head() calls update_refs(), it calls update_ref() with
> REF_NO_DEREF which updates HEAD directly intead of deferencing it and
> updating the branch that HEAD points to.
> 
> Also add a test to ensure this behavior.
> 
> 1. https://lore.kernel.org/git/xmqqsfrpbepd.fsf@gitster.g/

Maybe
Reported-by: Michael McClimon <michael@mcclimon.org>
?

> Signed-off-by: John Cai <johncai86@gmail.com>
> ---
>      rebase: update HEAD when is an oid
>      
>      Fixes a bug [1] reported by Michael McClimon where rebase with oids will
>      erroneously update the branch HEAD points to.
>      
>       1. https://lore.kernel.org/git/xmqqsfrpbepd.fsf@gitster.g/
> 
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1226%2Fjohn-cai%2Fjc%2Ffix-rebase-oids-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1226/john-cai/jc/fix-rebase-oids-v1
> Pull-Request: https://github.com/git/git/pull/1226
> 
>   builtin/rebase.c  |  2 +-
>   t/t3400-rebase.sh | 21 +++++++++++++++++++++
>   2 files changed, 22 insertions(+), 1 deletion(-)
> 
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index b29ad2b65e7..52afeffcc2e 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -828,7 +828,7 @@ static int checkout_up_to_date(struct rebase_options *options)
>   		    options->switch_to);
>   	ropts.oid = &options->orig_head;
>   	ropts.branch = options->head_name;
> -	ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
> +	ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK | RESET_HEAD_DETACH;

I think it would be clearer if the post image ended up as

	ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK
	if (options->head_name)
		ropts.branch = option->head_name
	else
		ropts.flags |= RESET_HEAD_DETACH

and we changed reset_head() to BUG() if both branch and 
RESET_HEAD_DETACH are given.

>   	ropts.head_msg = buf.buf;
>   	if (reset_head(the_repository, &ropts) < 0)
>   		ret = error(_("could not switch to %s"), options->switch_to);
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 71b1735e1dd..0b92e78976c 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -437,4 +437,25 @@ test_expect_success 'rebase when inside worktree subdirectory' '
>   	)
>   '
>   
> +test_expect_success 'rebase with oids' '
> +	git init main-wt &&
> +	(
> +		cd main-wt &&
> +		>file &&
> +		git add file &&
> +		git commit -m initial &&
> +		git checkout -b side &&
> +		echo >>file &&
> +		git commit -a -m side &&
> +		git checkout main &&
> +		git tag hold &&
> +		git checkout -B main hold &&
> +		git rev-parse main >pre &&
> +		git rebase $(git rev-parse main) $(git rev-parse side) &&
> +		git rev-parse main >post &&
> +		test "$(git rev-parse side)" = "$(cat .git/HEAD)" &&
> +		test_cmp pre post
> +	)
> +'

Using a stand alone test for bisecting makes sense but I think we should 
try and use the existing test setup for the regression test (it 
certainly does not need to run in its own worktree). The diff below 
shows how this could be done. Ideally there would be a preparatory 
commit that modernized the whole of the setup test rather than just the 
two commits we're using in the new test but that's not essential.

Best Wishes

Phillip

---- >8 ----
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 71b1735e1d..d5a8ee39fc 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -18,10 +18,7 @@ GIT_AUTHOR_EMAIL=bogus@email@address
  export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL

  test_expect_success 'prepare repository with topic branches' '
-       git config core.logAllRefUpdates true &&
-       echo First >A &&
-       git update-index --add A &&
-       git commit -m "Add A." &&
+       test_commit "Add A." A First First &&
         git checkout -b force-3way &&
         echo Dummy >Y &&
         git update-index --add Y &&
@@ -32,9 +29,7 @@ test_expect_success 'prepare repository with topic 
branches' '
         git mv A D/A &&
         git commit -m "Move A." &&
         git checkout -b my-topic-branch main &&
-       echo Second >B &&
-       git update-index --add B &&
-       git commit -m "Add B." &&
+       test_commit "Add B." B Second Second &&
         git checkout -f main &&
         echo Third >>A &&
         git update-index A &&
@@ -399,6 +394,15 @@ test_expect_success 'switch to branch not checked 
out' '
         git rebase main other
  '

+test_expect_success 'switch to non-branch detaches HEAD' '
+       git checkout main &&
+       old_main=$(git rev-parse HEAD) &&
+       git rebase First Second^0 &&
+       test_cmp_rev HEAD Second &&
+       test_cmp_rev main $old_main &&
+       test_must_fail git symbolic-ref HEAD
+'
+
  test_expect_success 'refuse to switch to branch checked out elsewhere' '
         git checkout main &&
         git worktree add wt &&


  parent reply	other threads:[~2022-03-11 15:05 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-11  5:05 [PATCH] rebase: set REF_HEAD_DETACH in checkout_up_to_date() John Cai via GitGitGadget
2022-03-11  5:33 ` Junio C Hamano
2022-03-11  5:55 ` Junio C Hamano
2022-03-11 14:14   ` John Cai
2022-03-11 15:05 ` Phillip Wood [this message]
2022-03-11 15:28   ` John Cai
2022-03-11 19:42   ` John Cai
2022-03-11 21:31     ` Phillip Wood
2022-03-11 17:24 ` [PATCH v2 0/2] rebase: update HEAD when is an oid John Cai via GitGitGadget
2022-03-11 17:24   ` [PATCH v2 1/2] rebase: use test_commit helper in setup John Cai via GitGitGadget
2022-03-13  7:50     ` Junio C Hamano
2022-03-14 10:52       ` Phillip Wood
2022-03-14 21:47         ` Junio C Hamano
2022-03-11 17:24   ` [PATCH v2 2/2] rebase: set REF_HEAD_DETACH in checkout_up_to_date() John Cai via GitGitGadget
2022-03-13  7:58     ` Junio C Hamano
2022-03-14 10:54       ` Phillip Wood
2022-03-14 14:05         ` Phillip Wood
2022-03-14 14:11       ` John Cai
2022-03-14 14:25         ` Phillip Wood
2022-03-17  3:16   ` [PATCH v3 0/2] rebase: update HEAD when is an oid John Cai via GitGitGadget
2022-03-17  3:16     ` [PATCH v3 1/2] rebase: use test_commit helper in setup John Cai via GitGitGadget
2022-03-17 13:37       ` Ævar Arnfjörð Bjarmason
2022-03-17  3:16     ` [PATCH v3 2/2] rebase: set REF_HEAD_DETACH in checkout_up_to_date() John Cai via GitGitGadget
2022-03-17 13:42       ` Ævar Arnfjörð Bjarmason
2022-03-17 15:34         ` Junio C Hamano
2022-03-17 19:53     ` [PATCH v4 0/3] rebase: update HEAD when is an oid John Cai via GitGitGadget
2022-03-17 19:53       ` [PATCH v4 1/3] rebase: test showing bug in rebase with non-branch John Cai via GitGitGadget
2022-03-17 21:10         ` Junio C Hamano
2022-03-17 21:37           ` Junio C Hamano
2022-03-17 22:44           ` John Cai
2022-03-17 19:53       ` [PATCH v4 2/3] rebase: use test_commit helper in setup John Cai via GitGitGadget
2022-03-18 11:14         ` Phillip Wood
2022-03-18 13:06           ` John Cai
2022-03-17 19:53       ` [PATCH v4 3/3] rebase: set REF_HEAD_DETACH in checkout_up_to_date() John Cai via GitGitGadget
2022-03-17 21:36         ` Junio C Hamano
2022-03-18  0:30           ` John Cai
2022-03-18 13:54       ` [PATCH v5 0/2] rebase: update HEAD when is an oid John Cai via GitGitGadget
2022-03-18 13:54         ` [PATCH v5 1/2] rebase: use test_commit helper in setup John Cai via GitGitGadget
2022-03-18 16:51           ` Junio C Hamano
2022-03-18 13:54         ` [PATCH v5 2/2] rebase: set REF_HEAD_DETACH in checkout_up_to_date() John Cai via GitGitGadget
2022-03-18 16:55         ` [PATCH v5 0/2] rebase: update HEAD when is an oid Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7c1c0b8e-7895-7a0e-6ab0-e45e21ec7329@gmail.com \
    --to=phillip.wood123@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=gitster@pobox.com \
    --cc=johncai86@gmail.com \
    --cc=phillip.wood@dunelm.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).