threads / patch / 53117

patchpull: avoid running both merge and rebase

Subject: [PATCH] pull: avoid running both merge and rebase

## tl;dr

7 messages between Mar 27, 2020 and Apr 4, 2020. Diffs are folded; open one to read it.

replies: 6people: 5as markdown or json

Elijah Newren via GitGitGadget· Mar 27, 2020, 21:51 UTC · lore
From: Elijah Newren <newren@gmail.com>

When opt_rebase is true, we still first check if we can fast-forward. If the branch is fast-forwardable, then we can avoid the rebase and just use merge to do the fast-forward logic. However, when commit a6d7eb2c7a ("pull: optionally rebase submodules (remote submodule changes only)", 2017-06-23) added the ability to rebase submodules it accidentally caused us to run BOTH a merge and a rebase. Add a flag to avoid doing both.

This was found when a user had both pull.rebase and rebase.autosquash set to true. In such a case, the running of both merge and rebase would cause ORIG_HEAD to be updated twice (and match HEAD at the end instead of the commit before the rebase started), against expectation.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
    pull: avoid running both merge and rebase
    
    Cc: Norbert Kiesel nkiesel@gmail.com [nkiesel@gmail.com], Jeff King 
    peff@peff.net [peff@peff.net]
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-739%2Fnewren%2Favoid-merge-and-rebase-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-739/newren/avoid-merge-and-rebase-v1
Pull-Request: https://github.com/git/git/pull/739
 builtin/pull.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
Show changes to builtin/pull.c +4 −1
diff --git a/builtin/pull.c b/builtin/pull.c
index 3e624d1e008..19899b45c1d 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -976,6 +976,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 	if (opt_rebase) {
 		int ret = 0;
+		int ran_ff = 0;
 		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
 		     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
 		    submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head))
@@ -992,10 +993,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			if (is_descendant_of(merge_head, list)) {
 				/* we can fast-forward this without invoking rebase */
 				opt_ff = "--ff-only";
+				ran_ff = 1;
 				ret = run_merge();
 			}
 		}
-		ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
+		if (!ran_ff)
+			ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
 
 		if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
 			     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))

base-commit: 274b9cc25322d9ee79aa8e6d4e86f0ffe5ced925
-- 
gitgitgadget
Junio C Hamano· Mar 27, 2020, 22:54 UTC · re: Elijah Newren via GitGitGadget · lore

Re: [PATCH] pull: avoid running both merge and rebase

"Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 9 quoted lines
> From: Elijah Newren <newren@gmail.com>
>
> When opt_rebase is true, we still first check if we can fast-forward.
> If the branch is fast-forwardable, then we can avoid the rebase and just
> use merge to do the fast-forward logic.  However, when commit a6d7eb2c7a
> ("pull: optionally rebase submodules (remote submodule changes only)",
> 2017-06-23) added the ability to rebase submodules it accidentally
> caused us to run BOTH a merge and a rebase.  Add a flag to avoid doing
> both.
This is a fun one.  Thanks for digging to the bottom of the issue.
Show 28 quoted lines
> diff --git a/builtin/pull.c b/builtin/pull.c
> index 3e624d1e008..19899b45c1d 100644
> --- a/builtin/pull.c
> +++ b/builtin/pull.c
> @@ -976,6 +976,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
>  
>  	if (opt_rebase) {
>  		int ret = 0;
> +		int ran_ff = 0;
>  		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
>  		     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
>  		    submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head))
> @@ -992,10 +993,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
>  			if (is_descendant_of(merge_head, list)) {
>  				/* we can fast-forward this without invoking rebase */
>  				opt_ff = "--ff-only";
> +				ran_ff = 1;
>  				ret = run_merge();
>  			}
>  		}
> -		ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
> +		if (!ran_ff)
> +			ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
>  
>  		if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
>  			     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
>
> base-commit: 274b9cc25322d9ee79aa8e6d4e86f0ffe5ced925
Jeff King· Mar 28, 2020, 15:56 UTC · re: Elijah Newren via GitGitGadget · lore

Re: [PATCH] pull: avoid running both merge and rebase

On Fri, Mar 27, 2020 at 09:51:40PM +0000, Elijah Newren via GitGitGadget wrote:
Show 19 quoted lines
> When opt_rebase is true, we still first check if we can fast-forward.
> If the branch is fast-forwardable, then we can avoid the rebase and just
> use merge to do the fast-forward logic.  However, when commit a6d7eb2c7a
> ("pull: optionally rebase submodules (remote submodule changes only)",
> 2017-06-23) added the ability to rebase submodules it accidentally
> caused us to run BOTH a merge and a rebase.  Add a flag to avoid doing
> both.
> 
> This was found when a user had both pull.rebase and rebase.autosquash
> set to true.  In such a case, the running of both merge and rebase would
> cause ORIG_HEAD to be updated twice (and match HEAD at the end instead
> of the commit before the rebase started), against expectation.
> 
> Signed-off-by: Elijah Newren <newren@gmail.com>
> ---
>     pull: avoid running both merge and rebase
>     
>     Cc: Norbert Kiesel nkiesel@gmail.com [nkiesel@gmail.com], Jeff King 
>     peff@peff.net [peff@peff.net]

I'm not sure how cc is supposed to work with GGG, but it clearly didn't here. :)

Anyway, the patch looks good. Thanks for following through on this.
Show 11 quoted lines
> @@ -992,10 +993,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
>  			if (is_descendant_of(merge_head, list)) {
>  				/* we can fast-forward this without invoking rebase */
>  				opt_ff = "--ff-only";
> +				ran_ff = 1;
>  				ret = run_merge();
>  			}
>  		}
> -		ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
> +		if (!ran_ff)
> +			ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);

It feels like there should be some arrangement of the conditionals that doesn't require setting an extra flag, but I actually don't think there is. And anyway, doing the most obvious and minimal fix here is the right place to start. We don't need more regressions. ;)

-Peff
Derrick Stolee· Mar 28, 2020, 16:55 UTC · re: Jeff King · lore

Re: [PATCH] pull: avoid running both merge and rebase

On 3/28/2020 11:56 AM, Jeff King wrote:
Show 24 quoted lines
> On Fri, Mar 27, 2020 at 09:51:40PM +0000, Elijah Newren via GitGitGadget wrote:
> 
>> When opt_rebase is true, we still first check if we can fast-forward.
>> If the branch is fast-forwardable, then we can avoid the rebase and just
>> use merge to do the fast-forward logic.  However, when commit a6d7eb2c7a
>> ("pull: optionally rebase submodules (remote submodule changes only)",
>> 2017-06-23) added the ability to rebase submodules it accidentally
>> caused us to run BOTH a merge and a rebase.  Add a flag to avoid doing
>> both.
>>
>> This was found when a user had both pull.rebase and rebase.autosquash
>> set to true.  In such a case, the running of both merge and rebase would
>> cause ORIG_HEAD to be updated twice (and match HEAD at the end instead
>> of the commit before the rebase started), against expectation.
>>
>> Signed-off-by: Elijah Newren <newren@gmail.com>
>> ---
>>     pull: avoid running both merge and rebase
>>     
>>     Cc: Norbert Kiesel nkiesel@gmail.com [nkiesel@gmail.com], Jeff King 
>>     peff@peff.net [peff@peff.net]
> 
> I'm not sure how cc is supposed to work with GGG, but it clearly didn't
> here. :)
Angle brackets would work instead of square brackets:
	Cc: Norbert Keisel <nkiesel@gmail.com>

for example. Personally, I drop the names and only use email addresses so I don't make this same mistake.

-Stolee
Elijah Newren· Mar 28, 2020, 17:17 UTC · re: Derrick Stolee · lore

Re: [PATCH] pull: avoid running both merge and rebase

On Sat, Mar 28, 2020 at 9:55 AM Derrick Stolee <stolee@gmail.com> wrote:
Show 33 quoted lines
>
> On 3/28/2020 11:56 AM, Jeff King wrote:
> > On Fri, Mar 27, 2020 at 09:51:40PM +0000, Elijah Newren via GitGitGadget wrote:
> >
> >> When opt_rebase is true, we still first check if we can fast-forward.
> >> If the branch is fast-forwardable, then we can avoid the rebase and just
> >> use merge to do the fast-forward logic.  However, when commit a6d7eb2c7a
> >> ("pull: optionally rebase submodules (remote submodule changes only)",
> >> 2017-06-23) added the ability to rebase submodules it accidentally
> >> caused us to run BOTH a merge and a rebase.  Add a flag to avoid doing
> >> both.
> >>
> >> This was found when a user had both pull.rebase and rebase.autosquash
> >> set to true.  In such a case, the running of both merge and rebase would
> >> cause ORIG_HEAD to be updated twice (and match HEAD at the end instead
> >> of the commit before the rebase started), against expectation.
> >>
> >> Signed-off-by: Elijah Newren <newren@gmail.com>
> >> ---
> >>     pull: avoid running both merge and rebase
> >>
> >>     Cc: Norbert Kiesel nkiesel@gmail.com [nkiesel@gmail.com], Jeff King
> >>     peff@peff.net [peff@peff.net]
> >
> > I'm not sure how cc is supposed to work with GGG, but it clearly didn't
> > here. :)
>
> Angle brackets would work instead of square brackets:
>
>         Cc: Norbert Keisel <nkiesel@gmail.com>
>
> for example. Personally, I drop the names and only use email addresses
> so I don't make this same mistake.
My original did have angle brackets; it was literally the following line:
Cc: Norbert Kiesel <nkiesel@gmail.com>, Jeff King <peff@peff.net>

Not sure why it came through with duplicated email addresses with one inside of square brackets. Maybe GitHub markup does something to the angle brackets, and GGG doesn't get the original text but the markdown-interpreted clobbering thereof? Or something like that?

Elijah Newren· Mar 28, 2020, 17:18 UTC · re: Jeff King · lore

Re: [PATCH] pull: avoid running both merge and rebase

On Sat, Mar 28, 2020 at 8:56 AM Jeff King <peff@peff.net> wrote:
Show 25 quoted lines
>
> On Fri, Mar 27, 2020 at 09:51:40PM +0000, Elijah Newren via GitGitGadget wrote:
>
> > When opt_rebase is true, we still first check if we can fast-forward.
> > If the branch is fast-forwardable, then we can avoid the rebase and just
> > use merge to do the fast-forward logic.  However, when commit a6d7eb2c7a
> > ("pull: optionally rebase submodules (remote submodule changes only)",
> > 2017-06-23) added the ability to rebase submodules it accidentally
> > caused us to run BOTH a merge and a rebase.  Add a flag to avoid doing
> > both.
> >
> > This was found when a user had both pull.rebase and rebase.autosquash
> > set to true.  In such a case, the running of both merge and rebase would
> > cause ORIG_HEAD to be updated twice (and match HEAD at the end instead
> > of the commit before the rebase started), against expectation.
> >
> > Signed-off-by: Elijah Newren <newren@gmail.com>
> > ---
> >     pull: avoid running both merge and rebase
> >
> >     Cc: Norbert Kiesel nkiesel@gmail.com [nkiesel@gmail.com], Jeff King
> >     peff@peff.net [peff@peff.net]
>
> I'm not sure how cc is supposed to work with GGG, but it clearly didn't
> here. :)

Yeah, I clearly don't either. I even looked up another submission from Dscho (https://github.com/git/git/pull/728) and attempted to mimic it, but still managed to get it wrong somehow and I don't know how.

Show 18 quoted lines
> Anyway, the patch looks good. Thanks for following through on this.
>
> > @@ -992,10 +993,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
> >                       if (is_descendant_of(merge_head, list)) {
> >                               /* we can fast-forward this without invoking rebase */
> >                               opt_ff = "--ff-only";
> > +                             ran_ff = 1;
> >                               ret = run_merge();
> >                       }
> >               }
> > -             ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
> > +             if (!ran_ff)
> > +                     ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
>
> It feels like there should be some arrangement of the conditionals that
> doesn't require setting an extra flag, but I actually don't think there
> is. And anyway, doing the most obvious and minimal fix here is the right
> place to start. We don't need more regressions. ;)
Thanks for reviewing it.
Johannes Schindelin· Apr 4, 2020, 13:47 UTC · re: Elijah Newren · lore

GGG Cc: bug, was Re: [PATCH] pull: avoid running both merge and rebase

Hi Elijah,
On Sat, 28 Mar 2020, Elijah Newren wrote:
Show 31 quoted lines
> On Sat, Mar 28, 2020 at 8:56 AM Jeff King <peff@peff.net> wrote:
> >
> > On Fri, Mar 27, 2020 at 09:51:40PM +0000, Elijah Newren via GitGitGadget wrote:
> >
> > > When opt_rebase is true, we still first check if we can fast-forward.
> > > If the branch is fast-forwardable, then we can avoid the rebase and just
> > > use merge to do the fast-forward logic.  However, when commit a6d7eb2c7a
> > > ("pull: optionally rebase submodules (remote submodule changes only)",
> > > 2017-06-23) added the ability to rebase submodules it accidentally
> > > caused us to run BOTH a merge and a rebase.  Add a flag to avoid doing
> > > both.
> > >
> > > This was found when a user had both pull.rebase and rebase.autosquash
> > > set to true.  In such a case, the running of both merge and rebase would
> > > cause ORIG_HEAD to be updated twice (and match HEAD at the end instead
> > > of the commit before the rebase started), against expectation.
> > >
> > > Signed-off-by: Elijah Newren <newren@gmail.com>
> > > ---
> > >     pull: avoid running both merge and rebase
> > >
> > >     Cc: Norbert Kiesel nkiesel@gmail.com [nkiesel@gmail.com], Jeff King
> > >     peff@peff.net [peff@peff.net]
> >
> > I'm not sure how cc is supposed to work with GGG, but it clearly didn't
> > here. :)
>
> Yeah, I clearly don't either.  I even looked up another submission
> from Dscho (https://github.com/git/git/pull/728) and attempted to
> mimic it, but still managed to get it wrong somehow and I don't know
> how.

It might be a bug in the way I implemented folding the cover letter into single-patch mails. I simply might not pick up the Cc:s there.

However, I am seriously under water right now and won't be able to work on a fix for that. Would you mind opening a ticket at https://github.com/gitgitgadget/gitgitgadget/issues/new?

Thanks, Dscho

Show 22 quoted lines
>
> > Anyway, the patch looks good. Thanks for following through on this.
> >
> > > @@ -992,10 +993,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
> > >                       if (is_descendant_of(merge_head, list)) {
> > >                               /* we can fast-forward this without invoking rebase */
> > >                               opt_ff = "--ff-only";
> > > +                             ran_ff = 1;
> > >                               ret = run_merge();
> > >                       }
> > >               }
> > > -             ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
> > > +             if (!ran_ff)
> > > +                     ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
> >
> > It feels like there should be some arrangement of the conditionals that
> > doesn't require setting an extra flag, but I actually don't think there
> > is. And anyway, doing the most obvious and minimal fix here is the right
> > place to start. We don't need more regressions. ;)
>
> Thanks for reviewing it.
>

← back to recent threads