git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] rebase -x: sanity check command
@ 2019-01-28 10:26 Phillip Wood
  2019-01-28 18:23 ` Junio C Hamano
  2019-01-28 22:03 ` Johannes Schindelin
  0 siblings, 2 replies; 31+ messages in thread
From: Phillip Wood @ 2019-01-28 10:26 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Johannes Schindelin, Junio C Hamano, Phillip Wood

From: Phillip Wood <phillip.wood@dunelm.org.uk>

If the user gives an empty argument to --exec then the rebase starts to
run before erroring out with

  error: missing arguments for exec
  error: invalid line 2: exec
  You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
  Or you can abort the rebase with 'git rebase --abort'.

Instead check for empty commands before starting the rebase.

Also check that the command does not contain any newlines as the
todo-list format is unable to cope with multiline commands. Note that
this changes the behavior, before this change one could do

git rebase --exec='echo one
exec echo two'

and it would insert two exec lines in the todo list, now it will error
out.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
---
 builtin/rebase.c              | 22 ++++++++++++++++++++++
 t/t3404-rebase-interactive.sh | 19 +++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 00de70365e..b6c54b03c1 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -793,6 +793,24 @@ static void set_reflog_action(struct rebase_options *options)
 	strbuf_release(&buf);
 }
 
+static int check_exec_cmd(const char *cmd)
+{
+	int non_blank = 0;
+
+	while (*cmd) {
+		if (*cmd == '\n')
+			return error(_("exec commands cannot contain newlines"));
+		if (!isspace(*cmd))
+			non_blank = 1;
+		cmd++;
+	}
+
+	if (non_blank)
+		return 0;
+
+	return error(_("empty exec command"));
+}
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -1130,6 +1148,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	for (i = 0; i < exec.nr; i++)
+		if (check_exec_cmd(exec.items[i].string))
+			exit(1);
+
 	if (!(options.flags & REBASE_NO_QUIET))
 		argv_array_push(&options.git_am_opts, "-q");
 
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 7a440e08d8..c98f64eb2d 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -147,6 +147,25 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
 	git rebase --continue
 '
 
+test_expect_success 'rebase -x with empty command fails' '
+	test_when_finished "git rebase --abort ||:" &&
+	test_must_fail git rebase -x "" @ 2>actual &&
+	test_write_lines "error: empty exec command" >expected &&
+	test_i18ncmp expected actual &&
+	test_must_fail git rebase -x " " @ 2>actual &&
+	test_i18ncmp expected actual
+'
+
+LF='
+'
+test_expect_success 'rebase -x with newline in command fails' '
+	test_when_finished "git rebase --abort ||:" &&
+	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
+	test_write_lines "error: exec commands cannot contain newlines" \
+			 >expected &&
+	test_i18ncmp expected actual
+'
+
 test_expect_success 'rebase -i with exec of inexistent command' '
 	git checkout master &&
 	test_when_finished "git rebase --abort" &&
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase -x: sanity check command
  2019-01-28 10:26 [PATCH] rebase -x: sanity check command Phillip Wood
@ 2019-01-28 18:23 ` Junio C Hamano
  2019-01-28 21:56   ` Johannes Schindelin
  2019-01-28 22:03 ` Johannes Schindelin
  1 sibling, 1 reply; 31+ messages in thread
From: Junio C Hamano @ 2019-01-28 18:23 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Git Mailing List, Johannes Schindelin, Phillip Wood

Phillip Wood <phillip.wood@talktalk.net> writes:

> From: Phillip Wood <phillip.wood@dunelm.org.uk>
>
> If the user gives an empty argument to --exec then the rebase starts to
> run before erroring out with
>
>   error: missing arguments for exec
>   error: invalid line 2: exec
>   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
>   Or you can abort the rebase with 'git rebase --abort'.

Hmph.  I do agree that the above makes an unfortunate end-user
experience, but I would sort-of imagine that it would even be nicer
for such an empty exec to behave as if it were "exec false" but with
less severe error message, i.e. a way for the user to say "I want to
break the sequence here and get an interactive session".  We may not
even need to add the "break" insn if we go that way and there is one
less thing for users to learn.  I dunno, but I tend to prefer giving
a useful and safe behaviour to interactive users other than erroring
out, when there _is_ such a safe behaviour that is obvious from the
situation, and I feel that an empty "exec" is such a case.

> Also check that the command does not contain any newlines as the
> todo-list format is unable to cope with multiline commands. Note that
> this changes the behavior, before this change one could do
>
> git rebase --exec='echo one
> exec echo two'

It is very good to check the input, regardless of what an empty
"exec" should do.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase -x: sanity check command
  2019-01-28 18:23 ` Junio C Hamano
@ 2019-01-28 21:56   ` Johannes Schindelin
  2019-01-29 11:40     ` Phillip Wood
  0 siblings, 1 reply; 31+ messages in thread
From: Johannes Schindelin @ 2019-01-28 21:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Phillip Wood, Git Mailing List, Phillip Wood

Hi Junio,

On Mon, 28 Jan 2019, Junio C Hamano wrote:

> Phillip Wood <phillip.wood@talktalk.net> writes:
> 
> > From: Phillip Wood <phillip.wood@dunelm.org.uk>
> >
> > If the user gives an empty argument to --exec then the rebase starts to
> > run before erroring out with
> >
> >   error: missing arguments for exec
> >   error: invalid line 2: exec
> >   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
> >   Or you can abort the rebase with 'git rebase --abort'.
> 
> Hmph.  I do agree that the above makes an unfortunate end-user
> experience, but I would sort-of imagine that it would even be nicer
> for such an empty exec to behave as if it were "exec false" but with
> less severe error message, i.e. a way for the user to say "I want to
> break the sequence here and get an interactive session".  We may not
> even need to add the "break" insn if we go that way and there is one
> less thing for users to learn.  I dunno, but I tend to prefer giving
> a useful and safe behaviour to interactive users other than erroring
> out, when there _is_ such a safe behaviour that is obvious from the
> situation, and I feel that an empty "exec" is such a case.

That would make things unnecessarily confusing. An empty command is not
`false` with a gentler error message. An empty command is a missing
command.

I am, however, concerned that special-casing an empty command will not
make things better: if the user called `git rebase --exec=fasle`, they
will *still* have to clean up their edit script.

Or just `git rebase --abort`, which I would do whether I had forgotten to
specify a command or whether I had a typo in my command.

> > Also check that the command does not contain any newlines as the
> > todo-list format is unable to cope with multiline commands. Note that
> > this changes the behavior, before this change one could do
> >
> > git rebase --exec='echo one
> > exec echo two'
> 
> It is very good to check the input, regardless of what an empty
> "exec" should do.

Should we then also check for incorrect quoting, missing commands, other
errors? I am not sure that this path leads to sanity.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase -x: sanity check command
  2019-01-28 10:26 [PATCH] rebase -x: sanity check command Phillip Wood
  2019-01-28 18:23 ` Junio C Hamano
@ 2019-01-28 22:03 ` Johannes Schindelin
  2019-01-29 11:34   ` Phillip Wood
  1 sibling, 1 reply; 31+ messages in thread
From: Johannes Schindelin @ 2019-01-28 22:03 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Git Mailing List, Junio C Hamano

Hi Phillip,

On Mon, 28 Jan 2019, Phillip Wood wrote:

> From: Phillip Wood <phillip.wood@dunelm.org.uk>
> 
> If the user gives an empty argument to --exec then the rebase starts to
> run before erroring out with
> 
>   error: missing arguments for exec
>   error: invalid line 2: exec
>   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
>   Or you can abort the rebase with 'git rebase --abort'.

And that's the same if you specify an incorrect command.

In both cases, I would probably heed the second line of the advice: git
rebase --abort.

> Instead check for empty commands before starting the rebase.
> 
> Also check that the command does not contain any newlines as the
> todo-list format is unable to cope with multiline commands. Note that
> this changes the behavior, before this change one could do
> 
> git rebase --exec='echo one
> exec echo two'
> 
> and it would insert two exec lines in the todo list, now it will error
> out.

This, however, makes a ton of sense to me.

> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 00de70365e..b6c54b03c1 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -793,6 +793,24 @@ static void set_reflog_action(struct rebase_options *options)
>  	strbuf_release(&buf);
>  }
>  
> +static int check_exec_cmd(const char *cmd)
> +{
> +	int non_blank = 0;
> +
> +	while (*cmd) {
> +		if (*cmd == '\n')
> +			return error(_("exec commands cannot contain newlines"));
> +		if (!isspace(*cmd))
> +			non_blank = 1;
> +		cmd++;
> +	}
> +
> +	if (non_blank)
> +		return 0;

We are not in a performance critical path here, so I would prefer the
readability of this code:

	if (strchr(cmd, '\n'))
		return error(...);

And if you *really* must,

	/* Does the command consist purely of whitespace? */
	if (!cmd[strspn(cmd, " \t\r\n")])
		return error(...);

But as I suggested also in a reply to Junio's answer: where would we stop
to validate the commands?

Ciao,
Dscho

> +
> +	return error(_("empty exec command"));
> +}
> +
>  int cmd_rebase(int argc, const char **argv, const char *prefix)
>  {
>  	struct rebase_options options = {
> @@ -1130,6 +1148,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  		}
>  	}
>  
> +	for (i = 0; i < exec.nr; i++)
> +		if (check_exec_cmd(exec.items[i].string))
> +			exit(1);
> +
>  	if (!(options.flags & REBASE_NO_QUIET))
>  		argv_array_push(&options.git_am_opts, "-q");
>  
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index 7a440e08d8..c98f64eb2d 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -147,6 +147,25 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>  	git rebase --continue
>  '
>  
> +test_expect_success 'rebase -x with empty command fails' '
> +	test_when_finished "git rebase --abort ||:" &&
> +	test_must_fail git rebase -x "" @ 2>actual &&
> +	test_write_lines "error: empty exec command" >expected &&
> +	test_i18ncmp expected actual &&
> +	test_must_fail git rebase -x " " @ 2>actual &&
> +	test_i18ncmp expected actual
> +'
> +
> +LF='
> +'
> +test_expect_success 'rebase -x with newline in command fails' '
> +	test_when_finished "git rebase --abort ||:" &&
> +	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
> +	test_write_lines "error: exec commands cannot contain newlines" \
> +			 >expected &&
> +	test_i18ncmp expected actual
> +'
> +
>  test_expect_success 'rebase -i with exec of inexistent command' '
>  	git checkout master &&
>  	test_when_finished "git rebase --abort" &&
> -- 
> 2.20.1
> 
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase -x: sanity check command
  2019-01-28 22:03 ` Johannes Schindelin
@ 2019-01-29 11:34   ` Phillip Wood
  2019-01-29 15:32     ` Johannes Schindelin
  0 siblings, 1 reply; 31+ messages in thread
From: Phillip Wood @ 2019-01-29 11:34 UTC (permalink / raw)
  To: Johannes Schindelin, Phillip Wood; +Cc: Git Mailing List, Junio C Hamano

Hi Dscho

On 28/01/2019 22:03, Johannes Schindelin wrote:
> Hi Phillip,
> 
> On Mon, 28 Jan 2019, Phillip Wood wrote:
> 
>> From: Phillip Wood <phillip.wood@dunelm.org.uk>
>>
>> If the user gives an empty argument to --exec then the rebase starts to
>> run before erroring out with
>>
>>   error: missing arguments for exec
>>   error: invalid line 2: exec
>>   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
>>   Or you can abort the rebase with 'git rebase --abort'.
> 
> And that's the same if you specify an incorrect command.

Not quite, the issue is that the todo list is invalid, not that the
command fails - it never gets that far. Those errors are coming from
parse_insn_line() and parse_insn_buffer().

> 
> In both cases, I would probably heed the second line of the advice: git
> rebase --abort.
> 
>> Instead check for empty commands before starting the rebase.
>>
>> Also check that the command does not contain any newlines as the
>> todo-list format is unable to cope with multiline commands. Note that
>> this changes the behavior, before this change one could do
>>
>> git rebase --exec='echo one
>> exec echo two'
>>
>> and it would insert two exec lines in the todo list, now it will error
>> out.
> 
> This, however, makes a ton of sense to me.
> 
>> diff --git a/builtin/rebase.c b/builtin/rebase.c
>> index 00de70365e..b6c54b03c1 100644
>> --- a/builtin/rebase.c
>> +++ b/builtin/rebase.c
>> @@ -793,6 +793,24 @@ static void set_reflog_action(struct rebase_options *options)
>>  	strbuf_release(&buf);
>>  }
>>  
>> +static int check_exec_cmd(const char *cmd)
>> +{
>> +	int non_blank = 0;
>> +
>> +	while (*cmd) {
>> +		if (*cmd == '\n')
>> +			return error(_("exec commands cannot contain newlines"));
>> +		if (!isspace(*cmd))
>> +			non_blank = 1;
>> +		cmd++;
>> +	}
>> +
>> +	if (non_blank)
>> +		return 0;
> 
> We are not in a performance critical path here, so I would prefer the
> readability of this code:
> 
> 	if (strchr(cmd, '\n'))
> 		return error(...);
> 
> And if you *really* must,
> 
> 	/* Does the command consist purely of whitespace? */
> 	if (!cmd[strspn(cmd, " \t\r\n")])
> 		return error(...);
> 
> But as I suggested also in a reply to Junio's answer: where would we stop
> to validate the commands?

I'm not trying to validate the command (and I don't think we can/should)
- just generate a todo list that can be parsed.

Best Wishes

Phillip

> 
> Ciao,
> Dscho
> 
>> +
>> +	return error(_("empty exec command"));
>> +}
>> +
>>  int cmd_rebase(int argc, const char **argv, const char *prefix)
>>  {
>>  	struct rebase_options options = {
>> @@ -1130,6 +1148,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>>  		}
>>  	}
>>  
>> +	for (i = 0; i < exec.nr; i++)
>> +		if (check_exec_cmd(exec.items[i].string))
>> +			exit(1);
>> +
>>  	if (!(options.flags & REBASE_NO_QUIET))
>>  		argv_array_push(&options.git_am_opts, "-q");
>>  
>> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
>> index 7a440e08d8..c98f64eb2d 100755
>> --- a/t/t3404-rebase-interactive.sh
>> +++ b/t/t3404-rebase-interactive.sh
>> @@ -147,6 +147,25 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>>  	git rebase --continue
>>  '
>>  
>> +test_expect_success 'rebase -x with empty command fails' '
>> +	test_when_finished "git rebase --abort ||:" &&
>> +	test_must_fail git rebase -x "" @ 2>actual &&
>> +	test_write_lines "error: empty exec command" >expected &&
>> +	test_i18ncmp expected actual &&
>> +	test_must_fail git rebase -x " " @ 2>actual &&
>> +	test_i18ncmp expected actual
>> +'
>> +
>> +LF='
>> +'
>> +test_expect_success 'rebase -x with newline in command fails' '
>> +	test_when_finished "git rebase --abort ||:" &&
>> +	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
>> +	test_write_lines "error: exec commands cannot contain newlines" \
>> +			 >expected &&
>> +	test_i18ncmp expected actual
>> +'
>> +
>>  test_expect_success 'rebase -i with exec of inexistent command' '
>>  	git checkout master &&
>>  	test_when_finished "git rebase --abort" &&
>> -- 
>> 2.20.1
>>
>>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase -x: sanity check command
  2019-01-28 21:56   ` Johannes Schindelin
@ 2019-01-29 11:40     ` Phillip Wood
  2019-01-29 15:35       ` Johannes Schindelin
  0 siblings, 1 reply; 31+ messages in thread
From: Phillip Wood @ 2019-01-29 11:40 UTC (permalink / raw)
  To: Johannes Schindelin, Junio C Hamano; +Cc: Git Mailing List, Phillip Wood

Dear Junio & Dscho

On 28/01/2019 21:56, Johannes Schindelin wrote:
> Hi Junio,
> 
> On Mon, 28 Jan 2019, Junio C Hamano wrote:
> 
>> Phillip Wood <phillip.wood@talktalk.net> writes:
>>
>>> From: Phillip Wood <phillip.wood@dunelm.org.uk>
>>>
>>> If the user gives an empty argument to --exec then the rebase starts to
>>> run before erroring out with
>>>
>>>   error: missing arguments for exec
>>>   error: invalid line 2: exec
>>>   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
>>>   Or you can abort the rebase with 'git rebase --abort'.
>>
>> Hmph.  I do agree that the above makes an unfortunate end-user
>> experience, but I would sort-of imagine that it would even be nicer
>> for such an empty exec to behave as if it were "exec false" but with
>> less severe error message, i.e. a way for the user to say "I want to
>> break the sequence here and get an interactive session".  We may not
>> even need to add the "break" insn if we go that way and there is one
>> less thing for users to learn.  I dunno, but I tend to prefer giving
>> a useful and safe behaviour to interactive users other than erroring
>> out, when there _is_ such a safe behaviour that is obvious from the
>> situation, and I feel that an empty "exec" is such a case.
> 
> That would make things unnecessarily confusing. An empty command is not
> `false` with a gentler error message. An empty command is a missing
> command.

I agree that having a special meaning to the empty command would be
confusing. Also giving it on the command line only helps if you want to
stop after each pick and my impression is that people want to break
after specific commits to amend a fixup or something like that.

> I am, however, concerned that special-casing an empty command will not
> make things better: if the user called `git rebase --exec=fasle`, they
> will *still* have to clean up their edit script.

The empty commands create an invalid todo list which git cannot parse,
this patch is not a step down the path of checking that the command
exists or is valid shell - I don't think that would be possible in the
general case.

Best Wishes

Phillip

> Or just `git rebase --abort`, which I would do whether I had forgotten to
> specify a command or whether I had a typo in my command.
> 
>>> Also check that the command does not contain any newlines as the
>>> todo-list format is unable to cope with multiline commands. Note that
>>> this changes the behavior, before this change one could do
>>>
>>> git rebase --exec='echo one
>>> exec echo two'
>>
>> It is very good to check the input, regardless of what an empty
>> "exec" should do.
> 
> Should we then also check for incorrect quoting, missing commands, other
> errors? I am not sure that this path leads to sanity.
> 
> Ciao,
> Dscho
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase -x: sanity check command
  2019-01-29 11:34   ` Phillip Wood
@ 2019-01-29 15:32     ` Johannes Schindelin
  2019-01-29 18:43       ` [PATCH v2] " Phillip Wood
  0 siblings, 1 reply; 31+ messages in thread
From: Johannes Schindelin @ 2019-01-29 15:32 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Git Mailing List, Junio C Hamano

Hi Phillip,

[sorry for the double-send, I dropped the Cc: list by mistake the first
time I replied]

On Tue, 29 Jan 2019, Phillip Wood wrote:

> On 28/01/2019 22:03, Johannes Schindelin wrote:
> > Hi Phillip,
> > 
> > On Mon, 28 Jan 2019, Phillip Wood wrote:
> > 
> >> From: Phillip Wood <phillip.wood@dunelm.org.uk>
> >>
> >> If the user gives an empty argument to --exec then the rebase starts to
> >> run before erroring out with
> >>
> >>   error: missing arguments for exec
> >>   error: invalid line 2: exec
> >>   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
> >>   Or you can abort the rebase with 'git rebase --abort'.
> > 
> > And that's the same if you specify an incorrect command.
> 
> Not quite, the issue is that the todo list is invalid, not that the
> command fails - it never gets that far. Those errors are coming from
> parse_insn_line() and parse_insn_buffer().

Ah! I misunderstood "then the rebase starts to run" part.

So please let me withdraw my objections to catch this error.

However, I still would highly recommend to use `strspn()` to simplify the
code.

Thanks,
Dscho

> > In both cases, I would probably heed the second line of the advice: git
> > rebase --abort.
> > 
> >> Instead check for empty commands before starting the rebase.
> >>
> >> Also check that the command does not contain any newlines as the
> >> todo-list format is unable to cope with multiline commands. Note that
> >> this changes the behavior, before this change one could do
> >>
> >> git rebase --exec='echo one
> >> exec echo two'
> >>
> >> and it would insert two exec lines in the todo list, now it will error
> >> out.
> > 
> > This, however, makes a ton of sense to me.
> > 
> >> diff --git a/builtin/rebase.c b/builtin/rebase.c
> >> index 00de70365e..b6c54b03c1 100644
> >> --- a/builtin/rebase.c
> >> +++ b/builtin/rebase.c
> >> @@ -793,6 +793,24 @@ static void set_reflog_action(struct rebase_options *options)
> >>  	strbuf_release(&buf);
> >>  }
> >>  
> >> +static int check_exec_cmd(const char *cmd)
> >> +{
> >> +	int non_blank = 0;
> >> +
> >> +	while (*cmd) {
> >> +		if (*cmd == '\n')
> >> +			return error(_("exec commands cannot contain newlines"));
> >> +		if (!isspace(*cmd))
> >> +			non_blank = 1;
> >> +		cmd++;
> >> +	}
> >> +
> >> +	if (non_blank)
> >> +		return 0;
> > 
> > We are not in a performance critical path here, so I would prefer the
> > readability of this code:
> > 
> > 	if (strchr(cmd, '\n'))
> > 		return error(...);
> > 
> > And if you *really* must,
> > 
> > 	/* Does the command consist purely of whitespace? */
> > 	if (!cmd[strspn(cmd, " \t\r\n")])
> > 		return error(...);
> > 
> > But as I suggested also in a reply to Junio's answer: where would we stop
> > to validate the commands?
> 
> I'm not trying to validate the command (and I don't think we can/should)
> - just generate a todo list that can be parsed.
> 
> Best Wishes
> 
> Phillip
> 
> > 
> > Ciao,
> > Dscho
> > 
> >> +
> >> +	return error(_("empty exec command"));
> >> +}
> >> +
> >>  int cmd_rebase(int argc, const char **argv, const char *prefix)
> >>  {
> >>  	struct rebase_options options = {
> >> @@ -1130,6 +1148,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> >>  		}
> >>  	}
> >>  
> >> +	for (i = 0; i < exec.nr; i++)
> >> +		if (check_exec_cmd(exec.items[i].string))
> >> +			exit(1);
> >> +
> >>  	if (!(options.flags & REBASE_NO_QUIET))
> >>  		argv_array_push(&options.git_am_opts, "-q");
> >>  
> >> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> >> index 7a440e08d8..c98f64eb2d 100755
> >> --- a/t/t3404-rebase-interactive.sh
> >> +++ b/t/t3404-rebase-interactive.sh
> >> @@ -147,6 +147,25 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
> >>  	git rebase --continue
> >>  '
> >>  
> >> +test_expect_success 'rebase -x with empty command fails' '
> >> +	test_when_finished "git rebase --abort ||:" &&
> >> +	test_must_fail git rebase -x "" @ 2>actual &&
> >> +	test_write_lines "error: empty exec command" >expected &&
> >> +	test_i18ncmp expected actual &&
> >> +	test_must_fail git rebase -x " " @ 2>actual &&
> >> +	test_i18ncmp expected actual
> >> +'
> >> +
> >> +LF='
> >> +'
> >> +test_expect_success 'rebase -x with newline in command fails' '
> >> +	test_when_finished "git rebase --abort ||:" &&
> >> +	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
> >> +	test_write_lines "error: exec commands cannot contain newlines" \
> >> +			 >expected &&
> >> +	test_i18ncmp expected actual
> >> +'
> >> +
> >>  test_expect_success 'rebase -i with exec of inexistent command' '
> >>  	git checkout master &&
> >>  	test_when_finished "git rebase --abort" &&
> >> -- 
> >> 2.20.1
> >>
> >>
> 
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase -x: sanity check command
  2019-01-29 11:40     ` Phillip Wood
@ 2019-01-29 15:35       ` Johannes Schindelin
  0 siblings, 0 replies; 31+ messages in thread
From: Johannes Schindelin @ 2019-01-29 15:35 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Junio C Hamano, Git Mailing List

Hi Phillip,

On Tue, 29 Jan 2019, Phillip Wood wrote:

> On 28/01/2019 21:56, Johannes Schindelin wrote:
> > 
> > On Mon, 28 Jan 2019, Junio C Hamano wrote:
> > 
> >> Phillip Wood <phillip.wood@talktalk.net> writes:
> >>
> >>> From: Phillip Wood <phillip.wood@dunelm.org.uk>
> >>>
> >>> If the user gives an empty argument to --exec then the rebase starts to
> >>> run before erroring out with
> >>>
> >>>   error: missing arguments for exec
> >>>   error: invalid line 2: exec
> >>>   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
> >>>   Or you can abort the rebase with 'git rebase --abort'.
> >>
> >> Hmph.  I do agree that the above makes an unfortunate end-user
> >> experience, but I would sort-of imagine that it would even be nicer
> >> for such an empty exec to behave as if it were "exec false" but with
> >> less severe error message, i.e. a way for the user to say "I want to
> >> break the sequence here and get an interactive session".  We may not
> >> even need to add the "break" insn if we go that way and there is one
> >> less thing for users to learn.  I dunno, but I tend to prefer giving
> >> a useful and safe behaviour to interactive users other than erroring
> >> out, when there _is_ such a safe behaviour that is obvious from the
> >> situation, and I feel that an empty "exec" is such a case.
> > 
> > That would make things unnecessarily confusing. An empty command is not
> > `false` with a gentler error message. An empty command is a missing
> > command.
> 
> I agree that having a special meaning to the empty command would be
> confusing. Also giving it on the command line only helps if you want to
> stop after each pick and my impression is that people want to break
> after specific commits to amend a fixup or something like that.
> 
> > I am, however, concerned that special-casing an empty command will not
> > make things better: if the user called `git rebase --exec=fasle`, they
> > will *still* have to clean up their edit script.
> 
> The empty commands create an invalid todo list which git cannot parse,
> this patch is not a step down the path of checking that the command
> exists or is valid shell - I don't think that would be possible in the
> general case.

Well, at least the error message is helpful: it suggests --edit-todo.

But as I said in another reply, I understand now that your patch validates
the argument as necessary to produce a valid todo list.

Thanks,
Dscho

> 
> Best Wishes
> 
> Phillip
> 
> > Or just `git rebase --abort`, which I would do whether I had forgotten to
> > specify a command or whether I had a typo in my command.
> > 
> >>> Also check that the command does not contain any newlines as the
> >>> todo-list format is unable to cope with multiline commands. Note that
> >>> this changes the behavior, before this change one could do
> >>>
> >>> git rebase --exec='echo one
> >>> exec echo two'
> >>
> >> It is very good to check the input, regardless of what an empty
> >> "exec" should do.
> > 
> > Should we then also check for incorrect quoting, missing commands, other
> > errors? I am not sure that this path leads to sanity.
> > 
> > Ciao,
> > Dscho
> > 
> 
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v2] rebase -x: sanity check command
  2019-01-29 15:32     ` Johannes Schindelin
@ 2019-01-29 18:43       ` Phillip Wood
  2019-01-29 21:53         ` Junio C Hamano
                           ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Phillip Wood @ 2019-01-29 18:43 UTC (permalink / raw)
  To: Git Mailing List, Johannes Schindelin, Junio C Hamano; +Cc: Phillip Wood

From: Phillip Wood <phillip.wood@dunelm.org.uk>

If the user gives an empty argument to --exec then git creates a todo
list that it cannot parse. The rebase starts to run before erroring out
with

  error: missing arguments for exec
  error: invalid line 2: exec
  You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
  Or you can abort the rebase with 'git rebase --abort'.

Instead check for empty commands before starting the rebase.

Also check that the command does not contain any newlines as the
todo-list format is unable to cope with multiline commands. Note that
this changes the behavior, before this change one could do

git rebase --exec='echo one
exec echo two'

and it would insert two exec lines in the todo list, now it will error
out.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
---

Apologies for the resend but I messed up the from address on the
previous send and I don't think it made it to the mailing list.

Thanks for the comments. I've updated the code as suggested by Dscho
and tried to make it clearer in the commit message that this is fixing
git creating a todo-list that it cannot parse.

Range-diff against v1:
1:  9626549aec ! 1:  726b84c300 rebase -x: sanity check command
    @@ -2,8 +2,9 @@
     
         rebase -x: sanity check command
     
    -    If the user gives an empty argument to --exec then the rebase starts to
    -    run before erroring out with
    +    If the user gives an empty argument to --exec then git creates a todo
    +    list that it cannot parse. The rebase starts to run before erroring out
    +    with
     
           error: missing arguments for exec
           error: invalid line 2: exec
    @@ -33,21 +34,16 @@
      
     +static int check_exec_cmd(const char *cmd)
     +{
    -+	int non_blank = 0;
    ++	if (strchr(cmd, '\n'))
    ++		return error(_("exec commands cannot contain newlines"));
     +
    -+	while (*cmd) {
    -+		if (*cmd == '\n')
    -+			return error(_("exec commands cannot contain newlines"));
    -+		if (!isspace(*cmd))
    -+			non_blank = 1;
    -+		cmd++;
    -+	}
    ++	/* Does the command consist purely of whitespace? */
    ++	if (!cmd[strspn(cmd, " \t\r\f\v")])
    ++		return error(_("empty exec command"));
     +
    -+	if (non_blank)
    -+		return 0;
    -+
    -+	return error(_("empty exec command"));
    ++	return 0;
     +}
    ++
     +
      int cmd_rebase(int argc, const char **argv, const char *prefix)
      {

 builtin/rebase.c              | 17 +++++++++++++++++
 t/t3404-rebase-interactive.sh | 19 +++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 00de70365e..f75bd79b45 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -793,6 +793,19 @@ static void set_reflog_action(struct rebase_options *options)
 	strbuf_release(&buf);
 }
 
+static int check_exec_cmd(const char *cmd)
+{
+	if (strchr(cmd, '\n'))
+		return error(_("exec commands cannot contain newlines"));
+
+	/* Does the command consist purely of whitespace? */
+	if (!cmd[strspn(cmd, " \t\r\f\v")])
+		return error(_("empty exec command"));
+
+	return 0;
+}
+
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -1130,6 +1143,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	for (i = 0; i < exec.nr; i++)
+		if (check_exec_cmd(exec.items[i].string))
+			exit(1);
+
 	if (!(options.flags & REBASE_NO_QUIET))
 		argv_array_push(&options.git_am_opts, "-q");
 
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 7a440e08d8..c98f64eb2d 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -147,6 +147,25 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
 	git rebase --continue
 '
 
+test_expect_success 'rebase -x with empty command fails' '
+	test_when_finished "git rebase --abort ||:" &&
+	test_must_fail git rebase -x "" @ 2>actual &&
+	test_write_lines "error: empty exec command" >expected &&
+	test_i18ncmp expected actual &&
+	test_must_fail git rebase -x " " @ 2>actual &&
+	test_i18ncmp expected actual
+'
+
+LF='
+'
+test_expect_success 'rebase -x with newline in command fails' '
+	test_when_finished "git rebase --abort ||:" &&
+	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
+	test_write_lines "error: exec commands cannot contain newlines" \
+			 >expected &&
+	test_i18ncmp expected actual
+'
+
 test_expect_success 'rebase -i with exec of inexistent command' '
 	git checkout master &&
 	test_when_finished "git rebase --abort" &&
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v2] rebase -x: sanity check command
  2019-01-29 18:43       ` [PATCH v2] " Phillip Wood
@ 2019-01-29 21:53         ` Junio C Hamano
  2019-01-30 12:25         ` Johannes Schindelin
  2019-02-13 13:31         ` Ævar Arnfjörð Bjarmason
  2 siblings, 0 replies; 31+ messages in thread
From: Junio C Hamano @ 2019-01-29 21:53 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Git Mailing List, Johannes Schindelin, Phillip Wood

Phillip Wood <phillip.wood@talktalk.net> writes:

> Thanks for the comments. I've updated the code as suggested by Dscho
> and tried to make it clearer in the commit message that this is fixing
> git creating a todo-list that it cannot parse.

Will queue.  Thanks.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2] rebase -x: sanity check command
  2019-01-29 18:43       ` [PATCH v2] " Phillip Wood
  2019-01-29 21:53         ` Junio C Hamano
@ 2019-01-30 12:25         ` Johannes Schindelin
  2019-02-13 13:31         ` Ævar Arnfjörð Bjarmason
  2 siblings, 0 replies; 31+ messages in thread
From: Johannes Schindelin @ 2019-01-30 12:25 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Git Mailing List, Junio C Hamano

Hi Phillip,

On Tue, 29 Jan 2019, Phillip Wood wrote:

> Range-diff against v1:
> 1:  9626549aec ! 1:  726b84c300 rebase -x: sanity check command
>     @@ -2,8 +2,9 @@
>      
>          rebase -x: sanity check command
>      
>     -    If the user gives an empty argument to --exec then the rebase starts to
>     -    run before erroring out with
>     +    If the user gives an empty argument to --exec then git creates a todo
>     +    list that it cannot parse. The rebase starts to run before erroring out
>     +    with
>      
>            error: missing arguments for exec
>            error: invalid line 2: exec
>     @@ -33,21 +34,16 @@
>       
>      +static int check_exec_cmd(const char *cmd)
>      +{
>     -+	int non_blank = 0;
>     ++	if (strchr(cmd, '\n'))
>     ++		return error(_("exec commands cannot contain newlines"));
>      +
>     -+	while (*cmd) {
>     -+		if (*cmd == '\n')
>     -+			return error(_("exec commands cannot contain newlines"));
>     -+		if (!isspace(*cmd))
>     -+			non_blank = 1;
>     -+		cmd++;
>     -+	}
>     ++	/* Does the command consist purely of whitespace? */
>     ++	if (!cmd[strspn(cmd, " \t\r\f\v")])
>     ++		return error(_("empty exec command"));
>      +
>     -+	if (non_blank)
>     -+		return 0;
>     -+
>     -+	return error(_("empty exec command"));
>     ++	return 0;
>      +}
>     ++
>      +
>       int cmd_rebase(int argc, const char **argv, const char *prefix)
>       {

Looks great!

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2] rebase -x: sanity check command
  2019-01-29 18:43       ` [PATCH v2] " Phillip Wood
  2019-01-29 21:53         ` Junio C Hamano
  2019-01-30 12:25         ` Johannes Schindelin
@ 2019-02-13 13:31         ` Ævar Arnfjörð Bjarmason
  2019-02-13 14:22           ` [PATCH] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
  2 siblings, 1 reply; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-02-13 13:31 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Git Mailing List, Johannes Schindelin, Junio C Hamano


On Tue, Jan 29 2019, Phillip Wood wrote:

> From: Phillip Wood <phillip.wood@dunelm.org.uk>
>
> If the user gives an empty argument to --exec then git creates a todo
> list that it cannot parse. The rebase starts to run before erroring out
> with
>
>   error: missing arguments for exec
>   error: invalid line 2: exec
>   You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
>   Or you can abort the rebase with 'git rebase --abort'.
>
> Instead check for empty commands before starting the rebase.
>
> Also check that the command does not contain any newlines as the
> todo-list format is unable to cope with multiline commands. Note that
> this changes the behavior, before this change one could do
>
> git rebase --exec='echo one
> exec echo two'
>
> and it would insert two exec lines in the todo list, now it will error
> out.
>
> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> ---
>
> Apologies for the resend but I messed up the from address on the
> previous send and I don't think it made it to the mailing list.
>
> Thanks for the comments. I've updated the code as suggested by Dscho
> and tried to make it clearer in the commit message that this is fixing
> git creating a todo-list that it cannot parse.
>
> Range-diff against v1:
> 1:  9626549aec ! 1:  726b84c300 rebase -x: sanity check command
>     @@ -2,8 +2,9 @@
>
>          rebase -x: sanity check command
>
>     -    If the user gives an empty argument to --exec then the rebase starts to
>     -    run before erroring out with
>     +    If the user gives an empty argument to --exec then git creates a todo
>     +    list that it cannot parse. The rebase starts to run before erroring out
>     +    with
>
>            error: missing arguments for exec
>            error: invalid line 2: exec
>     @@ -33,21 +34,16 @@
>
>      +static int check_exec_cmd(const char *cmd)
>      +{
>     -+	int non_blank = 0;
>     ++	if (strchr(cmd, '\n'))
>     ++		return error(_("exec commands cannot contain newlines"));
>      +
>     -+	while (*cmd) {
>     -+		if (*cmd == '\n')
>     -+			return error(_("exec commands cannot contain newlines"));
>     -+		if (!isspace(*cmd))
>     -+			non_blank = 1;
>     -+		cmd++;
>     -+	}
>     ++	/* Does the command consist purely of whitespace? */
>     ++	if (!cmd[strspn(cmd, " \t\r\f\v")])
>     ++		return error(_("empty exec command"));
>      +
>     -+	if (non_blank)
>     -+		return 0;
>     -+
>     -+	return error(_("empty exec command"));
>     ++	return 0;
>      +}
>     ++
>      +
>       int cmd_rebase(int argc, const char **argv, const char *prefix)
>       {
>
>  builtin/rebase.c              | 17 +++++++++++++++++
>  t/t3404-rebase-interactive.sh | 19 +++++++++++++++++++
>  2 files changed, 36 insertions(+)
>
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 00de70365e..f75bd79b45 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -793,6 +793,19 @@ static void set_reflog_action(struct rebase_options *options)
>  	strbuf_release(&buf);
>  }
>
> +static int check_exec_cmd(const char *cmd)
> +{
> +	if (strchr(cmd, '\n'))
> +		return error(_("exec commands cannot contain newlines"));
> +
> +	/* Does the command consist purely of whitespace? */
> +	if (!cmd[strspn(cmd, " \t\r\f\v")])
> +		return error(_("empty exec command"));
> +
> +	return 0;
> +}
> +
> +
>  int cmd_rebase(int argc, const char **argv, const char *prefix)
>  {
>  	struct rebase_options options = {
> @@ -1130,6 +1143,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  		}
>  	}
>
> +	for (i = 0; i < exec.nr; i++)
> +		if (check_exec_cmd(exec.items[i].string))
> +			exit(1);
> +
>  	if (!(options.flags & REBASE_NO_QUIET))
>  		argv_array_push(&options.git_am_opts, "-q");
>
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index 7a440e08d8..c98f64eb2d 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -147,6 +147,25 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>  	git rebase --continue
>  '
>
> +test_expect_success 'rebase -x with empty command fails' '
> +	test_when_finished "git rebase --abort ||:" &&
> +	test_must_fail git rebase -x "" @ 2>actual &&
> +	test_write_lines "error: empty exec command" >expected &&
> +	test_i18ncmp expected actual &&
> +	test_must_fail git rebase -x " " @ 2>actual &&
> +	test_i18ncmp expected actual
> +'
> +
> +LF='
> +'
> +test_expect_success 'rebase -x with newline in command fails' '
> +	test_when_finished "git rebase --abort ||:" &&
> +	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
> +	test_write_lines "error: exec commands cannot contain newlines" \
> +			 >expected &&
> +	test_i18ncmp expected actual
> +'
> +
>  test_expect_success 'rebase -i with exec of inexistent command' '
>  	git checkout master &&
>  	test_when_finished "git rebase --abort" &&

This patch breaks the test suite (with these two new tests) under
GIT_TEST_REBASE_USE_BUILTIN=false. So a 2.21.0-rc0 regression.

It would have been better to raise this before the rc period, but I just
noticed this now, but we can now:

 1. Skip the test under that mode
 2. Fix the shell code to do the same thing
 3. Just remove the shell code & GIT_TEST_REBASE_USE_BUILTIN=false mode

Maybe we should just do #3. The reason for the escape hatch was in case
we had bugs, and now we've had a full release cycle, but maybe that's
too early...

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH] rebase: remove the rebase.useBuiltin setting
  2019-02-13 13:31         ` Ævar Arnfjörð Bjarmason
@ 2019-02-13 14:22           ` Ævar Arnfjörð Bjarmason
  2019-02-13 16:25             ` Johannes Schindelin
                               ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-02-13 14:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Remove the rebase.useBuiltin setting, which was added as an escape
hatch to disable the builtin version of rebase first released with Git
2.20.

See [1] for the initial implementation of rebase.useBuiltin, and [2]
and [3] for the documentation and corresponding
GIT_TEST_REBASE_USE_BUILTIN option.

As noted in [4] the test suite hasn't passed with
GIT_TEST_REBASE_USE_BUILTIN=false since c762aada1a ("rebase -x: sanity
check command", 2019-01-29). We could fix this as we did for another
such bug in 7e097e27d3 ("legacy-rebase: backport -C<n> and
--whitespace=<option> checks", 2018-11-20), or just decide that the
built-in version is stable enough, and remove the legacy version. This
patch implements that removal of the legacy version.

1. 55071ea248 ("rebase: start implementing it as a builtin",
   2018-08-07)
2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
   off", 2018-11-14)
4. https://public-inbox.org/git/87ftsrke6r.fsf@evledraar.gmail.com/
---

On Wed, Feb 13 2019, Ævar Arnfjörð Bjarmason wrote:
> On Tue, Jan 29 2019, Phillip Wood wrote:
>> [...]
>>  test_expect_success 'rebase -i with exec of inexistent command' '
>>      git checkout master &&
>>      test_when_finished "git rebase --abort" &&
>
> This patch breaks the test suite (with these two new tests) under
> GIT_TEST_REBASE_USE_BUILTIN=false. So a 2.21.0-rc0 regression.
>
> It would have been better to raise this before the rc period, but I just
> noticed this now, but we can now:
>
>  1. Skip the test under that mode
>  2. Fix the shell code to do the same thing
>  3. Just remove the shell code & GIT_TEST_REBASE_USE_BUILTIN=false mode
>
> Maybe we should just do #3. The reason for the escape hatch was in case
> we had bugs, and now we've had a full release cycle, but maybe that's
> too early...

Here is approach #3, intended for 2.21, but I'll defer to Junio on
whether we should take that approach.

 Documentation/config/rebase.txt |  17 +-
 Makefile                        |   1 -
 builtin/rebase.c                |  17 +-
 git-legacy-rebase.sh            | 770 --------------------------------
 t/README                        |   4 -
 t/t3400-rebase.sh               |   6 +
 6 files changed, 13 insertions(+), 802 deletions(-)
 delete mode 100755 git-legacy-rebase.sh

diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 331d250e04..c747452983 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -1,16 +1,9 @@
 rebase.useBuiltin::
-	Set to `false` to use the legacy shellscript implementation of
-	linkgit:git-rebase[1]. Is `true` by default, which means use
-	the built-in rewrite of it in C.
-+
-The C rewrite is first included with Git version 2.20. This option
-serves an an escape hatch to re-enable the legacy version in case any
-bugs are found in the rewrite. This option and the shellscript version
-of linkgit:git-rebase[1] will be removed in some future release.
-+
-If you find some reason to set this option to `false` other than
-one-off testing you should report the behavior difference as a bug in
-git.
+	Unused configuration variable. Used between Git version 2.20
+	and 2.21 as an escape hatch to enable the legacy shellscript
+	implementation of rebase. Now the built-in rewrite of it in C
+	is always used. Setting this will emit a warning, to alert any
+	remaining users that setting this now does nothing.
 
 rebase.stat::
 	Whether to show a diffstat of what changed upstream since the last
diff --git a/Makefile b/Makefile
index 0e13a5b469..58dceccd8a 100644
--- a/Makefile
+++ b/Makefile
@@ -626,7 +626,6 @@ SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-legacy-rebase.sh
 SCRIPT_SH += git-remote-testgit.sh
 SCRIPT_SH += git-request-pull.sh
 SCRIPT_SH += git-stash.sh
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 7c7bc13e91..37a036933d 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1135,21 +1135,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	};
 	int i;
 
-	/*
-	 * NEEDSWORK: Once the builtin rebase has been tested enough
-	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
-	 * can be removed.
-	 */
-
-	if (!use_builtin_rebase()) {
-		const char *path = mkpath("%s/git-legacy-rebase",
-					  git_exec_path());
-
-		if (sane_execvp(path, (char **)argv) < 0)
-			die_errno(_("could not exec %s"), path);
-		else
-			BUG("sane_execvp() returned???");
-	}
+	if (!use_builtin_rebase())
+		warning(_("The rebase.useBuiltin support has been removed!"));
 
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_rebase_usage,
diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh
deleted file mode 100755
index 5c2c4e5276..0000000000
--- a/git-legacy-rebase.sh
+++ /dev/null
@@ -1,770 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano.
-#
-
-SUBDIRECTORY_OK=Yes
-OPTIONS_KEEPDASHDASH=
-OPTIONS_STUCKLONG=t
-OPTIONS_SPEC="\
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
-git rebase --continue | --abort | --skip | --edit-todo
---
- Available options are
-v,verbose!         display a diffstat of what changed upstream
-q,quiet!           be quiet. implies --no-stat
-autostash          automatically stash/stash pop before and after
-fork-point         use 'merge-base --fork-point' to refine upstream
-onto=!             rebase onto given branch instead of upstream
-r,rebase-merges?   try to rebase merges instead of skipping them
-p,preserve-merges! try to recreate merges instead of ignoring them
-s,strategy=!       use the given merge strategy
-X,strategy-option=! pass the argument through to the merge strategy
-no-ff!             cherry-pick all commits, even if unchanged
-f,force-rebase!    cherry-pick all commits, even if unchanged
-m,merge!           use merging strategies to rebase
-i,interactive!     let the user edit the list of commits to rebase
-x,exec=!           add exec lines after each commit of the editable list
-k,keep-empty	   preserve empty commits during rebase
-allow-empty-message allow rebasing commits with empty messages
-stat!              display a diffstat of what changed upstream
-n,no-stat!         do not show diffstat of what changed upstream
-verify             allow pre-rebase hook to run
-rerere-autoupdate  allow rerere to update index with resolved conflicts
-root!              rebase all reachable commits up to the root(s)
-autosquash         move commits that begin with squash!/fixup! under -i
-signoff            add a Signed-off-by: line to each commit
-committer-date-is-author-date! passed to 'git am'
-ignore-date!       passed to 'git am'
-whitespace=!       passed to 'git apply'
-ignore-whitespace! passed to 'git apply'
-C=!                passed to 'git apply'
-S,gpg-sign?        GPG-sign commits
- Actions:
-continue!          continue
-abort!             abort and check out the original branch
-skip!              skip current patch and continue
-edit-todo!         edit the todo list during an interactive rebase
-quit!              abort but keep HEAD where it is
-show-current-patch! show the patch file being applied or merged
-reschedule-failed-exec automatically reschedule failed exec commands
-"
-. git-sh-setup
-set_reflog_action rebase
-require_work_tree_exists
-cd_to_toplevel
-
-LF='
-'
-ok_to_skip_pre_rebase=
-
-squash_onto=
-unset onto
-unset restrict_revision
-cmd=
-strategy=
-strategy_opts=
-do_merge=
-merge_dir="$GIT_DIR"/rebase-merge
-apply_dir="$GIT_DIR"/rebase-apply
-verbose=
-diffstat=
-test "$(git config --bool rebase.stat)" = true && diffstat=t
-autostash="$(git config --bool rebase.autostash || echo false)"
-fork_point=auto
-git_am_opt=
-git_format_patch_opt=
-rebase_root=
-force_rebase=
-allow_rerere_autoupdate=
-# Non-empty if a rebase was in progress when 'git rebase' was invoked
-in_progress=
-# One of {am, merge, interactive}
-type=
-# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
-state_dir=
-# One of {'', continue, skip, abort}, as parsed from command line
-action=
-rebase_merges=
-rebase_cousins=
-preserve_merges=
-autosquash=
-keep_empty=
-allow_empty_message=--allow-empty-message
-signoff=
-reschedule_failed_exec=
-test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
-case "$(git config --bool commit.gpgsign)" in
-true)	gpg_sign_opt=-S ;;
-*)	gpg_sign_opt= ;;
-esac
-test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
-reschedule_failed_exec=--reschedule-failed-exec
-. git-rebase--common
-
-read_basic_state () {
-	test -f "$state_dir/head-name" &&
-	test -f "$state_dir/onto" &&
-	head_name=$(cat "$state_dir"/head-name) &&
-	onto=$(cat "$state_dir"/onto) &&
-	# We always write to orig-head, but interactive rebase used to write to
-	# head. Fall back to reading from head to cover for the case that the
-	# user upgraded git with an ongoing interactive rebase.
-	if test -f "$state_dir"/orig-head
-	then
-		orig_head=$(cat "$state_dir"/orig-head)
-	else
-		orig_head=$(cat "$state_dir"/head)
-	fi &&
-	test -f "$state_dir"/quiet && GIT_QUIET=t
-	test -f "$state_dir"/verbose && verbose=t
-	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
-	test -f "$state_dir"/strategy_opts &&
-		strategy_opts="$(cat "$state_dir"/strategy_opts)"
-	test -f "$state_dir"/allow_rerere_autoupdate &&
-		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
-	test -f "$state_dir"/gpg_sign_opt &&
-		gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
-	test -f "$state_dir"/signoff && {
-		signoff="$(cat "$state_dir"/signoff)"
-		force_rebase=t
-	}
-	test -f "$state_dir"/reschedule-failed-exec &&
-		reschedule_failed_exec=t
-}
-
-finish_rebase () {
-	rm -f "$(git rev-parse --git-path REBASE_HEAD)"
-	apply_autostash &&
-	{ git gc --auto || true; } &&
-	rm -rf "$state_dir"
-}
-
-run_interactive () {
-	GIT_CHERRY_PICK_HELP="$resolvemsg"
-	export GIT_CHERRY_PICK_HELP
-
-	test -n "$keep_empty" && keep_empty="--keep-empty"
-	test -n "$rebase_merges" && rebase_merges="--rebase-merges"
-	test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
-	test -n "$autosquash" && autosquash="--autosquash"
-	test -n "$verbose" && verbose="--verbose"
-	test -n "$force_rebase" && force_rebase="--no-ff"
-	test -n "$restrict_revision" && \
-		restrict_revision="--restrict-revision=^$restrict_revision"
-	test -n "$upstream" && upstream="--upstream=$upstream"
-	test -n "$onto" && onto="--onto=$onto"
-	test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
-	test -n "$onto_name" && onto_name="--onto-name=$onto_name"
-	test -n "$head_name" && head_name="--head-name=$head_name"
-	test -n "$strategy" && strategy="--strategy=$strategy"
-	test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
-	test -n "$switch_to" && switch_to="--switch-to=$switch_to"
-	test -n "$cmd" && cmd="--cmd=$cmd"
-	test -n "$action" && action="--$action"
-
-	exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
-		"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
-		"$allow_empty_message" "$autosquash" "$verbose" \
-		"$force_rebase" "$onto_name" "$head_name" "$strategy" \
-		"$strategy_opts" "$cmd" "$switch_to" \
-		"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
-		"$reschedule_failed_exec"
-}
-
-run_specific_rebase () {
-	if [ "$interactive_rebase" = implied ]; then
-		GIT_SEQUENCE_EDITOR=:
-		export GIT_SEQUENCE_EDITOR
-		autosquash=
-	fi
-
-	if test -n "$interactive_rebase" -a -z "$preserve_merges"
-	then
-		run_interactive
-	else
-		. git-rebase--$type
-
-		if test -z "$preserve_merges"
-		then
-			git_rebase__$type
-		else
-			git_rebase__preserve_merges
-		fi
-	fi
-
-	ret=$?
-	if test $ret -eq 0
-	then
-		finish_rebase
-	elif test $ret -eq 2 # special exit status for rebase -p
-	then
-		apply_autostash &&
-		rm -rf "$state_dir" &&
-		die "Nothing to do"
-	fi
-	exit $ret
-}
-
-run_pre_rebase_hook () {
-	if test -z "$ok_to_skip_pre_rebase" &&
-	   test -x "$(git rev-parse --git-path hooks/pre-rebase)"
-	then
-		"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
-		die "$(gettext "The pre-rebase hook refused to rebase.")"
-	fi
-}
-
-test -f "$apply_dir"/applying &&
-	die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
-
-if test -d "$apply_dir"
-then
-	type=am
-	state_dir="$apply_dir"
-elif test -d "$merge_dir"
-then
-	type=interactive
-	if test -d "$merge_dir"/rewritten
-	then
-		type=preserve-merges
-		interactive_rebase=explicit
-		preserve_merges=t
-	elif test -f "$merge_dir"/interactive
-	then
-		interactive_rebase=explicit
-	fi
-	state_dir="$merge_dir"
-fi
-test -n "$type" && in_progress=t
-
-total_argc=$#
-while test $# != 0
-do
-	case "$1" in
-	--no-verify)
-		ok_to_skip_pre_rebase=yes
-		;;
-	--verify)
-		ok_to_skip_pre_rebase=
-		;;
-	--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
-		test $total_argc -eq 2 || usage
-		action=${1##--}
-		;;
-	--onto=*)
-		onto="${1#--onto=}"
-		;;
-	--exec=*)
-		cmd="${cmd}exec ${1#--exec=}${LF}"
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--interactive)
-		interactive_rebase=explicit
-		;;
-	--keep-empty)
-		keep_empty=yes
-		;;
-	--allow-empty-message)
-		allow_empty_message=--allow-empty-message
-		;;
-	--no-keep-empty)
-		keep_empty=
-		;;
-	--rebase-merges)
-		rebase_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--rebase-merges=*)
-		rebase_merges=t
-		case "${1#*=}" in
-		rebase-cousins) rebase_cousins=t;;
-		no-rebase-cousins) rebase_cousins=;;
-		*) die "Unknown mode: $1";;
-		esac
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--preserve-merges)
-		preserve_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--autosquash)
-		autosquash=t
-		;;
-	--no-autosquash)
-		autosquash=
-		;;
-	--fork-point)
-		fork_point=t
-		;;
-	--no-fork-point)
-		fork_point=
-		;;
-	--merge)
-		do_merge=t
-		;;
-	--strategy-option=*)
-		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
-		do_merge=t
-		test -z "$strategy" && strategy=recursive
-		;;
-	--strategy=*)
-		strategy="${1#--strategy=}"
-		do_merge=t
-		;;
-	--no-stat)
-		diffstat=
-		;;
-	--stat)
-		diffstat=t
-		;;
-	--autostash)
-		autostash=true
-		;;
-	--no-autostash)
-		autostash=false
-		;;
-	--verbose)
-		verbose=t
-		diffstat=t
-		GIT_QUIET=
-		;;
-	--quiet)
-		GIT_QUIET=t
-		git_am_opt="$git_am_opt -q"
-		verbose=
-		diffstat=
-		;;
-	--whitespace=*)
-		git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
-		case "${1#--whitespace=}" in
-		fix|strip)
-			force_rebase=t
-			;;
-		warn|nowarn|error|error-all)
-			;; # okay, known whitespace option
-		*)
-			die "fatal: Invalid whitespace option: '${1#*=}'"
-			;;
-		esac
-		;;
-	--ignore-whitespace)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--signoff)
-		signoff=--signoff
-		;;
-	--no-signoff)
-		signoff=
-		;;
-	--committer-date-is-author-date|--ignore-date)
-		git_am_opt="$git_am_opt $1"
-		force_rebase=t
-		;;
-	-C*[!0-9]*)
-		die "fatal: switch \`C' expects a numerical value"
-		;;
-	-C*)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--root)
-		rebase_root=t
-		;;
-	--force-rebase|--no-ff)
-		force_rebase=t
-		;;
-	--rerere-autoupdate|--no-rerere-autoupdate)
-		allow_rerere_autoupdate="$1"
-		;;
-	--gpg-sign)
-		gpg_sign_opt=-S
-		;;
-	--gpg-sign=*)
-		gpg_sign_opt="-S${1#--gpg-sign=}"
-		;;
-	--reschedule-failed-exec)
-		reschedule_failed_exec=--reschedule-failed-exec
-		;;
-	--no-reschedule-failed-exec)
-		reschedule_failed_exec=
-		;;
-	--)
-		shift
-		break
-		;;
-	*)
-		usage
-		;;
-	esac
-	shift
-done
-test $# -gt 2 && usage
-
-if test -n "$action"
-then
-	test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
-	# Only interactive rebase uses detailed reflog messages
-	if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
-	then
-		GIT_REFLOG_ACTION="rebase -i ($action)"
-		export GIT_REFLOG_ACTION
-	fi
-fi
-
-if test "$action" = "edit-todo" && test -z "$interactive_rebase"
-then
-	die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
-fi
-
-case "$action" in
-continue)
-	# Sanity check
-	git rev-parse --verify HEAD >/dev/null ||
-		die "$(gettext "Cannot read HEAD")"
-	git update-index --ignore-submodules --refresh &&
-	git diff-files --quiet --ignore-submodules || {
-		echo "$(gettext "You must edit all merge conflicts and then
-mark them as resolved using git add")"
-		exit 1
-	}
-	read_basic_state
-	run_specific_rebase
-	;;
-skip)
-	output git reset --hard HEAD || exit $?
-	read_basic_state
-	run_specific_rebase
-	;;
-abort)
-	git rerere clear
-	read_basic_state
-	case "$head_name" in
-	refs/*)
-		git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
-		die "$(eval_gettext "Could not move back to \$head_name")"
-		;;
-	esac
-	output git reset --hard $orig_head
-	finish_rebase
-	exit
-	;;
-quit)
-	exec rm -rf "$state_dir"
-	;;
-edit-todo)
-	run_specific_rebase
-	;;
-show-current-patch)
-	run_specific_rebase
-	die "BUG: run_specific_rebase is not supposed to return here"
-	;;
-esac
-
-# Make sure no rebase is in progress
-if test -n "$in_progress"
-then
-	state_dir_base=${state_dir##*/}
-	cmd_live_rebase="git rebase (--continue | --abort | --skip)"
-	cmd_clear_stale_rebase="rm -fr \"$state_dir\""
-	die "
-$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
-I wonder if you are in the middle of another rebase.  If that is the
-case, please try
-	$cmd_live_rebase
-If that is not the case, please
-	$cmd_clear_stale_rebase
-and run me again.  I am stopping in case you still have something
-valuable there.')"
-fi
-
-if test -n "$rebase_root" && test -z "$onto"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-if test -n "$keep_empty"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-actually_interactive=
-if test -n "$interactive_rebase"
-then
-	if test -z "$preserve_merges"
-	then
-		type=interactive
-	else
-		type=preserve-merges
-	fi
-	actually_interactive=t
-	state_dir="$merge_dir"
-elif test -n "$do_merge"
-then
-	interactive_rebase=implied
-	type=interactive
-	state_dir="$merge_dir"
-else
-	type=am
-	state_dir="$apply_dir"
-fi
-
-if test -t 2 && test -z "$GIT_QUIET"
-then
-	git_format_patch_opt="$git_format_patch_opt --progress"
-fi
-
-incompatible_opts=$(echo " $git_am_opt " | \
-		    sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
-if test -n "$incompatible_opts"
-then
-	if test -n "$actually_interactive" || test "$do_merge"
-	then
-		die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
-	fi
-fi
-
-if test -n "$signoff"
-then
-	test -n "$preserve_merges" &&
-		die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
-	git_am_opt="$git_am_opt $signoff"
-	force_rebase=t
-fi
-
-if test -n "$preserve_merges"
-then
-	# Note: incompatibility with --signoff handled in signoff block above
-	# Note: incompatibility with --interactive is just a strong warning;
-	#       git-rebase.txt caveats with "unless you know what you are doing"
-	test -n "$rebase_merges" &&
-		die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
-
-	test -n "$reschedule_failed_exec" &&
-		die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
-fi
-
-if test -n "$rebase_merges"
-then
-	test -n "$strategy_opts" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
-	test -n "$strategy" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
-fi
-
-if test -z "$rebase_root"
-then
-	case "$#" in
-	0)
-		if ! upstream_name=$(git rev-parse --symbolic-full-name \
-			--verify -q @{upstream} 2>/dev/null)
-		then
-			. git-parse-remote
-			error_on_missing_default_upstream "rebase" "rebase" \
-				"against" "git rebase $(gettext '<branch>')"
-		fi
-
-		test "$fork_point" = auto && fork_point=t
-		;;
-	*)	upstream_name="$1"
-		if test "$upstream_name" = "-"
-		then
-			upstream_name="@{-1}"
-		fi
-		shift
-		;;
-	esac
-	upstream=$(peel_committish "${upstream_name}") ||
-	die "$(eval_gettext "invalid upstream '\$upstream_name'")"
-	upstream_arg="$upstream_name"
-else
-	if test -z "$onto"
-	then
-		empty_tree=$(git hash-object -t tree /dev/null)
-		onto=$(git commit-tree $empty_tree </dev/null)
-		squash_onto="$onto"
-	fi
-	unset upstream_name
-	unset upstream
-	test $# -gt 1 && usage
-	upstream_arg=--root
-fi
-
-# Make sure the branch to rebase onto is valid.
-onto_name=${onto-"$upstream_name"}
-case "$onto_name" in
-*...*)
-	if	left=${onto_name%...*} right=${onto_name#*...} &&
-		onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
-	then
-		case "$onto" in
-		?*"$LF"?*)
-			die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
-			;;
-		'')
-			die "$(eval_gettext "\$onto_name: there is no merge base")"
-			;;
-		esac
-	else
-		die "$(eval_gettext "\$onto_name: there is no merge base")"
-	fi
-	;;
-*)
-	onto=$(peel_committish "$onto_name") ||
-	die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
-	;;
-esac
-
-# If the branch to rebase is given, that is the branch we will rebase
-# $branch_name -- branch/commit being rebased, or HEAD (already detached)
-# $orig_head -- commit object name of tip of the branch before rebasing
-# $head_name -- refs/heads/<that-branch> or "detached HEAD"
-switch_to=
-case "$#" in
-1)
-	# Is it "rebase other $branchname" or "rebase other $commit"?
-	branch_name="$1"
-	switch_to="$1"
-
-	# Is it a local branch?
-	if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
-	   orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
-	then
-		head_name="refs/heads/$branch_name"
-	# If not is it a valid ref (branch or commit)?
-	elif orig_head=$(git rev-parse -q --verify "$branch_name")
-	then
-		head_name="detached HEAD"
-
-	else
-		die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
-	fi
-	;;
-0)
-	# Do not need to switch branches, we are already on it.
-	if branch_name=$(git symbolic-ref -q HEAD)
-	then
-		head_name=$branch_name
-		branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
-	else
-		head_name="detached HEAD"
-		branch_name=HEAD
-	fi
-	orig_head=$(git rev-parse --verify HEAD) || exit
-	;;
-*)
-	die "BUG: unexpected number of arguments left to parse"
-	;;
-esac
-
-if test "$fork_point" = t
-then
-	new_upstream=$(git merge-base --fork-point "$upstream_name" \
-			"${switch_to:-HEAD}")
-	if test -n "$new_upstream"
-	then
-		restrict_revision=$new_upstream
-	fi
-fi
-
-if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
-then
-	stash_sha1=$(git stash create "autostash") ||
-	die "$(gettext 'Cannot autostash')"
-
-	mkdir -p "$state_dir" &&
-	echo $stash_sha1 >"$state_dir/autostash" &&
-	stash_abbrev=$(git rev-parse --short $stash_sha1) &&
-	echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
-	git reset --hard
-fi
-
-require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
-
-# Now we are rebasing commits $upstream..$orig_head (or with --root,
-# everything leading up to $orig_head) on top of $onto
-
-# Check if we are already based on $onto with linear history,
-# but this should be done only when upstream and onto are the same
-# and if this is not an interactive rebase.
-mb=$(git merge-base "$onto" "$orig_head")
-if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
-	test "$mb" = "$onto" && test -z "$restrict_revision" &&
-	# linear history?
-	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
-then
-	if test -z "$force_rebase"
-	then
-		# Lazily switch to the target branch if needed...
-		test -z "$switch_to" ||
-		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
-			git checkout -q "$switch_to" --
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date.")"
-		fi
-		finish_rebase
-		exit 0
-	else
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date, rebase forced.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
-		fi
-	fi
-fi
-
-# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook "$upstream_arg" "$@"
-
-if test -n "$diffstat"
-then
-	if test -n "$verbose"
-	then
-		if test -z "$mb"
-		then
-			echo "$(eval_gettext "Changes to \$onto:")"
-		else
-			echo "$(eval_gettext "Changes from \$mb to \$onto:")"
-		fi
-	fi
-	mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
-	# We want color (if set), but no pager
-	GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
-fi
-
-if test -z "$actually_interactive" && test "$mb" = "$orig_head"
-then
-	say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
-	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-		git checkout -q "$onto^0" || die "could not detach HEAD"
-	# If the $onto is a proper descendant of the tip of the branch, then
-	# we just fast-forwarded.
-	git update-ref ORIG_HEAD $orig_head
-	move_to_original_branch
-	finish_rebase
-	exit 0
-fi
-
-test -n "$interactive_rebase" && run_specific_rebase
-
-# Detach HEAD and reset the tree
-say "$(gettext "First, rewinding head to replay your work on top of it...")"
-
-GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-	git checkout -q "$onto^0" || die "could not detach HEAD"
-git update-ref ORIG_HEAD $orig_head
-
-if test -n "$rebase_root"
-then
-	revisions="$onto..$orig_head"
-else
-	revisions="${restrict_revision-$upstream}..$orig_head"
-fi
-
-run_specific_rebase
diff --git a/t/README b/t/README
index 1326fd7505..decceb8576 100644
--- a/t/README
+++ b/t/README
@@ -374,10 +374,6 @@ the --no-sparse command-line argument.
 GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
 by overriding the minimum number of cache entries required per thread.
 
-GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the
-builtin version of git-rebase. See 'rebase.useBuiltin' in
-git-config(1).
-
 GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
 of the index for the whole test suite by bypassing the default number of
 cache entries and thread minimums. Setting this to 1 will make the
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 3e73f7584c..0a88eed1db 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -311,4 +311,10 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
 	)
 '
 
+test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN= \
+		git -c rebase.useBuiltin=false rebase 2>err &&
+	test_i18ngrep "rebase.useBuiltin support has been removed" err
+'
+
 test_done
-- 
2.20.1.611.gfbb209baf1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase: remove the rebase.useBuiltin setting
  2019-02-13 14:22           ` [PATCH] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
@ 2019-02-13 16:25             ` Johannes Schindelin
  2019-02-13 20:46             ` Junio C Hamano
  2019-03-14 13:24             ` [PATCH v2] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
  2 siblings, 0 replies; 31+ messages in thread
From: Johannes Schindelin @ 2019-02-13 16:25 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Junio C Hamano, Phillip Wood

[-- Attachment #1: Type: text/plain, Size: 29218 bytes --]

Hi Ævar,

On Wed, 13 Feb 2019, Ævar Arnfjörð Bjarmason wrote:

> Remove the rebase.useBuiltin setting, which was added as an escape
> hatch to disable the builtin version of rebase first released with Git
> 2.20.

I like it!

Thanks,
Dscho

> 
> See [1] for the initial implementation of rebase.useBuiltin, and [2]
> and [3] for the documentation and corresponding
> GIT_TEST_REBASE_USE_BUILTIN option.
> 
> As noted in [4] the test suite hasn't passed with
> GIT_TEST_REBASE_USE_BUILTIN=false since c762aada1a ("rebase -x: sanity
> check command", 2019-01-29). We could fix this as we did for another
> such bug in 7e097e27d3 ("legacy-rebase: backport -C<n> and
> --whitespace=<option> checks", 2018-11-20), or just decide that the
> built-in version is stable enough, and remove the legacy version. This
> patch implements that removal of the legacy version.
> 
> 1. 55071ea248 ("rebase: start implementing it as a builtin",
>    2018-08-07)
> 2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
> 3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
>    off", 2018-11-14)
> 4. https://public-inbox.org/git/87ftsrke6r.fsf@evledraar.gmail.com/
> ---
> 
> On Wed, Feb 13 2019, Ævar Arnfjörð Bjarmason wrote:
> > On Tue, Jan 29 2019, Phillip Wood wrote:
> >> [...]
> >>  test_expect_success 'rebase -i with exec of inexistent command' '
> >>      git checkout master &&
> >>      test_when_finished "git rebase --abort" &&
> >
> > This patch breaks the test suite (with these two new tests) under
> > GIT_TEST_REBASE_USE_BUILTIN=false. So a 2.21.0-rc0 regression.
> >
> > It would have been better to raise this before the rc period, but I just
> > noticed this now, but we can now:
> >
> >  1. Skip the test under that mode
> >  2. Fix the shell code to do the same thing
> >  3. Just remove the shell code & GIT_TEST_REBASE_USE_BUILTIN=false mode
> >
> > Maybe we should just do #3. The reason for the escape hatch was in case
> > we had bugs, and now we've had a full release cycle, but maybe that's
> > too early...
> 
> Here is approach #3, intended for 2.21, but I'll defer to Junio on
> whether we should take that approach.
> 
>  Documentation/config/rebase.txt |  17 +-
>  Makefile                        |   1 -
>  builtin/rebase.c                |  17 +-
>  git-legacy-rebase.sh            | 770 --------------------------------
>  t/README                        |   4 -
>  t/t3400-rebase.sh               |   6 +
>  6 files changed, 13 insertions(+), 802 deletions(-)
>  delete mode 100755 git-legacy-rebase.sh
> 
> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
> index 331d250e04..c747452983 100644
> --- a/Documentation/config/rebase.txt
> +++ b/Documentation/config/rebase.txt
> @@ -1,16 +1,9 @@
>  rebase.useBuiltin::
> -	Set to `false` to use the legacy shellscript implementation of
> -	linkgit:git-rebase[1]. Is `true` by default, which means use
> -	the built-in rewrite of it in C.
> -+
> -The C rewrite is first included with Git version 2.20. This option
> -serves an an escape hatch to re-enable the legacy version in case any
> -bugs are found in the rewrite. This option and the shellscript version
> -of linkgit:git-rebase[1] will be removed in some future release.
> -+
> -If you find some reason to set this option to `false` other than
> -one-off testing you should report the behavior difference as a bug in
> -git.
> +	Unused configuration variable. Used between Git version 2.20
> +	and 2.21 as an escape hatch to enable the legacy shellscript
> +	implementation of rebase. Now the built-in rewrite of it in C
> +	is always used. Setting this will emit a warning, to alert any
> +	remaining users that setting this now does nothing.
>  
>  rebase.stat::
>  	Whether to show a diffstat of what changed upstream since the last
> diff --git a/Makefile b/Makefile
> index 0e13a5b469..58dceccd8a 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -626,7 +626,6 @@ SCRIPT_SH += git-merge-one-file.sh
>  SCRIPT_SH += git-merge-resolve.sh
>  SCRIPT_SH += git-mergetool.sh
>  SCRIPT_SH += git-quiltimport.sh
> -SCRIPT_SH += git-legacy-rebase.sh
>  SCRIPT_SH += git-remote-testgit.sh
>  SCRIPT_SH += git-request-pull.sh
>  SCRIPT_SH += git-stash.sh
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 7c7bc13e91..37a036933d 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -1135,21 +1135,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  	};
>  	int i;
>  
> -	/*
> -	 * NEEDSWORK: Once the builtin rebase has been tested enough
> -	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
> -	 * can be removed.
> -	 */
> -
> -	if (!use_builtin_rebase()) {
> -		const char *path = mkpath("%s/git-legacy-rebase",
> -					  git_exec_path());
> -
> -		if (sane_execvp(path, (char **)argv) < 0)
> -			die_errno(_("could not exec %s"), path);
> -		else
> -			BUG("sane_execvp() returned???");
> -	}
> +	if (!use_builtin_rebase())
> +		warning(_("The rebase.useBuiltin support has been removed!"));
>  
>  	if (argc == 2 && !strcmp(argv[1], "-h"))
>  		usage_with_options(builtin_rebase_usage,
> diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh
> deleted file mode 100755
> index 5c2c4e5276..0000000000
> --- a/git-legacy-rebase.sh
> +++ /dev/null
> @@ -1,770 +0,0 @@
> -#!/bin/sh
> -#
> -# Copyright (c) 2005 Junio C Hamano.
> -#
> -
> -SUBDIRECTORY_OK=Yes
> -OPTIONS_KEEPDASHDASH=
> -OPTIONS_STUCKLONG=t
> -OPTIONS_SPEC="\
> -git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
> -git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
> -git rebase --continue | --abort | --skip | --edit-todo
> ---
> - Available options are
> -v,verbose!         display a diffstat of what changed upstream
> -q,quiet!           be quiet. implies --no-stat
> -autostash          automatically stash/stash pop before and after
> -fork-point         use 'merge-base --fork-point' to refine upstream
> -onto=!             rebase onto given branch instead of upstream
> -r,rebase-merges?   try to rebase merges instead of skipping them
> -p,preserve-merges! try to recreate merges instead of ignoring them
> -s,strategy=!       use the given merge strategy
> -X,strategy-option=! pass the argument through to the merge strategy
> -no-ff!             cherry-pick all commits, even if unchanged
> -f,force-rebase!    cherry-pick all commits, even if unchanged
> -m,merge!           use merging strategies to rebase
> -i,interactive!     let the user edit the list of commits to rebase
> -x,exec=!           add exec lines after each commit of the editable list
> -k,keep-empty	   preserve empty commits during rebase
> -allow-empty-message allow rebasing commits with empty messages
> -stat!              display a diffstat of what changed upstream
> -n,no-stat!         do not show diffstat of what changed upstream
> -verify             allow pre-rebase hook to run
> -rerere-autoupdate  allow rerere to update index with resolved conflicts
> -root!              rebase all reachable commits up to the root(s)
> -autosquash         move commits that begin with squash!/fixup! under -i
> -signoff            add a Signed-off-by: line to each commit
> -committer-date-is-author-date! passed to 'git am'
> -ignore-date!       passed to 'git am'
> -whitespace=!       passed to 'git apply'
> -ignore-whitespace! passed to 'git apply'
> -C=!                passed to 'git apply'
> -S,gpg-sign?        GPG-sign commits
> - Actions:
> -continue!          continue
> -abort!             abort and check out the original branch
> -skip!              skip current patch and continue
> -edit-todo!         edit the todo list during an interactive rebase
> -quit!              abort but keep HEAD where it is
> -show-current-patch! show the patch file being applied or merged
> -reschedule-failed-exec automatically reschedule failed exec commands
> -"
> -. git-sh-setup
> -set_reflog_action rebase
> -require_work_tree_exists
> -cd_to_toplevel
> -
> -LF='
> -'
> -ok_to_skip_pre_rebase=
> -
> -squash_onto=
> -unset onto
> -unset restrict_revision
> -cmd=
> -strategy=
> -strategy_opts=
> -do_merge=
> -merge_dir="$GIT_DIR"/rebase-merge
> -apply_dir="$GIT_DIR"/rebase-apply
> -verbose=
> -diffstat=
> -test "$(git config --bool rebase.stat)" = true && diffstat=t
> -autostash="$(git config --bool rebase.autostash || echo false)"
> -fork_point=auto
> -git_am_opt=
> -git_format_patch_opt=
> -rebase_root=
> -force_rebase=
> -allow_rerere_autoupdate=
> -# Non-empty if a rebase was in progress when 'git rebase' was invoked
> -in_progress=
> -# One of {am, merge, interactive}
> -type=
> -# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
> -state_dir=
> -# One of {'', continue, skip, abort}, as parsed from command line
> -action=
> -rebase_merges=
> -rebase_cousins=
> -preserve_merges=
> -autosquash=
> -keep_empty=
> -allow_empty_message=--allow-empty-message
> -signoff=
> -reschedule_failed_exec=
> -test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
> -case "$(git config --bool commit.gpgsign)" in
> -true)	gpg_sign_opt=-S ;;
> -*)	gpg_sign_opt= ;;
> -esac
> -test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
> -reschedule_failed_exec=--reschedule-failed-exec
> -. git-rebase--common
> -
> -read_basic_state () {
> -	test -f "$state_dir/head-name" &&
> -	test -f "$state_dir/onto" &&
> -	head_name=$(cat "$state_dir"/head-name) &&
> -	onto=$(cat "$state_dir"/onto) &&
> -	# We always write to orig-head, but interactive rebase used to write to
> -	# head. Fall back to reading from head to cover for the case that the
> -	# user upgraded git with an ongoing interactive rebase.
> -	if test -f "$state_dir"/orig-head
> -	then
> -		orig_head=$(cat "$state_dir"/orig-head)
> -	else
> -		orig_head=$(cat "$state_dir"/head)
> -	fi &&
> -	test -f "$state_dir"/quiet && GIT_QUIET=t
> -	test -f "$state_dir"/verbose && verbose=t
> -	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
> -	test -f "$state_dir"/strategy_opts &&
> -		strategy_opts="$(cat "$state_dir"/strategy_opts)"
> -	test -f "$state_dir"/allow_rerere_autoupdate &&
> -		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
> -	test -f "$state_dir"/gpg_sign_opt &&
> -		gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
> -	test -f "$state_dir"/signoff && {
> -		signoff="$(cat "$state_dir"/signoff)"
> -		force_rebase=t
> -	}
> -	test -f "$state_dir"/reschedule-failed-exec &&
> -		reschedule_failed_exec=t
> -}
> -
> -finish_rebase () {
> -	rm -f "$(git rev-parse --git-path REBASE_HEAD)"
> -	apply_autostash &&
> -	{ git gc --auto || true; } &&
> -	rm -rf "$state_dir"
> -}
> -
> -run_interactive () {
> -	GIT_CHERRY_PICK_HELP="$resolvemsg"
> -	export GIT_CHERRY_PICK_HELP
> -
> -	test -n "$keep_empty" && keep_empty="--keep-empty"
> -	test -n "$rebase_merges" && rebase_merges="--rebase-merges"
> -	test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
> -	test -n "$autosquash" && autosquash="--autosquash"
> -	test -n "$verbose" && verbose="--verbose"
> -	test -n "$force_rebase" && force_rebase="--no-ff"
> -	test -n "$restrict_revision" && \
> -		restrict_revision="--restrict-revision=^$restrict_revision"
> -	test -n "$upstream" && upstream="--upstream=$upstream"
> -	test -n "$onto" && onto="--onto=$onto"
> -	test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
> -	test -n "$onto_name" && onto_name="--onto-name=$onto_name"
> -	test -n "$head_name" && head_name="--head-name=$head_name"
> -	test -n "$strategy" && strategy="--strategy=$strategy"
> -	test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
> -	test -n "$switch_to" && switch_to="--switch-to=$switch_to"
> -	test -n "$cmd" && cmd="--cmd=$cmd"
> -	test -n "$action" && action="--$action"
> -
> -	exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
> -		"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
> -		"$allow_empty_message" "$autosquash" "$verbose" \
> -		"$force_rebase" "$onto_name" "$head_name" "$strategy" \
> -		"$strategy_opts" "$cmd" "$switch_to" \
> -		"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
> -		"$reschedule_failed_exec"
> -}
> -
> -run_specific_rebase () {
> -	if [ "$interactive_rebase" = implied ]; then
> -		GIT_SEQUENCE_EDITOR=:
> -		export GIT_SEQUENCE_EDITOR
> -		autosquash=
> -	fi
> -
> -	if test -n "$interactive_rebase" -a -z "$preserve_merges"
> -	then
> -		run_interactive
> -	else
> -		. git-rebase--$type
> -
> -		if test -z "$preserve_merges"
> -		then
> -			git_rebase__$type
> -		else
> -			git_rebase__preserve_merges
> -		fi
> -	fi
> -
> -	ret=$?
> -	if test $ret -eq 0
> -	then
> -		finish_rebase
> -	elif test $ret -eq 2 # special exit status for rebase -p
> -	then
> -		apply_autostash &&
> -		rm -rf "$state_dir" &&
> -		die "Nothing to do"
> -	fi
> -	exit $ret
> -}
> -
> -run_pre_rebase_hook () {
> -	if test -z "$ok_to_skip_pre_rebase" &&
> -	   test -x "$(git rev-parse --git-path hooks/pre-rebase)"
> -	then
> -		"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
> -		die "$(gettext "The pre-rebase hook refused to rebase.")"
> -	fi
> -}
> -
> -test -f "$apply_dir"/applying &&
> -	die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
> -
> -if test -d "$apply_dir"
> -then
> -	type=am
> -	state_dir="$apply_dir"
> -elif test -d "$merge_dir"
> -then
> -	type=interactive
> -	if test -d "$merge_dir"/rewritten
> -	then
> -		type=preserve-merges
> -		interactive_rebase=explicit
> -		preserve_merges=t
> -	elif test -f "$merge_dir"/interactive
> -	then
> -		interactive_rebase=explicit
> -	fi
> -	state_dir="$merge_dir"
> -fi
> -test -n "$type" && in_progress=t
> -
> -total_argc=$#
> -while test $# != 0
> -do
> -	case "$1" in
> -	--no-verify)
> -		ok_to_skip_pre_rebase=yes
> -		;;
> -	--verify)
> -		ok_to_skip_pre_rebase=
> -		;;
> -	--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
> -		test $total_argc -eq 2 || usage
> -		action=${1##--}
> -		;;
> -	--onto=*)
> -		onto="${1#--onto=}"
> -		;;
> -	--exec=*)
> -		cmd="${cmd}exec ${1#--exec=}${LF}"
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--interactive)
> -		interactive_rebase=explicit
> -		;;
> -	--keep-empty)
> -		keep_empty=yes
> -		;;
> -	--allow-empty-message)
> -		allow_empty_message=--allow-empty-message
> -		;;
> -	--no-keep-empty)
> -		keep_empty=
> -		;;
> -	--rebase-merges)
> -		rebase_merges=t
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--rebase-merges=*)
> -		rebase_merges=t
> -		case "${1#*=}" in
> -		rebase-cousins) rebase_cousins=t;;
> -		no-rebase-cousins) rebase_cousins=;;
> -		*) die "Unknown mode: $1";;
> -		esac
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--preserve-merges)
> -		preserve_merges=t
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--autosquash)
> -		autosquash=t
> -		;;
> -	--no-autosquash)
> -		autosquash=
> -		;;
> -	--fork-point)
> -		fork_point=t
> -		;;
> -	--no-fork-point)
> -		fork_point=
> -		;;
> -	--merge)
> -		do_merge=t
> -		;;
> -	--strategy-option=*)
> -		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
> -		do_merge=t
> -		test -z "$strategy" && strategy=recursive
> -		;;
> -	--strategy=*)
> -		strategy="${1#--strategy=}"
> -		do_merge=t
> -		;;
> -	--no-stat)
> -		diffstat=
> -		;;
> -	--stat)
> -		diffstat=t
> -		;;
> -	--autostash)
> -		autostash=true
> -		;;
> -	--no-autostash)
> -		autostash=false
> -		;;
> -	--verbose)
> -		verbose=t
> -		diffstat=t
> -		GIT_QUIET=
> -		;;
> -	--quiet)
> -		GIT_QUIET=t
> -		git_am_opt="$git_am_opt -q"
> -		verbose=
> -		diffstat=
> -		;;
> -	--whitespace=*)
> -		git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
> -		case "${1#--whitespace=}" in
> -		fix|strip)
> -			force_rebase=t
> -			;;
> -		warn|nowarn|error|error-all)
> -			;; # okay, known whitespace option
> -		*)
> -			die "fatal: Invalid whitespace option: '${1#*=}'"
> -			;;
> -		esac
> -		;;
> -	--ignore-whitespace)
> -		git_am_opt="$git_am_opt $1"
> -		;;
> -	--signoff)
> -		signoff=--signoff
> -		;;
> -	--no-signoff)
> -		signoff=
> -		;;
> -	--committer-date-is-author-date|--ignore-date)
> -		git_am_opt="$git_am_opt $1"
> -		force_rebase=t
> -		;;
> -	-C*[!0-9]*)
> -		die "fatal: switch \`C' expects a numerical value"
> -		;;
> -	-C*)
> -		git_am_opt="$git_am_opt $1"
> -		;;
> -	--root)
> -		rebase_root=t
> -		;;
> -	--force-rebase|--no-ff)
> -		force_rebase=t
> -		;;
> -	--rerere-autoupdate|--no-rerere-autoupdate)
> -		allow_rerere_autoupdate="$1"
> -		;;
> -	--gpg-sign)
> -		gpg_sign_opt=-S
> -		;;
> -	--gpg-sign=*)
> -		gpg_sign_opt="-S${1#--gpg-sign=}"
> -		;;
> -	--reschedule-failed-exec)
> -		reschedule_failed_exec=--reschedule-failed-exec
> -		;;
> -	--no-reschedule-failed-exec)
> -		reschedule_failed_exec=
> -		;;
> -	--)
> -		shift
> -		break
> -		;;
> -	*)
> -		usage
> -		;;
> -	esac
> -	shift
> -done
> -test $# -gt 2 && usage
> -
> -if test -n "$action"
> -then
> -	test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
> -	# Only interactive rebase uses detailed reflog messages
> -	if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
> -	then
> -		GIT_REFLOG_ACTION="rebase -i ($action)"
> -		export GIT_REFLOG_ACTION
> -	fi
> -fi
> -
> -if test "$action" = "edit-todo" && test -z "$interactive_rebase"
> -then
> -	die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
> -fi
> -
> -case "$action" in
> -continue)
> -	# Sanity check
> -	git rev-parse --verify HEAD >/dev/null ||
> -		die "$(gettext "Cannot read HEAD")"
> -	git update-index --ignore-submodules --refresh &&
> -	git diff-files --quiet --ignore-submodules || {
> -		echo "$(gettext "You must edit all merge conflicts and then
> -mark them as resolved using git add")"
> -		exit 1
> -	}
> -	read_basic_state
> -	run_specific_rebase
> -	;;
> -skip)
> -	output git reset --hard HEAD || exit $?
> -	read_basic_state
> -	run_specific_rebase
> -	;;
> -abort)
> -	git rerere clear
> -	read_basic_state
> -	case "$head_name" in
> -	refs/*)
> -		git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
> -		die "$(eval_gettext "Could not move back to \$head_name")"
> -		;;
> -	esac
> -	output git reset --hard $orig_head
> -	finish_rebase
> -	exit
> -	;;
> -quit)
> -	exec rm -rf "$state_dir"
> -	;;
> -edit-todo)
> -	run_specific_rebase
> -	;;
> -show-current-patch)
> -	run_specific_rebase
> -	die "BUG: run_specific_rebase is not supposed to return here"
> -	;;
> -esac
> -
> -# Make sure no rebase is in progress
> -if test -n "$in_progress"
> -then
> -	state_dir_base=${state_dir##*/}
> -	cmd_live_rebase="git rebase (--continue | --abort | --skip)"
> -	cmd_clear_stale_rebase="rm -fr \"$state_dir\""
> -	die "
> -$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
> -I wonder if you are in the middle of another rebase.  If that is the
> -case, please try
> -	$cmd_live_rebase
> -If that is not the case, please
> -	$cmd_clear_stale_rebase
> -and run me again.  I am stopping in case you still have something
> -valuable there.')"
> -fi
> -
> -if test -n "$rebase_root" && test -z "$onto"
> -then
> -	test -z "$interactive_rebase" && interactive_rebase=implied
> -fi
> -
> -if test -n "$keep_empty"
> -then
> -	test -z "$interactive_rebase" && interactive_rebase=implied
> -fi
> -
> -actually_interactive=
> -if test -n "$interactive_rebase"
> -then
> -	if test -z "$preserve_merges"
> -	then
> -		type=interactive
> -	else
> -		type=preserve-merges
> -	fi
> -	actually_interactive=t
> -	state_dir="$merge_dir"
> -elif test -n "$do_merge"
> -then
> -	interactive_rebase=implied
> -	type=interactive
> -	state_dir="$merge_dir"
> -else
> -	type=am
> -	state_dir="$apply_dir"
> -fi
> -
> -if test -t 2 && test -z "$GIT_QUIET"
> -then
> -	git_format_patch_opt="$git_format_patch_opt --progress"
> -fi
> -
> -incompatible_opts=$(echo " $git_am_opt " | \
> -		    sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
> -if test -n "$incompatible_opts"
> -then
> -	if test -n "$actually_interactive" || test "$do_merge"
> -	then
> -		die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
> -	fi
> -fi
> -
> -if test -n "$signoff"
> -then
> -	test -n "$preserve_merges" &&
> -		die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
> -	git_am_opt="$git_am_opt $signoff"
> -	force_rebase=t
> -fi
> -
> -if test -n "$preserve_merges"
> -then
> -	# Note: incompatibility with --signoff handled in signoff block above
> -	# Note: incompatibility with --interactive is just a strong warning;
> -	#       git-rebase.txt caveats with "unless you know what you are doing"
> -	test -n "$rebase_merges" &&
> -		die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
> -
> -	test -n "$reschedule_failed_exec" &&
> -		die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
> -fi
> -
> -if test -n "$rebase_merges"
> -then
> -	test -n "$strategy_opts" &&
> -		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
> -	test -n "$strategy" &&
> -		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
> -fi
> -
> -if test -z "$rebase_root"
> -then
> -	case "$#" in
> -	0)
> -		if ! upstream_name=$(git rev-parse --symbolic-full-name \
> -			--verify -q @{upstream} 2>/dev/null)
> -		then
> -			. git-parse-remote
> -			error_on_missing_default_upstream "rebase" "rebase" \
> -				"against" "git rebase $(gettext '<branch>')"
> -		fi
> -
> -		test "$fork_point" = auto && fork_point=t
> -		;;
> -	*)	upstream_name="$1"
> -		if test "$upstream_name" = "-"
> -		then
> -			upstream_name="@{-1}"
> -		fi
> -		shift
> -		;;
> -	esac
> -	upstream=$(peel_committish "${upstream_name}") ||
> -	die "$(eval_gettext "invalid upstream '\$upstream_name'")"
> -	upstream_arg="$upstream_name"
> -else
> -	if test -z "$onto"
> -	then
> -		empty_tree=$(git hash-object -t tree /dev/null)
> -		onto=$(git commit-tree $empty_tree </dev/null)
> -		squash_onto="$onto"
> -	fi
> -	unset upstream_name
> -	unset upstream
> -	test $# -gt 1 && usage
> -	upstream_arg=--root
> -fi
> -
> -# Make sure the branch to rebase onto is valid.
> -onto_name=${onto-"$upstream_name"}
> -case "$onto_name" in
> -*...*)
> -	if	left=${onto_name%...*} right=${onto_name#*...} &&
> -		onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
> -	then
> -		case "$onto" in
> -		?*"$LF"?*)
> -			die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
> -			;;
> -		'')
> -			die "$(eval_gettext "\$onto_name: there is no merge base")"
> -			;;
> -		esac
> -	else
> -		die "$(eval_gettext "\$onto_name: there is no merge base")"
> -	fi
> -	;;
> -*)
> -	onto=$(peel_committish "$onto_name") ||
> -	die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
> -	;;
> -esac
> -
> -# If the branch to rebase is given, that is the branch we will rebase
> -# $branch_name -- branch/commit being rebased, or HEAD (already detached)
> -# $orig_head -- commit object name of tip of the branch before rebasing
> -# $head_name -- refs/heads/<that-branch> or "detached HEAD"
> -switch_to=
> -case "$#" in
> -1)
> -	# Is it "rebase other $branchname" or "rebase other $commit"?
> -	branch_name="$1"
> -	switch_to="$1"
> -
> -	# Is it a local branch?
> -	if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
> -	   orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
> -	then
> -		head_name="refs/heads/$branch_name"
> -	# If not is it a valid ref (branch or commit)?
> -	elif orig_head=$(git rev-parse -q --verify "$branch_name")
> -	then
> -		head_name="detached HEAD"
> -
> -	else
> -		die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
> -	fi
> -	;;
> -0)
> -	# Do not need to switch branches, we are already on it.
> -	if branch_name=$(git symbolic-ref -q HEAD)
> -	then
> -		head_name=$branch_name
> -		branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
> -	else
> -		head_name="detached HEAD"
> -		branch_name=HEAD
> -	fi
> -	orig_head=$(git rev-parse --verify HEAD) || exit
> -	;;
> -*)
> -	die "BUG: unexpected number of arguments left to parse"
> -	;;
> -esac
> -
> -if test "$fork_point" = t
> -then
> -	new_upstream=$(git merge-base --fork-point "$upstream_name" \
> -			"${switch_to:-HEAD}")
> -	if test -n "$new_upstream"
> -	then
> -		restrict_revision=$new_upstream
> -	fi
> -fi
> -
> -if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
> -then
> -	stash_sha1=$(git stash create "autostash") ||
> -	die "$(gettext 'Cannot autostash')"
> -
> -	mkdir -p "$state_dir" &&
> -	echo $stash_sha1 >"$state_dir/autostash" &&
> -	stash_abbrev=$(git rev-parse --short $stash_sha1) &&
> -	echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
> -	git reset --hard
> -fi
> -
> -require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
> -
> -# Now we are rebasing commits $upstream..$orig_head (or with --root,
> -# everything leading up to $orig_head) on top of $onto
> -
> -# Check if we are already based on $onto with linear history,
> -# but this should be done only when upstream and onto are the same
> -# and if this is not an interactive rebase.
> -mb=$(git merge-base "$onto" "$orig_head")
> -if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
> -	test "$mb" = "$onto" && test -z "$restrict_revision" &&
> -	# linear history?
> -	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
> -then
> -	if test -z "$force_rebase"
> -	then
> -		# Lazily switch to the target branch if needed...
> -		test -z "$switch_to" ||
> -		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
> -			git checkout -q "$switch_to" --
> -		if test "$branch_name" = "HEAD" &&
> -			 ! git symbolic-ref -q HEAD
> -		then
> -			say "$(eval_gettext "HEAD is up to date.")"
> -		else
> -			say "$(eval_gettext "Current branch \$branch_name is up to date.")"
> -		fi
> -		finish_rebase
> -		exit 0
> -	else
> -		if test "$branch_name" = "HEAD" &&
> -			 ! git symbolic-ref -q HEAD
> -		then
> -			say "$(eval_gettext "HEAD is up to date, rebase forced.")"
> -		else
> -			say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
> -		fi
> -	fi
> -fi
> -
> -# If a hook exists, give it a chance to interrupt
> -run_pre_rebase_hook "$upstream_arg" "$@"
> -
> -if test -n "$diffstat"
> -then
> -	if test -n "$verbose"
> -	then
> -		if test -z "$mb"
> -		then
> -			echo "$(eval_gettext "Changes to \$onto:")"
> -		else
> -			echo "$(eval_gettext "Changes from \$mb to \$onto:")"
> -		fi
> -	fi
> -	mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
> -	# We want color (if set), but no pager
> -	GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
> -fi
> -
> -if test -z "$actually_interactive" && test "$mb" = "$orig_head"
> -then
> -	say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
> -	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
> -		git checkout -q "$onto^0" || die "could not detach HEAD"
> -	# If the $onto is a proper descendant of the tip of the branch, then
> -	# we just fast-forwarded.
> -	git update-ref ORIG_HEAD $orig_head
> -	move_to_original_branch
> -	finish_rebase
> -	exit 0
> -fi
> -
> -test -n "$interactive_rebase" && run_specific_rebase
> -
> -# Detach HEAD and reset the tree
> -say "$(gettext "First, rewinding head to replay your work on top of it...")"
> -
> -GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
> -	git checkout -q "$onto^0" || die "could not detach HEAD"
> -git update-ref ORIG_HEAD $orig_head
> -
> -if test -n "$rebase_root"
> -then
> -	revisions="$onto..$orig_head"
> -else
> -	revisions="${restrict_revision-$upstream}..$orig_head"
> -fi
> -
> -run_specific_rebase
> diff --git a/t/README b/t/README
> index 1326fd7505..decceb8576 100644
> --- a/t/README
> +++ b/t/README
> @@ -374,10 +374,6 @@ the --no-sparse command-line argument.
>  GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
>  by overriding the minimum number of cache entries required per thread.
>  
> -GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the
> -builtin version of git-rebase. See 'rebase.useBuiltin' in
> -git-config(1).
> -
>  GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
>  of the index for the whole test suite by bypassing the default number of
>  cache entries and thread minimums. Setting this to 1 will make the
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 3e73f7584c..0a88eed1db 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -311,4 +311,10 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
>  	)
>  '
>  
> +test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN= \
> +		git -c rebase.useBuiltin=false rebase 2>err &&
> +	test_i18ngrep "rebase.useBuiltin support has been removed" err
> +'
> +
>  test_done
> -- 
> 2.20.1.611.gfbb209baf1
> 
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase: remove the rebase.useBuiltin setting
  2019-02-13 14:22           ` [PATCH] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
  2019-02-13 16:25             ` Johannes Schindelin
@ 2019-02-13 20:46             ` Junio C Hamano
  2019-02-13 21:49               ` [PATCH] rebase: fix regression in rebase.useBuiltin=false test mode Ævar Arnfjörð Bjarmason
  2019-03-14 13:24             ` [PATCH v2] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
  2 siblings, 1 reply; 31+ messages in thread
From: Junio C Hamano @ 2019-02-13 20:46 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Phillip Wood, Johannes Schindelin

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Remove the rebase.useBuiltin setting, which was added as an escape
> hatch to disable the builtin version of rebase first released with Git
> 2.20.
> ...
>> This patch breaks the test suite (with these two new tests) under
>> GIT_TEST_REBASE_USE_BUILTIN=false. So a 2.21.0-rc0 regression.
>>
>> It would have been better to raise this before the rc period, but I just
>> noticed this now, but we can now:
>>
>>  1. Skip the test under that mode
>>  2. Fix the shell code to do the same thing
>>  3. Just remove the shell code & GIT_TEST_REBASE_USE_BUILTIN=false mode
>>
>> Maybe we should just do #3. The reason for the escape hatch was in case
>> we had bugs, and now we've had a full release cycle, but maybe that's
>> too early...

If a new feature is added to the built-in version, I do not think it
is a good use of our time to backport it to the scripted version, if
only to make the USE_BUILTIN=false test pass, especially when the
problematic thing is a fringe feature, lack of which would not
affect the real users too much.

So I do agree that #2 is a bad choice.

However, it is way too late in the cycle to say that we will ship
without the escape hatch for the upcoming release, so #3 is a non
starter.  And you are reading too much into a full release cycle,
which is merely less than 1k commits and a bit short of 3 months.

It would however be long enough to declare victory _immediately
after_ the upcoming release and start the next cycle without the
escape hatch.  At that point we'd be committed to maintain only the
built-in version.

The more important every-day features should still be covered by
tests, if the scripted ones are to be kept as escape hatch.  So to
me #1 looks like the only sensible choice at this point, if you want
to see a test cycle with USE_BUILTIN=false to fully pass (i.e. by
skipping the ones that are known not to pass).


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH] rebase: fix regression in rebase.useBuiltin=false test mode
  2019-02-13 20:46             ` Junio C Hamano
@ 2019-02-13 21:49               ` Ævar Arnfjörð Bjarmason
  2019-02-13 23:21                 ` Junio C Hamano
  2019-02-14 16:12                 ` Phillip Wood
  0 siblings, 2 replies; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-02-13 21:49 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Fix a recently introduced regression in c762aada1a ("rebase -x: sanity
check command", 2019-01-29) triggered when running the tests with
GIT_TEST_REBASE_USE_BUILTIN=false. See 62c23938fa ("tests: add a
special setup where rebase.useBuiltin is off", 2018-11-14) for how
that test mode works.

As discussed on-list[1] it's not worth it to implement the sanity
check in the legacy rebase code, we plan to remove it after the 2.21
release. So let's do the bare minimum to make the tests pass under the
GIT_TEST_REBASE_USE_BUILTIN=false special setup.

1. https://public-inbox.org/git/xmqqva1nbeno.fsf@gitster-ct.c.googlers.com/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---

On Wed, Feb 13 2019, Junio C Hamano wrote:
  
> [...]
> It would however be long enough to declare victory _immediately
> after_ the upcoming release and start the next cycle without the
> escape hatch.  At that point we'd be committed to maintain only the
> built-in version.
>
> The more important every-day features should still be covered by
> tests, if the scripted ones are to be kept as escape hatch.  So to
> me #1 looks like the only sensible choice at this point, if you want
> to see a test cycle with USE_BUILTIN=false to fully pass (i.e. by
> skipping the ones that are known not to pass).

Let's do this for 2.21 then and I'll re-submit the legacy removal
patch after we start 2.22.

 t/t3404-rebase-interactive.sh | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 52fa41c707..b60b11f9f2 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -149,10 +149,12 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
 
 test_expect_success 'rebase -x with empty command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail git rebase -x "" @ 2>actual &&
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
+		git rebase -x "" @ 2>actual &&
 	test_write_lines "error: empty exec command" >expected &&
 	test_i18ncmp expected actual &&
-	test_must_fail git rebase -x " " @ 2>actual &&
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
+		git rebase -x " " @ 2>actual &&
 	test_i18ncmp expected actual
 '
 
@@ -160,7 +162,8 @@ LF='
 '
 test_expect_success 'rebase -x with newline in command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
+		git rebase -x "a${LF}b" @ 2>actual &&
 	test_write_lines "error: exec commands cannot contain newlines" \
 			 >expected &&
 	test_i18ncmp expected actual
-- 
2.20.1.611.gfbb209baf1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase: fix regression in rebase.useBuiltin=false test mode
  2019-02-13 21:49               ` [PATCH] rebase: fix regression in rebase.useBuiltin=false test mode Ævar Arnfjörð Bjarmason
@ 2019-02-13 23:21                 ` Junio C Hamano
  2019-02-14 16:12                 ` Phillip Wood
  1 sibling, 0 replies; 31+ messages in thread
From: Junio C Hamano @ 2019-02-13 23:21 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Phillip Wood, Johannes Schindelin

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Let's do this for 2.21 then and I'll re-submit the legacy removal
> patch after we start 2.22.

OK, I would have thought that a prereq to check if the environment
is set and skip these problematic tests would be a lot cleaner
(primarily because the "legacy removal" patch will not touch the
body of the tests at all), but for just the coming few weeks, this
would suffice.

Thanks.

>
>  t/t3404-rebase-interactive.sh | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index 52fa41c707..b60b11f9f2 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -149,10 +149,12 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>  
>  test_expect_success 'rebase -x with empty command fails' '
>  	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail git rebase -x "" @ 2>actual &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> +		git rebase -x "" @ 2>actual &&
>  	test_write_lines "error: empty exec command" >expected &&
>  	test_i18ncmp expected actual &&
> -	test_must_fail git rebase -x " " @ 2>actual &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> +		git rebase -x " " @ 2>actual &&
>  	test_i18ncmp expected actual
>  '
>  
> @@ -160,7 +162,8 @@ LF='
>  '
>  test_expect_success 'rebase -x with newline in command fails' '
>  	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> +		git rebase -x "a${LF}b" @ 2>actual &&
>  	test_write_lines "error: exec commands cannot contain newlines" \
>  			 >expected &&
>  	test_i18ncmp expected actual

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase: fix regression in rebase.useBuiltin=false test mode
  2019-02-13 21:49               ` [PATCH] rebase: fix regression in rebase.useBuiltin=false test mode Ævar Arnfjörð Bjarmason
  2019-02-13 23:21                 ` Junio C Hamano
@ 2019-02-14 16:12                 ` Phillip Wood
  1 sibling, 0 replies; 31+ messages in thread
From: Phillip Wood @ 2019-02-14 16:12 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin

Hi Ævar

On 13/02/2019 21:49, Ævar Arnfjörð Bjarmason wrote:
> Fix a recently introduced regression in c762aada1a ("rebase -x: sanity
> check command", 2019-01-29) triggered when running the tests with
> GIT_TEST_REBASE_USE_BUILTIN=false. See 62c23938fa ("tests: add a
> special setup where rebase.useBuiltin is off", 2018-11-14) for how
> that test mode works.
> 
> As discussed on-list[1] it's not worth it to implement the sanity
> check in the legacy rebase code, we plan to remove it after the 2.21
> release. So let's do the bare minimum to make the tests pass under the
> GIT_TEST_REBASE_USE_BUILTIN=false special setup.
> 
> 1. https://public-inbox.org/git/xmqqva1nbeno.fsf@gitster-ct.c.googlers.com/
> 

Thanks for doing this, when I wrote the original patch I decided it wasn't
worth updating the legacy rebase but forgot about running the tests with
rebase.useBuiltin off.

Best Wishes

Phillip


> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
> 
> On Wed, Feb 13 2019, Junio C Hamano wrote:
>    
>> [...]
>> It would however be long enough to declare victory _immediately
>> after_ the upcoming release and start the next cycle without the
>> escape hatch.  At that point we'd be committed to maintain only the
>> built-in version.
>>
>> The more important every-day features should still be covered by
>> tests, if the scripted ones are to be kept as escape hatch.  So to
>> me #1 looks like the only sensible choice at this point, if you want
>> to see a test cycle with USE_BUILTIN=false to fully pass (i.e. by
>> skipping the ones that are known not to pass).
> 
> Let's do this for 2.21 then and I'll re-submit the legacy removal
> patch after we start 2.22.
> 
>   t/t3404-rebase-interactive.sh | 9 ++++++---
>   1 file changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index 52fa41c707..b60b11f9f2 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -149,10 +149,12 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>   
>   test_expect_success 'rebase -x with empty command fails' '
>   	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail git rebase -x "" @ 2>actual &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> +		git rebase -x "" @ 2>actual &&
>   	test_write_lines "error: empty exec command" >expected &&
>   	test_i18ncmp expected actual &&
> -	test_must_fail git rebase -x " " @ 2>actual &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> +		git rebase -x " " @ 2>actual &&
>   	test_i18ncmp expected actual
>   '
>   
> @@ -160,7 +162,8 @@ LF='
>   '
>   test_expect_success 'rebase -x with newline in command fails' '
>   	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> +		git rebase -x "a${LF}b" @ 2>actual &&
>   	test_write_lines "error: exec commands cannot contain newlines" \
>   			 >expected &&
>   	test_i18ncmp expected actual
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v2] rebase: remove the rebase.useBuiltin setting
  2019-02-13 14:22           ` [PATCH] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
  2019-02-13 16:25             ` Johannes Schindelin
  2019-02-13 20:46             ` Junio C Hamano
@ 2019-03-14 13:24             ` Ævar Arnfjörð Bjarmason
  2019-03-14 14:58               ` Johannes Schindelin
  2 siblings, 1 reply; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-03-14 13:24 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Remove the rebase.useBuiltin setting, which was added as an escape
hatch to disable the builtin version of rebase first released with Git
2.20.

See [1] for the initial implementation of rebase.useBuiltin, and [2]
and [3] for the documentation and corresponding
GIT_TEST_REBASE_USE_BUILTIN option.

Carrying the legacy version is a maintenance burden as seen in
7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
version has been shown to be stable enough let's remove the legacy
version.

There's still a bunch of references to git-legacy-rebase in po/*.po,
but those will be dealt with in time by the i18n effort.

1. 55071ea248 ("rebase: start implementing it as a builtin",
   2018-08-07)
2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
   off", 2018-11-14)
---

I submitted this shortly before v2.21.0 where Junio noted that he'd
rather take the smaller 9aea5e9286 fix for that release.

So here this is again now that we've started on v2.22.0. Only trivial
changes:

 - updated commit message
 - removed legacy script from .gitignore
 - adjusted more test code for a test added in 9aea5e9286

 .gitignore                      |   1 -
 Documentation/config/rebase.txt |  17 +-
 Makefile                        |   1 -
 builtin/rebase.c                |  17 +-
 git-legacy-rebase.sh            | 770 --------------------------------
 t/README                        |   4 -
 t/t3400-rebase.sh               |   6 +
 t/t3404-rebase-interactive.sh   |   9 +-
 8 files changed, 16 insertions(+), 809 deletions(-)
 delete mode 100755 git-legacy-rebase.sh

diff --git a/.gitignore b/.gitignore
index 7374587f9d..5cb84f1d1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,7 +82,6 @@
 /git-init-db
 /git-interpret-trailers
 /git-instaweb
-/git-legacy-rebase
 /git-log
 /git-ls-files
 /git-ls-remote
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 331d250e04..c747452983 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -1,16 +1,9 @@
 rebase.useBuiltin::
-	Set to `false` to use the legacy shellscript implementation of
-	linkgit:git-rebase[1]. Is `true` by default, which means use
-	the built-in rewrite of it in C.
-+
-The C rewrite is first included with Git version 2.20. This option
-serves an an escape hatch to re-enable the legacy version in case any
-bugs are found in the rewrite. This option and the shellscript version
-of linkgit:git-rebase[1] will be removed in some future release.
-+
-If you find some reason to set this option to `false` other than
-one-off testing you should report the behavior difference as a bug in
-git.
+	Unused configuration variable. Used between Git version 2.20
+	and 2.21 as an escape hatch to enable the legacy shellscript
+	implementation of rebase. Now the built-in rewrite of it in C
+	is always used. Setting this will emit a warning, to alert any
+	remaining users that setting this now does nothing.
 
 rebase.stat::
 	Whether to show a diffstat of what changed upstream since the last
diff --git a/Makefile b/Makefile
index 537493822b..9f1159cffc 100644
--- a/Makefile
+++ b/Makefile
@@ -632,7 +632,6 @@ SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-legacy-rebase.sh
 SCRIPT_SH += git-remote-testgit.sh
 SCRIPT_SH += git-request-pull.sh
 SCRIPT_SH += git-stash.sh
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 52114cbf0d..829897a8fe 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1143,21 +1143,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	};
 	int i;
 
-	/*
-	 * NEEDSWORK: Once the builtin rebase has been tested enough
-	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
-	 * can be removed.
-	 */
-
-	if (!use_builtin_rebase()) {
-		const char *path = mkpath("%s/git-legacy-rebase",
-					  git_exec_path());
-
-		if (sane_execvp(path, (char **)argv) < 0)
-			die_errno(_("could not exec %s"), path);
-		else
-			BUG("sane_execvp() returned???");
-	}
+	if (!use_builtin_rebase())
+		warning(_("The rebase.useBuiltin support has been removed!"));
 
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_rebase_usage,
diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh
deleted file mode 100755
index 5c2c4e5276..0000000000
--- a/git-legacy-rebase.sh
+++ /dev/null
@@ -1,770 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano.
-#
-
-SUBDIRECTORY_OK=Yes
-OPTIONS_KEEPDASHDASH=
-OPTIONS_STUCKLONG=t
-OPTIONS_SPEC="\
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
-git rebase --continue | --abort | --skip | --edit-todo
---
- Available options are
-v,verbose!         display a diffstat of what changed upstream
-q,quiet!           be quiet. implies --no-stat
-autostash          automatically stash/stash pop before and after
-fork-point         use 'merge-base --fork-point' to refine upstream
-onto=!             rebase onto given branch instead of upstream
-r,rebase-merges?   try to rebase merges instead of skipping them
-p,preserve-merges! try to recreate merges instead of ignoring them
-s,strategy=!       use the given merge strategy
-X,strategy-option=! pass the argument through to the merge strategy
-no-ff!             cherry-pick all commits, even if unchanged
-f,force-rebase!    cherry-pick all commits, even if unchanged
-m,merge!           use merging strategies to rebase
-i,interactive!     let the user edit the list of commits to rebase
-x,exec=!           add exec lines after each commit of the editable list
-k,keep-empty	   preserve empty commits during rebase
-allow-empty-message allow rebasing commits with empty messages
-stat!              display a diffstat of what changed upstream
-n,no-stat!         do not show diffstat of what changed upstream
-verify             allow pre-rebase hook to run
-rerere-autoupdate  allow rerere to update index with resolved conflicts
-root!              rebase all reachable commits up to the root(s)
-autosquash         move commits that begin with squash!/fixup! under -i
-signoff            add a Signed-off-by: line to each commit
-committer-date-is-author-date! passed to 'git am'
-ignore-date!       passed to 'git am'
-whitespace=!       passed to 'git apply'
-ignore-whitespace! passed to 'git apply'
-C=!                passed to 'git apply'
-S,gpg-sign?        GPG-sign commits
- Actions:
-continue!          continue
-abort!             abort and check out the original branch
-skip!              skip current patch and continue
-edit-todo!         edit the todo list during an interactive rebase
-quit!              abort but keep HEAD where it is
-show-current-patch! show the patch file being applied or merged
-reschedule-failed-exec automatically reschedule failed exec commands
-"
-. git-sh-setup
-set_reflog_action rebase
-require_work_tree_exists
-cd_to_toplevel
-
-LF='
-'
-ok_to_skip_pre_rebase=
-
-squash_onto=
-unset onto
-unset restrict_revision
-cmd=
-strategy=
-strategy_opts=
-do_merge=
-merge_dir="$GIT_DIR"/rebase-merge
-apply_dir="$GIT_DIR"/rebase-apply
-verbose=
-diffstat=
-test "$(git config --bool rebase.stat)" = true && diffstat=t
-autostash="$(git config --bool rebase.autostash || echo false)"
-fork_point=auto
-git_am_opt=
-git_format_patch_opt=
-rebase_root=
-force_rebase=
-allow_rerere_autoupdate=
-# Non-empty if a rebase was in progress when 'git rebase' was invoked
-in_progress=
-# One of {am, merge, interactive}
-type=
-# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
-state_dir=
-# One of {'', continue, skip, abort}, as parsed from command line
-action=
-rebase_merges=
-rebase_cousins=
-preserve_merges=
-autosquash=
-keep_empty=
-allow_empty_message=--allow-empty-message
-signoff=
-reschedule_failed_exec=
-test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
-case "$(git config --bool commit.gpgsign)" in
-true)	gpg_sign_opt=-S ;;
-*)	gpg_sign_opt= ;;
-esac
-test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
-reschedule_failed_exec=--reschedule-failed-exec
-. git-rebase--common
-
-read_basic_state () {
-	test -f "$state_dir/head-name" &&
-	test -f "$state_dir/onto" &&
-	head_name=$(cat "$state_dir"/head-name) &&
-	onto=$(cat "$state_dir"/onto) &&
-	# We always write to orig-head, but interactive rebase used to write to
-	# head. Fall back to reading from head to cover for the case that the
-	# user upgraded git with an ongoing interactive rebase.
-	if test -f "$state_dir"/orig-head
-	then
-		orig_head=$(cat "$state_dir"/orig-head)
-	else
-		orig_head=$(cat "$state_dir"/head)
-	fi &&
-	test -f "$state_dir"/quiet && GIT_QUIET=t
-	test -f "$state_dir"/verbose && verbose=t
-	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
-	test -f "$state_dir"/strategy_opts &&
-		strategy_opts="$(cat "$state_dir"/strategy_opts)"
-	test -f "$state_dir"/allow_rerere_autoupdate &&
-		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
-	test -f "$state_dir"/gpg_sign_opt &&
-		gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
-	test -f "$state_dir"/signoff && {
-		signoff="$(cat "$state_dir"/signoff)"
-		force_rebase=t
-	}
-	test -f "$state_dir"/reschedule-failed-exec &&
-		reschedule_failed_exec=t
-}
-
-finish_rebase () {
-	rm -f "$(git rev-parse --git-path REBASE_HEAD)"
-	apply_autostash &&
-	{ git gc --auto || true; } &&
-	rm -rf "$state_dir"
-}
-
-run_interactive () {
-	GIT_CHERRY_PICK_HELP="$resolvemsg"
-	export GIT_CHERRY_PICK_HELP
-
-	test -n "$keep_empty" && keep_empty="--keep-empty"
-	test -n "$rebase_merges" && rebase_merges="--rebase-merges"
-	test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
-	test -n "$autosquash" && autosquash="--autosquash"
-	test -n "$verbose" && verbose="--verbose"
-	test -n "$force_rebase" && force_rebase="--no-ff"
-	test -n "$restrict_revision" && \
-		restrict_revision="--restrict-revision=^$restrict_revision"
-	test -n "$upstream" && upstream="--upstream=$upstream"
-	test -n "$onto" && onto="--onto=$onto"
-	test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
-	test -n "$onto_name" && onto_name="--onto-name=$onto_name"
-	test -n "$head_name" && head_name="--head-name=$head_name"
-	test -n "$strategy" && strategy="--strategy=$strategy"
-	test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
-	test -n "$switch_to" && switch_to="--switch-to=$switch_to"
-	test -n "$cmd" && cmd="--cmd=$cmd"
-	test -n "$action" && action="--$action"
-
-	exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
-		"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
-		"$allow_empty_message" "$autosquash" "$verbose" \
-		"$force_rebase" "$onto_name" "$head_name" "$strategy" \
-		"$strategy_opts" "$cmd" "$switch_to" \
-		"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
-		"$reschedule_failed_exec"
-}
-
-run_specific_rebase () {
-	if [ "$interactive_rebase" = implied ]; then
-		GIT_SEQUENCE_EDITOR=:
-		export GIT_SEQUENCE_EDITOR
-		autosquash=
-	fi
-
-	if test -n "$interactive_rebase" -a -z "$preserve_merges"
-	then
-		run_interactive
-	else
-		. git-rebase--$type
-
-		if test -z "$preserve_merges"
-		then
-			git_rebase__$type
-		else
-			git_rebase__preserve_merges
-		fi
-	fi
-
-	ret=$?
-	if test $ret -eq 0
-	then
-		finish_rebase
-	elif test $ret -eq 2 # special exit status for rebase -p
-	then
-		apply_autostash &&
-		rm -rf "$state_dir" &&
-		die "Nothing to do"
-	fi
-	exit $ret
-}
-
-run_pre_rebase_hook () {
-	if test -z "$ok_to_skip_pre_rebase" &&
-	   test -x "$(git rev-parse --git-path hooks/pre-rebase)"
-	then
-		"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
-		die "$(gettext "The pre-rebase hook refused to rebase.")"
-	fi
-}
-
-test -f "$apply_dir"/applying &&
-	die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
-
-if test -d "$apply_dir"
-then
-	type=am
-	state_dir="$apply_dir"
-elif test -d "$merge_dir"
-then
-	type=interactive
-	if test -d "$merge_dir"/rewritten
-	then
-		type=preserve-merges
-		interactive_rebase=explicit
-		preserve_merges=t
-	elif test -f "$merge_dir"/interactive
-	then
-		interactive_rebase=explicit
-	fi
-	state_dir="$merge_dir"
-fi
-test -n "$type" && in_progress=t
-
-total_argc=$#
-while test $# != 0
-do
-	case "$1" in
-	--no-verify)
-		ok_to_skip_pre_rebase=yes
-		;;
-	--verify)
-		ok_to_skip_pre_rebase=
-		;;
-	--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
-		test $total_argc -eq 2 || usage
-		action=${1##--}
-		;;
-	--onto=*)
-		onto="${1#--onto=}"
-		;;
-	--exec=*)
-		cmd="${cmd}exec ${1#--exec=}${LF}"
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--interactive)
-		interactive_rebase=explicit
-		;;
-	--keep-empty)
-		keep_empty=yes
-		;;
-	--allow-empty-message)
-		allow_empty_message=--allow-empty-message
-		;;
-	--no-keep-empty)
-		keep_empty=
-		;;
-	--rebase-merges)
-		rebase_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--rebase-merges=*)
-		rebase_merges=t
-		case "${1#*=}" in
-		rebase-cousins) rebase_cousins=t;;
-		no-rebase-cousins) rebase_cousins=;;
-		*) die "Unknown mode: $1";;
-		esac
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--preserve-merges)
-		preserve_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--autosquash)
-		autosquash=t
-		;;
-	--no-autosquash)
-		autosquash=
-		;;
-	--fork-point)
-		fork_point=t
-		;;
-	--no-fork-point)
-		fork_point=
-		;;
-	--merge)
-		do_merge=t
-		;;
-	--strategy-option=*)
-		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
-		do_merge=t
-		test -z "$strategy" && strategy=recursive
-		;;
-	--strategy=*)
-		strategy="${1#--strategy=}"
-		do_merge=t
-		;;
-	--no-stat)
-		diffstat=
-		;;
-	--stat)
-		diffstat=t
-		;;
-	--autostash)
-		autostash=true
-		;;
-	--no-autostash)
-		autostash=false
-		;;
-	--verbose)
-		verbose=t
-		diffstat=t
-		GIT_QUIET=
-		;;
-	--quiet)
-		GIT_QUIET=t
-		git_am_opt="$git_am_opt -q"
-		verbose=
-		diffstat=
-		;;
-	--whitespace=*)
-		git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
-		case "${1#--whitespace=}" in
-		fix|strip)
-			force_rebase=t
-			;;
-		warn|nowarn|error|error-all)
-			;; # okay, known whitespace option
-		*)
-			die "fatal: Invalid whitespace option: '${1#*=}'"
-			;;
-		esac
-		;;
-	--ignore-whitespace)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--signoff)
-		signoff=--signoff
-		;;
-	--no-signoff)
-		signoff=
-		;;
-	--committer-date-is-author-date|--ignore-date)
-		git_am_opt="$git_am_opt $1"
-		force_rebase=t
-		;;
-	-C*[!0-9]*)
-		die "fatal: switch \`C' expects a numerical value"
-		;;
-	-C*)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--root)
-		rebase_root=t
-		;;
-	--force-rebase|--no-ff)
-		force_rebase=t
-		;;
-	--rerere-autoupdate|--no-rerere-autoupdate)
-		allow_rerere_autoupdate="$1"
-		;;
-	--gpg-sign)
-		gpg_sign_opt=-S
-		;;
-	--gpg-sign=*)
-		gpg_sign_opt="-S${1#--gpg-sign=}"
-		;;
-	--reschedule-failed-exec)
-		reschedule_failed_exec=--reschedule-failed-exec
-		;;
-	--no-reschedule-failed-exec)
-		reschedule_failed_exec=
-		;;
-	--)
-		shift
-		break
-		;;
-	*)
-		usage
-		;;
-	esac
-	shift
-done
-test $# -gt 2 && usage
-
-if test -n "$action"
-then
-	test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
-	# Only interactive rebase uses detailed reflog messages
-	if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
-	then
-		GIT_REFLOG_ACTION="rebase -i ($action)"
-		export GIT_REFLOG_ACTION
-	fi
-fi
-
-if test "$action" = "edit-todo" && test -z "$interactive_rebase"
-then
-	die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
-fi
-
-case "$action" in
-continue)
-	# Sanity check
-	git rev-parse --verify HEAD >/dev/null ||
-		die "$(gettext "Cannot read HEAD")"
-	git update-index --ignore-submodules --refresh &&
-	git diff-files --quiet --ignore-submodules || {
-		echo "$(gettext "You must edit all merge conflicts and then
-mark them as resolved using git add")"
-		exit 1
-	}
-	read_basic_state
-	run_specific_rebase
-	;;
-skip)
-	output git reset --hard HEAD || exit $?
-	read_basic_state
-	run_specific_rebase
-	;;
-abort)
-	git rerere clear
-	read_basic_state
-	case "$head_name" in
-	refs/*)
-		git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
-		die "$(eval_gettext "Could not move back to \$head_name")"
-		;;
-	esac
-	output git reset --hard $orig_head
-	finish_rebase
-	exit
-	;;
-quit)
-	exec rm -rf "$state_dir"
-	;;
-edit-todo)
-	run_specific_rebase
-	;;
-show-current-patch)
-	run_specific_rebase
-	die "BUG: run_specific_rebase is not supposed to return here"
-	;;
-esac
-
-# Make sure no rebase is in progress
-if test -n "$in_progress"
-then
-	state_dir_base=${state_dir##*/}
-	cmd_live_rebase="git rebase (--continue | --abort | --skip)"
-	cmd_clear_stale_rebase="rm -fr \"$state_dir\""
-	die "
-$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
-I wonder if you are in the middle of another rebase.  If that is the
-case, please try
-	$cmd_live_rebase
-If that is not the case, please
-	$cmd_clear_stale_rebase
-and run me again.  I am stopping in case you still have something
-valuable there.')"
-fi
-
-if test -n "$rebase_root" && test -z "$onto"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-if test -n "$keep_empty"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-actually_interactive=
-if test -n "$interactive_rebase"
-then
-	if test -z "$preserve_merges"
-	then
-		type=interactive
-	else
-		type=preserve-merges
-	fi
-	actually_interactive=t
-	state_dir="$merge_dir"
-elif test -n "$do_merge"
-then
-	interactive_rebase=implied
-	type=interactive
-	state_dir="$merge_dir"
-else
-	type=am
-	state_dir="$apply_dir"
-fi
-
-if test -t 2 && test -z "$GIT_QUIET"
-then
-	git_format_patch_opt="$git_format_patch_opt --progress"
-fi
-
-incompatible_opts=$(echo " $git_am_opt " | \
-		    sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
-if test -n "$incompatible_opts"
-then
-	if test -n "$actually_interactive" || test "$do_merge"
-	then
-		die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
-	fi
-fi
-
-if test -n "$signoff"
-then
-	test -n "$preserve_merges" &&
-		die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
-	git_am_opt="$git_am_opt $signoff"
-	force_rebase=t
-fi
-
-if test -n "$preserve_merges"
-then
-	# Note: incompatibility with --signoff handled in signoff block above
-	# Note: incompatibility with --interactive is just a strong warning;
-	#       git-rebase.txt caveats with "unless you know what you are doing"
-	test -n "$rebase_merges" &&
-		die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
-
-	test -n "$reschedule_failed_exec" &&
-		die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
-fi
-
-if test -n "$rebase_merges"
-then
-	test -n "$strategy_opts" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
-	test -n "$strategy" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
-fi
-
-if test -z "$rebase_root"
-then
-	case "$#" in
-	0)
-		if ! upstream_name=$(git rev-parse --symbolic-full-name \
-			--verify -q @{upstream} 2>/dev/null)
-		then
-			. git-parse-remote
-			error_on_missing_default_upstream "rebase" "rebase" \
-				"against" "git rebase $(gettext '<branch>')"
-		fi
-
-		test "$fork_point" = auto && fork_point=t
-		;;
-	*)	upstream_name="$1"
-		if test "$upstream_name" = "-"
-		then
-			upstream_name="@{-1}"
-		fi
-		shift
-		;;
-	esac
-	upstream=$(peel_committish "${upstream_name}") ||
-	die "$(eval_gettext "invalid upstream '\$upstream_name'")"
-	upstream_arg="$upstream_name"
-else
-	if test -z "$onto"
-	then
-		empty_tree=$(git hash-object -t tree /dev/null)
-		onto=$(git commit-tree $empty_tree </dev/null)
-		squash_onto="$onto"
-	fi
-	unset upstream_name
-	unset upstream
-	test $# -gt 1 && usage
-	upstream_arg=--root
-fi
-
-# Make sure the branch to rebase onto is valid.
-onto_name=${onto-"$upstream_name"}
-case "$onto_name" in
-*...*)
-	if	left=${onto_name%...*} right=${onto_name#*...} &&
-		onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
-	then
-		case "$onto" in
-		?*"$LF"?*)
-			die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
-			;;
-		'')
-			die "$(eval_gettext "\$onto_name: there is no merge base")"
-			;;
-		esac
-	else
-		die "$(eval_gettext "\$onto_name: there is no merge base")"
-	fi
-	;;
-*)
-	onto=$(peel_committish "$onto_name") ||
-	die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
-	;;
-esac
-
-# If the branch to rebase is given, that is the branch we will rebase
-# $branch_name -- branch/commit being rebased, or HEAD (already detached)
-# $orig_head -- commit object name of tip of the branch before rebasing
-# $head_name -- refs/heads/<that-branch> or "detached HEAD"
-switch_to=
-case "$#" in
-1)
-	# Is it "rebase other $branchname" or "rebase other $commit"?
-	branch_name="$1"
-	switch_to="$1"
-
-	# Is it a local branch?
-	if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
-	   orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
-	then
-		head_name="refs/heads/$branch_name"
-	# If not is it a valid ref (branch or commit)?
-	elif orig_head=$(git rev-parse -q --verify "$branch_name")
-	then
-		head_name="detached HEAD"
-
-	else
-		die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
-	fi
-	;;
-0)
-	# Do not need to switch branches, we are already on it.
-	if branch_name=$(git symbolic-ref -q HEAD)
-	then
-		head_name=$branch_name
-		branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
-	else
-		head_name="detached HEAD"
-		branch_name=HEAD
-	fi
-	orig_head=$(git rev-parse --verify HEAD) || exit
-	;;
-*)
-	die "BUG: unexpected number of arguments left to parse"
-	;;
-esac
-
-if test "$fork_point" = t
-then
-	new_upstream=$(git merge-base --fork-point "$upstream_name" \
-			"${switch_to:-HEAD}")
-	if test -n "$new_upstream"
-	then
-		restrict_revision=$new_upstream
-	fi
-fi
-
-if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
-then
-	stash_sha1=$(git stash create "autostash") ||
-	die "$(gettext 'Cannot autostash')"
-
-	mkdir -p "$state_dir" &&
-	echo $stash_sha1 >"$state_dir/autostash" &&
-	stash_abbrev=$(git rev-parse --short $stash_sha1) &&
-	echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
-	git reset --hard
-fi
-
-require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
-
-# Now we are rebasing commits $upstream..$orig_head (or with --root,
-# everything leading up to $orig_head) on top of $onto
-
-# Check if we are already based on $onto with linear history,
-# but this should be done only when upstream and onto are the same
-# and if this is not an interactive rebase.
-mb=$(git merge-base "$onto" "$orig_head")
-if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
-	test "$mb" = "$onto" && test -z "$restrict_revision" &&
-	# linear history?
-	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
-then
-	if test -z "$force_rebase"
-	then
-		# Lazily switch to the target branch if needed...
-		test -z "$switch_to" ||
-		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
-			git checkout -q "$switch_to" --
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date.")"
-		fi
-		finish_rebase
-		exit 0
-	else
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date, rebase forced.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
-		fi
-	fi
-fi
-
-# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook "$upstream_arg" "$@"
-
-if test -n "$diffstat"
-then
-	if test -n "$verbose"
-	then
-		if test -z "$mb"
-		then
-			echo "$(eval_gettext "Changes to \$onto:")"
-		else
-			echo "$(eval_gettext "Changes from \$mb to \$onto:")"
-		fi
-	fi
-	mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
-	# We want color (if set), but no pager
-	GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
-fi
-
-if test -z "$actually_interactive" && test "$mb" = "$orig_head"
-then
-	say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
-	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-		git checkout -q "$onto^0" || die "could not detach HEAD"
-	# If the $onto is a proper descendant of the tip of the branch, then
-	# we just fast-forwarded.
-	git update-ref ORIG_HEAD $orig_head
-	move_to_original_branch
-	finish_rebase
-	exit 0
-fi
-
-test -n "$interactive_rebase" && run_specific_rebase
-
-# Detach HEAD and reset the tree
-say "$(gettext "First, rewinding head to replay your work on top of it...")"
-
-GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-	git checkout -q "$onto^0" || die "could not detach HEAD"
-git update-ref ORIG_HEAD $orig_head
-
-if test -n "$rebase_root"
-then
-	revisions="$onto..$orig_head"
-else
-	revisions="${restrict_revision-$upstream}..$orig_head"
-fi
-
-run_specific_rebase
diff --git a/t/README b/t/README
index 7a3d582267..385262357b 100644
--- a/t/README
+++ b/t/README
@@ -379,10 +379,6 @@ the --no-sparse command-line argument.
 GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
 by overriding the minimum number of cache entries required per thread.
 
-GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the
-builtin version of git-rebase. See 'rebase.useBuiltin' in
-git-config(1).
-
 GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
 of the index for the whole test suite by bypassing the default number of
 cache entries and thread minimums. Setting this to 1 will make the
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 3e73f7584c..0a88eed1db 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -311,4 +311,10 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
 	)
 '
 
+test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN= \
+		git -c rebase.useBuiltin=false rebase 2>err &&
+	test_i18ngrep "rebase.useBuiltin support has been removed" err
+'
+
 test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index b60b11f9f2..1723e1a858 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
 
 test_expect_success 'rebase -x with empty command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x "" @ 2>actual &&
+	test_must_fail env git rebase -x "" @ 2>actual &&
 	test_write_lines "error: empty exec command" >expected &&
 	test_i18ncmp expected actual &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x " " @ 2>actual &&
+	test_must_fail env git rebase -x " " @ 2>actual &&
 	test_i18ncmp expected actual
 '
 
@@ -162,8 +160,7 @@ LF='
 '
 test_expect_success 'rebase -x with newline in command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x "a${LF}b" @ 2>actual &&
+	test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
 	test_write_lines "error: exec commands cannot contain newlines" \
 			 >expected &&
 	test_i18ncmp expected actual
-- 
2.21.0.360.g471c308f928


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v2] rebase: remove the rebase.useBuiltin setting
  2019-03-14 13:24             ` [PATCH v2] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
@ 2019-03-14 14:58               ` Johannes Schindelin
  2019-03-14 15:27                 ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 31+ messages in thread
From: Johannes Schindelin @ 2019-03-14 14:58 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Junio C Hamano, Phillip Wood

[-- Attachment #1: Type: text/plain, Size: 6625 bytes --]

Hi Ævar,

On Thu, 14 Mar 2019, Ævar Arnfjörð Bjarmason wrote:

> Remove the rebase.useBuiltin setting, which was added as an escape
> hatch to disable the builtin version of rebase first released with Git
> 2.20.
> 
> See [1] for the initial implementation of rebase.useBuiltin, and [2]
> and [3] for the documentation and corresponding
> GIT_TEST_REBASE_USE_BUILTIN option.
> 
> Carrying the legacy version is a maintenance burden as seen in
> 7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
> checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
> rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
> version has been shown to be stable enough let's remove the legacy
> version.

I agree with that reasoning. Elsewhere, a wish cropped up for the `git
stash` command to optionally ignore unmatched globs, and if we go about to
implement this, we will have to implement it in the scripted and the
built-in version. If we can at least avoid that for the `rebase` command,
I think it would make things a bit easier over here.

> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
> index 331d250e04..c747452983 100644
> --- a/Documentation/config/rebase.txt
> +++ b/Documentation/config/rebase.txt
> @@ -1,16 +1,9 @@
>  rebase.useBuiltin::
> -	Set to `false` to use the legacy shellscript implementation of
> -	linkgit:git-rebase[1]. Is `true` by default, which means use
> -	the built-in rewrite of it in C.
> -+
> -The C rewrite is first included with Git version 2.20. This option
> -serves an an escape hatch to re-enable the legacy version in case any
> -bugs are found in the rewrite. This option and the shellscript version
> -of linkgit:git-rebase[1] will be removed in some future release.
> -+
> -If you find some reason to set this option to `false` other than
> -one-off testing you should report the behavior difference as a bug in
> -git.
> +	Unused configuration variable. Used between Git version 2.20
> +	and 2.21 as an escape hatch to enable the legacy shellscript
> +	implementation of rebase. Now the built-in rewrite of it in C
> +	is always used. Setting this will emit a warning, to alert any
> +	remaining users that setting this now does nothing.

Do we really need to document this? Why not just remove the entire entry
wholesale; the warning if `rebase.useBuiltin=false` is set will be
informative enough.

> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 52114cbf0d..829897a8fe 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -1143,21 +1143,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  	};
>  	int i;
>  
> -	/*
> -	 * NEEDSWORK: Once the builtin rebase has been tested enough
> -	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
> -	 * can be removed.
> -	 */
> -
> -	if (!use_builtin_rebase()) {
> -		const char *path = mkpath("%s/git-legacy-rebase",
> -					  git_exec_path());
> -
> -		if (sane_execvp(path, (char **)argv) < 0)
> -			die_errno(_("could not exec %s"), path);
> -		else
> -			BUG("sane_execvp() returned???");
> -	}
> +	if (!use_builtin_rebase())
> +		warning(_("The rebase.useBuiltin support has been removed!"));

A couple of thoughts about this:

- `use_builtin_rebase()` spawns a `git config`. This is a pretty expensive
  operation on Windows (even if it might not matter in the big scheme of
  things, as the couple of milliseconds are probably a mere drop on a hot
  stone compared to the I/O incurred by the recursive merge), and it was
  only done in that way to allow for spawning the legacy rebase without
  having touched any global state (such as setting `GIT_*` environment
  variables when a Git directory was discovered).

  Couldn't we rather move this warning into `rebase_config()`?

- The warning should start with a lower-case letter (why don't we have any
  automated linter for this? This is a totally automatable thing that
  could run as part of `make` when `DEVELOPER` is set, maybe just on the
  `git diff HEAD --` part, and maybe even generating a patch that can be
  applied; No human should *ever* need to spend time on such issues).

- That warning should probably talk more specifically about the scripted
  version having been removed, not only the option (which was actually not
  removed, otherwise the user would not see that warning ;-)).

> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 3e73f7584c..0a88eed1db 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -311,4 +311,10 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
>  	)
>  '
>  
> +test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN= \

Good attention to detail! I would have forgotten to unset that environment
variable.

> +		git -c rebase.useBuiltin=false rebase 2>err &&
> +	test_i18ngrep "rebase.useBuiltin support has been removed" err
> +'
> +
>  test_done
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index b60b11f9f2..1723e1a858 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>  
>  test_expect_success 'rebase -x with empty command fails' '
>  	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x "" @ 2>actual &&
> +	test_must_fail env git rebase -x "" @ 2>actual &&
>  	test_write_lines "error: empty exec command" >expected &&
>  	test_i18ncmp expected actual &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x " " @ 2>actual &&
> +	test_must_fail env git rebase -x " " @ 2>actual &&
>  	test_i18ncmp expected actual
>  '
>  
> @@ -162,8 +160,7 @@ LF='
>  '
>  test_expect_success 'rebase -x with newline in command fails' '
>  	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x "a${LF}b" @ 2>actual &&
> +	test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&

Not a terribly big deal, but I would have structured the patch (series) by
leaving this change to t3404 as a 2/2, as it is not technically necessary
to include those changes in 1/2 (if your goal is, as mine usually is, to
"go from working state to working state" between commits).

Thank you for keeping on the track with this,
Dscho

>  	test_write_lines "error: exec commands cannot contain newlines" \
>  			 >expected &&
>  	test_i18ncmp expected actual
> -- 
> 2.21.0.360.g471c308f928
> 
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2] rebase: remove the rebase.useBuiltin setting
  2019-03-14 14:58               ` Johannes Schindelin
@ 2019-03-14 15:27                 ` Ævar Arnfjörð Bjarmason
  2019-03-15 13:45                   ` [PATCH v3] " Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-03-14 15:27 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Junio C Hamano, Phillip Wood


On Thu, Mar 14 2019, Johannes Schindelin wrote:

> Hi Ævar,
>
> On Thu, 14 Mar 2019, Ævar Arnfjörð Bjarmason wrote:
>
>> Remove the rebase.useBuiltin setting, which was added as an escape
>> hatch to disable the builtin version of rebase first released with Git
>> 2.20.
>>
>> See [1] for the initial implementation of rebase.useBuiltin, and [2]
>> and [3] for the documentation and corresponding
>> GIT_TEST_REBASE_USE_BUILTIN option.
>>
>> Carrying the legacy version is a maintenance burden as seen in
>> 7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
>> checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
>> rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
>> version has been shown to be stable enough let's remove the legacy
>> version.
>
> I agree with that reasoning. Elsewhere, a wish cropped up for the `git
> stash` command to optionally ignore unmatched globs, and if we go about to
> implement this, we will have to implement it in the scripted and the
> built-in version. If we can at least avoid that for the `rebase` command,
> I think it would make things a bit easier over here.
>
>> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
>> index 331d250e04..c747452983 100644
>> --- a/Documentation/config/rebase.txt
>> +++ b/Documentation/config/rebase.txt
>> @@ -1,16 +1,9 @@
>>  rebase.useBuiltin::
>> -	Set to `false` to use the legacy shellscript implementation of
>> -	linkgit:git-rebase[1]. Is `true` by default, which means use
>> -	the built-in rewrite of it in C.
>> -+
>> -The C rewrite is first included with Git version 2.20. This option
>> -serves an an escape hatch to re-enable the legacy version in case any
>> -bugs are found in the rewrite. This option and the shellscript version
>> -of linkgit:git-rebase[1] will be removed in some future release.
>> -+
>> -If you find some reason to set this option to `false` other than
>> -one-off testing you should report the behavior difference as a bug in
>> -git.
>> +	Unused configuration variable. Used between Git version 2.20
>> +	and 2.21 as an escape hatch to enable the legacy shellscript
>> +	implementation of rebase. Now the built-in rewrite of it in C
>> +	is always used. Setting this will emit a warning, to alert any
>> +	remaining users that setting this now does nothing.
>
> Do we really need to document this? Why not just remove the entire entry
> wholesale; the warning if `rebase.useBuiltin=false` is set will be
> informative enough.

I don't have a super-strong preference in this case, but in general I
think it makes sense to have docs for this too.

Individual versions of git tend to be around for a while due to distro
packaging timelines, so e.g. if we're "lucky" a given version like 2.21
might be installed on say OSX for half a decade.

That'll mean some people probably setting this in config, and then when
they later wonder if it's needed they can Google search the config
option name or check it in git-config, less of a stretch than needing to
know to run git-rebase with the option...

>> diff --git a/builtin/rebase.c b/builtin/rebase.c
>> index 52114cbf0d..829897a8fe 100644
>> --- a/builtin/rebase.c
>> +++ b/builtin/rebase.c
>> @@ -1143,21 +1143,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>>  	};
>>  	int i;
>>
>> -	/*
>> -	 * NEEDSWORK: Once the builtin rebase has been tested enough
>> -	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
>> -	 * can be removed.
>> -	 */
>> -
>> -	if (!use_builtin_rebase()) {
>> -		const char *path = mkpath("%s/git-legacy-rebase",
>> -					  git_exec_path());
>> -
>> -		if (sane_execvp(path, (char **)argv) < 0)
>> -			die_errno(_("could not exec %s"), path);
>> -		else
>> -			BUG("sane_execvp() returned???");
>> -	}
>> +	if (!use_builtin_rebase())
>> +		warning(_("The rebase.useBuiltin support has been removed!"));
>
> A couple of thoughts about this:
>
> - `use_builtin_rebase()` spawns a `git config`. This is a pretty expensive
>   operation on Windows (even if it might not matter in the big scheme of
>   things, as the couple of milliseconds are probably a mere drop on a hot
>   stone compared to the I/O incurred by the recursive merge), and it was
>   only done in that way to allow for spawning the legacy rebase without
>   having touched any global state (such as setting `GIT_*` environment
>   variables when a Git directory was discovered).
>
>   Couldn't we rather move this warning into `rebase_config()`?
>
> - The warning should start with a lower-case letter (why don't we have any
>   automated linter for this? This is a totally automatable thing that
>   could run as part of `make` when `DEVELOPER` is set, maybe just on the
>   `git diff HEAD --` part, and maybe even generating a patch that can be
>   applied; No human should *ever* need to spend time on such issues).

Both of these make sense. Will have that in a v3 pending further
feedback. Didn't notice that strange use_builtin_rebase()
implementation.

> - That warning should probably talk more specifically about the scripted
>   version having been removed, not only the option (which was actually not
>   removed, otherwise the user would not see that warning ;-)).

...or just change it to briefly refer to the git-config docs where all
of this will be explained :)

>> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
>> index 3e73f7584c..0a88eed1db 100755
>> --- a/t/t3400-rebase.sh
>> +++ b/t/t3400-rebase.sh
>> @@ -311,4 +311,10 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
>>  	)
>>  '
>>
>> +test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
>> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN= \
>
> Good attention to detail! I would have forgotten to unset that environment
> variable.
>
>> +		git -c rebase.useBuiltin=false rebase 2>err &&
>> +	test_i18ngrep "rebase.useBuiltin support has been removed" err
>> +'
>> +
>>  test_done
>> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
>> index b60b11f9f2..1723e1a858 100755
>> --- a/t/t3404-rebase-interactive.sh
>> +++ b/t/t3404-rebase-interactive.sh
>> @@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>>
>>  test_expect_success 'rebase -x with empty command fails' '
>>  	test_when_finished "git rebase --abort ||:" &&
>> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
>> -		git rebase -x "" @ 2>actual &&
>> +	test_must_fail env git rebase -x "" @ 2>actual &&
>>  	test_write_lines "error: empty exec command" >expected &&
>>  	test_i18ncmp expected actual &&
>> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
>> -		git rebase -x " " @ 2>actual &&
>> +	test_must_fail env git rebase -x " " @ 2>actual &&
>>  	test_i18ncmp expected actual
>>  '
>>
>> @@ -162,8 +160,7 @@ LF='
>>  '
>>  test_expect_success 'rebase -x with newline in command fails' '
>>  	test_when_finished "git rebase --abort ||:" &&
>> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
>> -		git rebase -x "a${LF}b" @ 2>actual &&
>> +	test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
>
> Not a terribly big deal, but I would have structured the patch (series) by
> leaving this change to t3404 as a 2/2, as it is not technically necessary
> to include those changes in 1/2 (if your goal is, as mine usually is, to
> "go from working state to working state" between commits).

I run the test suite on various git versions, including for bisecting
purposes and with various GIT_TEST_* options on.

I'll probably never bump into *this* particular commit for this option,
but in general I think it makes more sense to not break the test suite
under existing GIT_TEST_* flags, unless it's a breakage where e.g. we
say "this isn't supported anymore".

By splitting this up as you suggest the 1/2 of those would be a head
scratching breakage under GIT_TEST_REBASE_USE_BUILTIN=false, and only
under 2/2 would we show via the warning why it was failing.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v3] rebase: remove the rebase.useBuiltin setting
  2019-03-14 15:27                 ` Ævar Arnfjörð Bjarmason
@ 2019-03-15 13:45                   ` Ævar Arnfjörð Bjarmason
  2019-03-15 15:44                     ` Johannes Schindelin
  2019-03-18 10:19                     ` Phillip Wood
  0 siblings, 2 replies; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-03-15 13:45 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Remove the rebase.useBuiltin setting, which was added as an escape
hatch to disable the builtin version of rebase first released with Git
2.20.

See [1] for the initial implementation of rebase.useBuiltin, and [2]
and [3] for the documentation and corresponding
GIT_TEST_REBASE_USE_BUILTIN option.

Carrying the legacy version is a maintenance burden as seen in
7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
version has been shown to be stable enough let's remove the legacy
version.

As noted in [3] having use_builtin_rebase() shell out to get its
config doesn't make any sense anymore, that was done for the purposes
of spawning the legacy rebase without having modified any global
state. Let's instead handle this case in rebase_config().

There's still a bunch of references to git-legacy-rebase in po/*.po,
but those will be dealt with in time by the i18n effort.

Even though this configuration variable only existed for one release
let's not entirely delete the entry from the docs, but note its
absence. Individual versions of git tend to be around for a while due
to distro packaging timelines, so e.g. if we're "lucky" a given
version like 2.21 might be installed on say OSX for half a decade.

That'll mean some people probably setting this in config, and then
when they later wonder if it's needed they can Google search the
config option name or check it in git-config. It also allows us to
refer to the docs from the warning for details.

1. 55071ea248 ("rebase: start implementing it as a builtin",
   2018-08-07)
2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
   off", 2018-11-14)
3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/
---

Addresses Johannes's comments on v2, and improves the tests I'm adding
to cover both the env var & config variable.

 .gitignore                      |   1 -
 Documentation/config/rebase.txt |  17 +-
 Makefile                        |   1 -
 builtin/rebase.c                |  50 +--
 git-legacy-rebase.sh            | 770 --------------------------------
 t/README                        |   4 -
 t/t3400-rebase.sh               |  16 +
 t/t3404-rebase-interactive.sh   |   9 +-
 8 files changed, 35 insertions(+), 833 deletions(-)
 delete mode 100755 git-legacy-rebase.sh

diff --git a/.gitignore b/.gitignore
index 7374587f9d..5cb84f1d1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,7 +82,6 @@
 /git-init-db
 /git-interpret-trailers
 /git-instaweb
-/git-legacy-rebase
 /git-log
 /git-ls-files
 /git-ls-remote
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 331d250e04..c747452983 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -1,16 +1,9 @@
 rebase.useBuiltin::
-	Set to `false` to use the legacy shellscript implementation of
-	linkgit:git-rebase[1]. Is `true` by default, which means use
-	the built-in rewrite of it in C.
-+
-The C rewrite is first included with Git version 2.20. This option
-serves an an escape hatch to re-enable the legacy version in case any
-bugs are found in the rewrite. This option and the shellscript version
-of linkgit:git-rebase[1] will be removed in some future release.
-+
-If you find some reason to set this option to `false` other than
-one-off testing you should report the behavior difference as a bug in
-git.
+	Unused configuration variable. Used between Git version 2.20
+	and 2.21 as an escape hatch to enable the legacy shellscript
+	implementation of rebase. Now the built-in rewrite of it in C
+	is always used. Setting this will emit a warning, to alert any
+	remaining users that setting this now does nothing.
 
 rebase.stat::
 	Whether to show a diffstat of what changed upstream since the last
diff --git a/Makefile b/Makefile
index 537493822b..9f1159cffc 100644
--- a/Makefile
+++ b/Makefile
@@ -632,7 +632,6 @@ SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-legacy-rebase.sh
 SCRIPT_SH += git-remote-testgit.sh
 SCRIPT_SH += git-request-pull.sh
 SCRIPT_SH += git-stash.sh
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 52114cbf0d..bc3dc629c1 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -46,29 +46,6 @@ enum rebase_type {
 	REBASE_PRESERVE_MERGES
 };
 
-static int use_builtin_rebase(void)
-{
-	struct child_process cp = CHILD_PROCESS_INIT;
-	struct strbuf out = STRBUF_INIT;
-	int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1);
-
-	if (env != -1)
-		return env;
-
-	argv_array_pushl(&cp.args,
-			 "config", "--bool", "rebase.usebuiltin", NULL);
-	cp.git_cmd = 1;
-	if (capture_command(&cp, &out, 6)) {
-		strbuf_release(&out);
-		return 1;
-	}
-
-	strbuf_trim(&out);
-	ret = !strcmp("true", out.buf);
-	strbuf_release(&out);
-	return ret;
-}
-
 struct rebase_options {
 	enum rebase_type type;
 	const char *state_dir;
@@ -106,6 +83,7 @@ struct rebase_options {
 	char *strategy, *strategy_opts;
 	struct strbuf git_format_patch_opt;
 	int reschedule_failed_exec;
+	int use_legacy_rebase;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -869,6 +847,11 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "rebase.usebuiltin")) {
+		opts->use_legacy_rebase = !git_config_bool(var, value);
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -1143,22 +1126,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	};
 	int i;
 
-	/*
-	 * NEEDSWORK: Once the builtin rebase has been tested enough
-	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
-	 * can be removed.
-	 */
-
-	if (!use_builtin_rebase()) {
-		const char *path = mkpath("%s/git-legacy-rebase",
-					  git_exec_path());
-
-		if (sane_execvp(path, (char **)argv) < 0)
-			die_errno(_("could not exec %s"), path);
-		else
-			BUG("sane_execvp() returned???");
-	}
-
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_rebase_usage,
 				   builtin_rebase_options);
@@ -1169,6 +1136,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	git_config(rebase_config, &options);
 
+	if (options.use_legacy_rebase ||
+	    !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
+		warning(_("the rebase.useBuiltin support has been removed!\n"
+			  "See its entry in 'git help config' for details."));
+
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "%s/applying", apply_dir());
 	if(file_exists(buf.buf))
diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh
deleted file mode 100755
index 5c2c4e5276..0000000000
--- a/git-legacy-rebase.sh
+++ /dev/null
@@ -1,770 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano.
-#
-
-SUBDIRECTORY_OK=Yes
-OPTIONS_KEEPDASHDASH=
-OPTIONS_STUCKLONG=t
-OPTIONS_SPEC="\
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
-git rebase --continue | --abort | --skip | --edit-todo
---
- Available options are
-v,verbose!         display a diffstat of what changed upstream
-q,quiet!           be quiet. implies --no-stat
-autostash          automatically stash/stash pop before and after
-fork-point         use 'merge-base --fork-point' to refine upstream
-onto=!             rebase onto given branch instead of upstream
-r,rebase-merges?   try to rebase merges instead of skipping them
-p,preserve-merges! try to recreate merges instead of ignoring them
-s,strategy=!       use the given merge strategy
-X,strategy-option=! pass the argument through to the merge strategy
-no-ff!             cherry-pick all commits, even if unchanged
-f,force-rebase!    cherry-pick all commits, even if unchanged
-m,merge!           use merging strategies to rebase
-i,interactive!     let the user edit the list of commits to rebase
-x,exec=!           add exec lines after each commit of the editable list
-k,keep-empty	   preserve empty commits during rebase
-allow-empty-message allow rebasing commits with empty messages
-stat!              display a diffstat of what changed upstream
-n,no-stat!         do not show diffstat of what changed upstream
-verify             allow pre-rebase hook to run
-rerere-autoupdate  allow rerere to update index with resolved conflicts
-root!              rebase all reachable commits up to the root(s)
-autosquash         move commits that begin with squash!/fixup! under -i
-signoff            add a Signed-off-by: line to each commit
-committer-date-is-author-date! passed to 'git am'
-ignore-date!       passed to 'git am'
-whitespace=!       passed to 'git apply'
-ignore-whitespace! passed to 'git apply'
-C=!                passed to 'git apply'
-S,gpg-sign?        GPG-sign commits
- Actions:
-continue!          continue
-abort!             abort and check out the original branch
-skip!              skip current patch and continue
-edit-todo!         edit the todo list during an interactive rebase
-quit!              abort but keep HEAD where it is
-show-current-patch! show the patch file being applied or merged
-reschedule-failed-exec automatically reschedule failed exec commands
-"
-. git-sh-setup
-set_reflog_action rebase
-require_work_tree_exists
-cd_to_toplevel
-
-LF='
-'
-ok_to_skip_pre_rebase=
-
-squash_onto=
-unset onto
-unset restrict_revision
-cmd=
-strategy=
-strategy_opts=
-do_merge=
-merge_dir="$GIT_DIR"/rebase-merge
-apply_dir="$GIT_DIR"/rebase-apply
-verbose=
-diffstat=
-test "$(git config --bool rebase.stat)" = true && diffstat=t
-autostash="$(git config --bool rebase.autostash || echo false)"
-fork_point=auto
-git_am_opt=
-git_format_patch_opt=
-rebase_root=
-force_rebase=
-allow_rerere_autoupdate=
-# Non-empty if a rebase was in progress when 'git rebase' was invoked
-in_progress=
-# One of {am, merge, interactive}
-type=
-# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
-state_dir=
-# One of {'', continue, skip, abort}, as parsed from command line
-action=
-rebase_merges=
-rebase_cousins=
-preserve_merges=
-autosquash=
-keep_empty=
-allow_empty_message=--allow-empty-message
-signoff=
-reschedule_failed_exec=
-test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
-case "$(git config --bool commit.gpgsign)" in
-true)	gpg_sign_opt=-S ;;
-*)	gpg_sign_opt= ;;
-esac
-test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
-reschedule_failed_exec=--reschedule-failed-exec
-. git-rebase--common
-
-read_basic_state () {
-	test -f "$state_dir/head-name" &&
-	test -f "$state_dir/onto" &&
-	head_name=$(cat "$state_dir"/head-name) &&
-	onto=$(cat "$state_dir"/onto) &&
-	# We always write to orig-head, but interactive rebase used to write to
-	# head. Fall back to reading from head to cover for the case that the
-	# user upgraded git with an ongoing interactive rebase.
-	if test -f "$state_dir"/orig-head
-	then
-		orig_head=$(cat "$state_dir"/orig-head)
-	else
-		orig_head=$(cat "$state_dir"/head)
-	fi &&
-	test -f "$state_dir"/quiet && GIT_QUIET=t
-	test -f "$state_dir"/verbose && verbose=t
-	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
-	test -f "$state_dir"/strategy_opts &&
-		strategy_opts="$(cat "$state_dir"/strategy_opts)"
-	test -f "$state_dir"/allow_rerere_autoupdate &&
-		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
-	test -f "$state_dir"/gpg_sign_opt &&
-		gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
-	test -f "$state_dir"/signoff && {
-		signoff="$(cat "$state_dir"/signoff)"
-		force_rebase=t
-	}
-	test -f "$state_dir"/reschedule-failed-exec &&
-		reschedule_failed_exec=t
-}
-
-finish_rebase () {
-	rm -f "$(git rev-parse --git-path REBASE_HEAD)"
-	apply_autostash &&
-	{ git gc --auto || true; } &&
-	rm -rf "$state_dir"
-}
-
-run_interactive () {
-	GIT_CHERRY_PICK_HELP="$resolvemsg"
-	export GIT_CHERRY_PICK_HELP
-
-	test -n "$keep_empty" && keep_empty="--keep-empty"
-	test -n "$rebase_merges" && rebase_merges="--rebase-merges"
-	test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
-	test -n "$autosquash" && autosquash="--autosquash"
-	test -n "$verbose" && verbose="--verbose"
-	test -n "$force_rebase" && force_rebase="--no-ff"
-	test -n "$restrict_revision" && \
-		restrict_revision="--restrict-revision=^$restrict_revision"
-	test -n "$upstream" && upstream="--upstream=$upstream"
-	test -n "$onto" && onto="--onto=$onto"
-	test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
-	test -n "$onto_name" && onto_name="--onto-name=$onto_name"
-	test -n "$head_name" && head_name="--head-name=$head_name"
-	test -n "$strategy" && strategy="--strategy=$strategy"
-	test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
-	test -n "$switch_to" && switch_to="--switch-to=$switch_to"
-	test -n "$cmd" && cmd="--cmd=$cmd"
-	test -n "$action" && action="--$action"
-
-	exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
-		"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
-		"$allow_empty_message" "$autosquash" "$verbose" \
-		"$force_rebase" "$onto_name" "$head_name" "$strategy" \
-		"$strategy_opts" "$cmd" "$switch_to" \
-		"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
-		"$reschedule_failed_exec"
-}
-
-run_specific_rebase () {
-	if [ "$interactive_rebase" = implied ]; then
-		GIT_SEQUENCE_EDITOR=:
-		export GIT_SEQUENCE_EDITOR
-		autosquash=
-	fi
-
-	if test -n "$interactive_rebase" -a -z "$preserve_merges"
-	then
-		run_interactive
-	else
-		. git-rebase--$type
-
-		if test -z "$preserve_merges"
-		then
-			git_rebase__$type
-		else
-			git_rebase__preserve_merges
-		fi
-	fi
-
-	ret=$?
-	if test $ret -eq 0
-	then
-		finish_rebase
-	elif test $ret -eq 2 # special exit status for rebase -p
-	then
-		apply_autostash &&
-		rm -rf "$state_dir" &&
-		die "Nothing to do"
-	fi
-	exit $ret
-}
-
-run_pre_rebase_hook () {
-	if test -z "$ok_to_skip_pre_rebase" &&
-	   test -x "$(git rev-parse --git-path hooks/pre-rebase)"
-	then
-		"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
-		die "$(gettext "The pre-rebase hook refused to rebase.")"
-	fi
-}
-
-test -f "$apply_dir"/applying &&
-	die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
-
-if test -d "$apply_dir"
-then
-	type=am
-	state_dir="$apply_dir"
-elif test -d "$merge_dir"
-then
-	type=interactive
-	if test -d "$merge_dir"/rewritten
-	then
-		type=preserve-merges
-		interactive_rebase=explicit
-		preserve_merges=t
-	elif test -f "$merge_dir"/interactive
-	then
-		interactive_rebase=explicit
-	fi
-	state_dir="$merge_dir"
-fi
-test -n "$type" && in_progress=t
-
-total_argc=$#
-while test $# != 0
-do
-	case "$1" in
-	--no-verify)
-		ok_to_skip_pre_rebase=yes
-		;;
-	--verify)
-		ok_to_skip_pre_rebase=
-		;;
-	--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
-		test $total_argc -eq 2 || usage
-		action=${1##--}
-		;;
-	--onto=*)
-		onto="${1#--onto=}"
-		;;
-	--exec=*)
-		cmd="${cmd}exec ${1#--exec=}${LF}"
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--interactive)
-		interactive_rebase=explicit
-		;;
-	--keep-empty)
-		keep_empty=yes
-		;;
-	--allow-empty-message)
-		allow_empty_message=--allow-empty-message
-		;;
-	--no-keep-empty)
-		keep_empty=
-		;;
-	--rebase-merges)
-		rebase_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--rebase-merges=*)
-		rebase_merges=t
-		case "${1#*=}" in
-		rebase-cousins) rebase_cousins=t;;
-		no-rebase-cousins) rebase_cousins=;;
-		*) die "Unknown mode: $1";;
-		esac
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--preserve-merges)
-		preserve_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--autosquash)
-		autosquash=t
-		;;
-	--no-autosquash)
-		autosquash=
-		;;
-	--fork-point)
-		fork_point=t
-		;;
-	--no-fork-point)
-		fork_point=
-		;;
-	--merge)
-		do_merge=t
-		;;
-	--strategy-option=*)
-		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
-		do_merge=t
-		test -z "$strategy" && strategy=recursive
-		;;
-	--strategy=*)
-		strategy="${1#--strategy=}"
-		do_merge=t
-		;;
-	--no-stat)
-		diffstat=
-		;;
-	--stat)
-		diffstat=t
-		;;
-	--autostash)
-		autostash=true
-		;;
-	--no-autostash)
-		autostash=false
-		;;
-	--verbose)
-		verbose=t
-		diffstat=t
-		GIT_QUIET=
-		;;
-	--quiet)
-		GIT_QUIET=t
-		git_am_opt="$git_am_opt -q"
-		verbose=
-		diffstat=
-		;;
-	--whitespace=*)
-		git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
-		case "${1#--whitespace=}" in
-		fix|strip)
-			force_rebase=t
-			;;
-		warn|nowarn|error|error-all)
-			;; # okay, known whitespace option
-		*)
-			die "fatal: Invalid whitespace option: '${1#*=}'"
-			;;
-		esac
-		;;
-	--ignore-whitespace)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--signoff)
-		signoff=--signoff
-		;;
-	--no-signoff)
-		signoff=
-		;;
-	--committer-date-is-author-date|--ignore-date)
-		git_am_opt="$git_am_opt $1"
-		force_rebase=t
-		;;
-	-C*[!0-9]*)
-		die "fatal: switch \`C' expects a numerical value"
-		;;
-	-C*)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--root)
-		rebase_root=t
-		;;
-	--force-rebase|--no-ff)
-		force_rebase=t
-		;;
-	--rerere-autoupdate|--no-rerere-autoupdate)
-		allow_rerere_autoupdate="$1"
-		;;
-	--gpg-sign)
-		gpg_sign_opt=-S
-		;;
-	--gpg-sign=*)
-		gpg_sign_opt="-S${1#--gpg-sign=}"
-		;;
-	--reschedule-failed-exec)
-		reschedule_failed_exec=--reschedule-failed-exec
-		;;
-	--no-reschedule-failed-exec)
-		reschedule_failed_exec=
-		;;
-	--)
-		shift
-		break
-		;;
-	*)
-		usage
-		;;
-	esac
-	shift
-done
-test $# -gt 2 && usage
-
-if test -n "$action"
-then
-	test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
-	# Only interactive rebase uses detailed reflog messages
-	if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
-	then
-		GIT_REFLOG_ACTION="rebase -i ($action)"
-		export GIT_REFLOG_ACTION
-	fi
-fi
-
-if test "$action" = "edit-todo" && test -z "$interactive_rebase"
-then
-	die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
-fi
-
-case "$action" in
-continue)
-	# Sanity check
-	git rev-parse --verify HEAD >/dev/null ||
-		die "$(gettext "Cannot read HEAD")"
-	git update-index --ignore-submodules --refresh &&
-	git diff-files --quiet --ignore-submodules || {
-		echo "$(gettext "You must edit all merge conflicts and then
-mark them as resolved using git add")"
-		exit 1
-	}
-	read_basic_state
-	run_specific_rebase
-	;;
-skip)
-	output git reset --hard HEAD || exit $?
-	read_basic_state
-	run_specific_rebase
-	;;
-abort)
-	git rerere clear
-	read_basic_state
-	case "$head_name" in
-	refs/*)
-		git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
-		die "$(eval_gettext "Could not move back to \$head_name")"
-		;;
-	esac
-	output git reset --hard $orig_head
-	finish_rebase
-	exit
-	;;
-quit)
-	exec rm -rf "$state_dir"
-	;;
-edit-todo)
-	run_specific_rebase
-	;;
-show-current-patch)
-	run_specific_rebase
-	die "BUG: run_specific_rebase is not supposed to return here"
-	;;
-esac
-
-# Make sure no rebase is in progress
-if test -n "$in_progress"
-then
-	state_dir_base=${state_dir##*/}
-	cmd_live_rebase="git rebase (--continue | --abort | --skip)"
-	cmd_clear_stale_rebase="rm -fr \"$state_dir\""
-	die "
-$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
-I wonder if you are in the middle of another rebase.  If that is the
-case, please try
-	$cmd_live_rebase
-If that is not the case, please
-	$cmd_clear_stale_rebase
-and run me again.  I am stopping in case you still have something
-valuable there.')"
-fi
-
-if test -n "$rebase_root" && test -z "$onto"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-if test -n "$keep_empty"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-actually_interactive=
-if test -n "$interactive_rebase"
-then
-	if test -z "$preserve_merges"
-	then
-		type=interactive
-	else
-		type=preserve-merges
-	fi
-	actually_interactive=t
-	state_dir="$merge_dir"
-elif test -n "$do_merge"
-then
-	interactive_rebase=implied
-	type=interactive
-	state_dir="$merge_dir"
-else
-	type=am
-	state_dir="$apply_dir"
-fi
-
-if test -t 2 && test -z "$GIT_QUIET"
-then
-	git_format_patch_opt="$git_format_patch_opt --progress"
-fi
-
-incompatible_opts=$(echo " $git_am_opt " | \
-		    sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
-if test -n "$incompatible_opts"
-then
-	if test -n "$actually_interactive" || test "$do_merge"
-	then
-		die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
-	fi
-fi
-
-if test -n "$signoff"
-then
-	test -n "$preserve_merges" &&
-		die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
-	git_am_opt="$git_am_opt $signoff"
-	force_rebase=t
-fi
-
-if test -n "$preserve_merges"
-then
-	# Note: incompatibility with --signoff handled in signoff block above
-	# Note: incompatibility with --interactive is just a strong warning;
-	#       git-rebase.txt caveats with "unless you know what you are doing"
-	test -n "$rebase_merges" &&
-		die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
-
-	test -n "$reschedule_failed_exec" &&
-		die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
-fi
-
-if test -n "$rebase_merges"
-then
-	test -n "$strategy_opts" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
-	test -n "$strategy" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
-fi
-
-if test -z "$rebase_root"
-then
-	case "$#" in
-	0)
-		if ! upstream_name=$(git rev-parse --symbolic-full-name \
-			--verify -q @{upstream} 2>/dev/null)
-		then
-			. git-parse-remote
-			error_on_missing_default_upstream "rebase" "rebase" \
-				"against" "git rebase $(gettext '<branch>')"
-		fi
-
-		test "$fork_point" = auto && fork_point=t
-		;;
-	*)	upstream_name="$1"
-		if test "$upstream_name" = "-"
-		then
-			upstream_name="@{-1}"
-		fi
-		shift
-		;;
-	esac
-	upstream=$(peel_committish "${upstream_name}") ||
-	die "$(eval_gettext "invalid upstream '\$upstream_name'")"
-	upstream_arg="$upstream_name"
-else
-	if test -z "$onto"
-	then
-		empty_tree=$(git hash-object -t tree /dev/null)
-		onto=$(git commit-tree $empty_tree </dev/null)
-		squash_onto="$onto"
-	fi
-	unset upstream_name
-	unset upstream
-	test $# -gt 1 && usage
-	upstream_arg=--root
-fi
-
-# Make sure the branch to rebase onto is valid.
-onto_name=${onto-"$upstream_name"}
-case "$onto_name" in
-*...*)
-	if	left=${onto_name%...*} right=${onto_name#*...} &&
-		onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
-	then
-		case "$onto" in
-		?*"$LF"?*)
-			die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
-			;;
-		'')
-			die "$(eval_gettext "\$onto_name: there is no merge base")"
-			;;
-		esac
-	else
-		die "$(eval_gettext "\$onto_name: there is no merge base")"
-	fi
-	;;
-*)
-	onto=$(peel_committish "$onto_name") ||
-	die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
-	;;
-esac
-
-# If the branch to rebase is given, that is the branch we will rebase
-# $branch_name -- branch/commit being rebased, or HEAD (already detached)
-# $orig_head -- commit object name of tip of the branch before rebasing
-# $head_name -- refs/heads/<that-branch> or "detached HEAD"
-switch_to=
-case "$#" in
-1)
-	# Is it "rebase other $branchname" or "rebase other $commit"?
-	branch_name="$1"
-	switch_to="$1"
-
-	# Is it a local branch?
-	if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
-	   orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
-	then
-		head_name="refs/heads/$branch_name"
-	# If not is it a valid ref (branch or commit)?
-	elif orig_head=$(git rev-parse -q --verify "$branch_name")
-	then
-		head_name="detached HEAD"
-
-	else
-		die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
-	fi
-	;;
-0)
-	# Do not need to switch branches, we are already on it.
-	if branch_name=$(git symbolic-ref -q HEAD)
-	then
-		head_name=$branch_name
-		branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
-	else
-		head_name="detached HEAD"
-		branch_name=HEAD
-	fi
-	orig_head=$(git rev-parse --verify HEAD) || exit
-	;;
-*)
-	die "BUG: unexpected number of arguments left to parse"
-	;;
-esac
-
-if test "$fork_point" = t
-then
-	new_upstream=$(git merge-base --fork-point "$upstream_name" \
-			"${switch_to:-HEAD}")
-	if test -n "$new_upstream"
-	then
-		restrict_revision=$new_upstream
-	fi
-fi
-
-if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
-then
-	stash_sha1=$(git stash create "autostash") ||
-	die "$(gettext 'Cannot autostash')"
-
-	mkdir -p "$state_dir" &&
-	echo $stash_sha1 >"$state_dir/autostash" &&
-	stash_abbrev=$(git rev-parse --short $stash_sha1) &&
-	echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
-	git reset --hard
-fi
-
-require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
-
-# Now we are rebasing commits $upstream..$orig_head (or with --root,
-# everything leading up to $orig_head) on top of $onto
-
-# Check if we are already based on $onto with linear history,
-# but this should be done only when upstream and onto are the same
-# and if this is not an interactive rebase.
-mb=$(git merge-base "$onto" "$orig_head")
-if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
-	test "$mb" = "$onto" && test -z "$restrict_revision" &&
-	# linear history?
-	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
-then
-	if test -z "$force_rebase"
-	then
-		# Lazily switch to the target branch if needed...
-		test -z "$switch_to" ||
-		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
-			git checkout -q "$switch_to" --
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date.")"
-		fi
-		finish_rebase
-		exit 0
-	else
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date, rebase forced.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
-		fi
-	fi
-fi
-
-# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook "$upstream_arg" "$@"
-
-if test -n "$diffstat"
-then
-	if test -n "$verbose"
-	then
-		if test -z "$mb"
-		then
-			echo "$(eval_gettext "Changes to \$onto:")"
-		else
-			echo "$(eval_gettext "Changes from \$mb to \$onto:")"
-		fi
-	fi
-	mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
-	# We want color (if set), but no pager
-	GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
-fi
-
-if test -z "$actually_interactive" && test "$mb" = "$orig_head"
-then
-	say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
-	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-		git checkout -q "$onto^0" || die "could not detach HEAD"
-	# If the $onto is a proper descendant of the tip of the branch, then
-	# we just fast-forwarded.
-	git update-ref ORIG_HEAD $orig_head
-	move_to_original_branch
-	finish_rebase
-	exit 0
-fi
-
-test -n "$interactive_rebase" && run_specific_rebase
-
-# Detach HEAD and reset the tree
-say "$(gettext "First, rewinding head to replay your work on top of it...")"
-
-GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-	git checkout -q "$onto^0" || die "could not detach HEAD"
-git update-ref ORIG_HEAD $orig_head
-
-if test -n "$rebase_root"
-then
-	revisions="$onto..$orig_head"
-else
-	revisions="${restrict_revision-$upstream}..$orig_head"
-fi
-
-run_specific_rebase
diff --git a/t/README b/t/README
index 7a3d582267..385262357b 100644
--- a/t/README
+++ b/t/README
@@ -379,10 +379,6 @@ the --no-sparse command-line argument.
 GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
 by overriding the minimum number of cache entries required per thread.
 
-GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the
-builtin version of git-rebase. See 'rebase.useBuiltin' in
-git-config(1).
-
 GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
 of the index for the whole test suite by bypassing the default number of
 cache entries and thread minimums. Setting this to 1 will make the
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 3e73f7584c..a809de9304 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -311,4 +311,20 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
 	)
 '
 
+test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
+	expected="rebase.useBuiltin support has been removed" &&
+
+	# Only warn when the legacy rebase is requested...
+	test_must_fail git -c rebase.useBuiltin=false rebase 2>err &&
+	test_i18ngrep "$expected" err &&
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err &&
+	test_i18ngrep "$expected" err &&
+
+	# ...not when we would have used the built-in anyway
+	test_must_fail git -c rebase.useBuiltin=true rebase 2>err &&
+	test_must_be_empty err &&
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err &&
+	test_must_be_empty err
+'
+
 test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index b60b11f9f2..1723e1a858 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
 
 test_expect_success 'rebase -x with empty command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x "" @ 2>actual &&
+	test_must_fail env git rebase -x "" @ 2>actual &&
 	test_write_lines "error: empty exec command" >expected &&
 	test_i18ncmp expected actual &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x " " @ 2>actual &&
+	test_must_fail env git rebase -x " " @ 2>actual &&
 	test_i18ncmp expected actual
 '
 
@@ -162,8 +160,7 @@ LF='
 '
 test_expect_success 'rebase -x with newline in command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x "a${LF}b" @ 2>actual &&
+	test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
 	test_write_lines "error: exec commands cannot contain newlines" \
 			 >expected &&
 	test_i18ncmp expected actual
-- 
2.21.0.360.g471c308f928


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v3] rebase: remove the rebase.useBuiltin setting
  2019-03-15 13:45                   ` [PATCH v3] " Ævar Arnfjörð Bjarmason
@ 2019-03-15 15:44                     ` Johannes Schindelin
  2019-03-15 16:11                       ` Ævar Arnfjörð Bjarmason
  2019-03-18 10:19                     ` Phillip Wood
  1 sibling, 1 reply; 31+ messages in thread
From: Johannes Schindelin @ 2019-03-15 15:44 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Junio C Hamano, Phillip Wood

[-- Attachment #1: Type: text/plain, Size: 2140 bytes --]

Hi Ævar,

On Fri, 15 Mar 2019, Ævar Arnfjörð Bjarmason wrote:

> Remove the rebase.useBuiltin setting, which was added as an escape
> hatch to disable the builtin version of rebase first released with Git
> 2.20.
> 
> See [1] for the initial implementation of rebase.useBuiltin, and [2]
> and [3] for the documentation and corresponding
> GIT_TEST_REBASE_USE_BUILTIN option.
> 
> Carrying the legacy version is a maintenance burden as seen in
> 7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
> checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
> rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
> version has been shown to be stable enough let's remove the legacy
> version.
> 
> As noted in [3] having use_builtin_rebase() shell out to get its
> config doesn't make any sense anymore, that was done for the purposes
> of spawning the legacy rebase without having modified any global
> state. Let's instead handle this case in rebase_config().
> 
> There's still a bunch of references to git-legacy-rebase in po/*.po,
> but those will be dealt with in time by the i18n effort.
> 
> Even though this configuration variable only existed for one release
> let's not entirely delete the entry from the docs, but note its
> absence. Individual versions of git tend to be around for a while due
> to distro packaging timelines, so e.g. if we're "lucky" a given
> version like 2.21 might be installed on say OSX for half a decade.
> 
> That'll mean some people probably setting this in config, and then
> when they later wonder if it's needed they can Google search the
> config option name or check it in git-config. It also allows us to
> refer to the docs from the warning for details.
> 
> 1. 55071ea248 ("rebase: start implementing it as a builtin",
>    2018-08-07)
> 2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
> 3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
>    off", 2018-11-14)
> 3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/
> ---

With the obviously intended SOB line: ACK!

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3] rebase: remove the rebase.useBuiltin setting
  2019-03-15 15:44                     ` Johannes Schindelin
@ 2019-03-15 16:11                       ` Ævar Arnfjörð Bjarmason
  2019-03-18  6:06                         ` Junio C Hamano
  0 siblings, 1 reply; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-03-15 16:11 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Junio C Hamano, Phillip Wood


On Fri, Mar 15 2019, Johannes Schindelin wrote:

> Hi Ævar,
>
> On Fri, 15 Mar 2019, Ævar Arnfjörð Bjarmason wrote:
>
>> Remove the rebase.useBuiltin setting, which was added as an escape
>> hatch to disable the builtin version of rebase first released with Git
>> 2.20.
>>
>> See [1] for the initial implementation of rebase.useBuiltin, and [2]
>> and [3] for the documentation and corresponding
>> GIT_TEST_REBASE_USE_BUILTIN option.
>>
>> Carrying the legacy version is a maintenance burden as seen in
>> 7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
>> checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
>> rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
>> version has been shown to be stable enough let's remove the legacy
>> version.
>>
>> As noted in [3] having use_builtin_rebase() shell out to get its
>> config doesn't make any sense anymore, that was done for the purposes
>> of spawning the legacy rebase without having modified any global
>> state. Let's instead handle this case in rebase_config().
>>
>> There's still a bunch of references to git-legacy-rebase in po/*.po,
>> but those will be dealt with in time by the i18n effort.
>>
>> Even though this configuration variable only existed for one release
>> let's not entirely delete the entry from the docs, but note its
>> absence. Individual versions of git tend to be around for a while due
>> to distro packaging timelines, so e.g. if we're "lucky" a given
>> version like 2.21 might be installed on say OSX for half a decade.
>>
>> That'll mean some people probably setting this in config, and then
>> when they later wonder if it's needed they can Google search the
>> config option name or check it in git-config. It also allows us to
>> refer to the docs from the warning for details.
>>
>> 1. 55071ea248 ("rebase: start implementing it as a builtin",
>>    2018-08-07)
>> 2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
>> 3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
>>    off", 2018-11-14)
>> 3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/
>> ---
>
> With the obviously intended SOB line: ACK!

Urgh, Junio: If there's no other comments/concerns on v3 requiring a v4
this has my:

    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3] rebase: remove the rebase.useBuiltin setting
  2019-03-15 16:11                       ` Ævar Arnfjörð Bjarmason
@ 2019-03-18  6:06                         ` Junio C Hamano
  0 siblings, 0 replies; 31+ messages in thread
From: Junio C Hamano @ 2019-03-18  6:06 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Johannes Schindelin, git, Phillip Wood

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> Urgh, Junio: If there's no other comments/concerns on v3 requiring a v4
> this has my:
>
>     Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Alright.  Let's queue, wait for a while to see if there is anything
else and continue.

Thanks.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3] rebase: remove the rebase.useBuiltin setting
  2019-03-15 13:45                   ` [PATCH v3] " Ævar Arnfjörð Bjarmason
  2019-03-15 15:44                     ` Johannes Schindelin
@ 2019-03-18 10:19                     ` Phillip Wood
  2019-03-18 11:01                       ` [PATCH v4] " Ævar Arnfjörð Bjarmason
  1 sibling, 1 reply; 31+ messages in thread
From: Phillip Wood @ 2019-03-18 10:19 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin

Hi Ævar

Thanks for doing this, it's great to see it from a maintenance 
perspective as well as it meaning the builtin rebase is considered 
stable. A couple small nit picks below

On 15/03/2019 13:45, Ævar Arnfjörð Bjarmason wrote:
> Remove the rebase.useBuiltin setting, which was added as an escape
> hatch to disable the builtin version of rebase first released with Git
> 2.20.
> 
> See [1] for the initial implementation of rebase.useBuiltin, and [2]
> and [3] for the documentation and corresponding
> GIT_TEST_REBASE_USE_BUILTIN option.
> 
> Carrying the legacy version is a maintenance burden as seen in
> 7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
> checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
> rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
> version has been shown to be stable enough let's remove the legacy
> version.
> 
> As noted in [3] having use_builtin_rebase() shell out to get its
> config doesn't make any sense anymore, that was done for the purposes
> of spawning the legacy rebase without having modified any global
> state. Let's instead handle this case in rebase_config().
> 
> There's still a bunch of references to git-legacy-rebase in po/*.po,
> but those will be dealt with in time by the i18n effort.
> 
> Even though this configuration variable only existed for one release

If it was added in 2.20 then that's two releases isn't it?

> let's not entirely delete the entry from the docs, but note its
> absence. Individual versions of git tend to be around for a while due
> to distro packaging timelines, so e.g. if we're "lucky" a given
> version like 2.21 might be installed on say OSX for half a decade.
> 
> That'll mean some people probably setting this in config, and then
> when they later wonder if it's needed they can Google search the
> config option name or check it in git-config. It also allows us to
> refer to the docs from the warning for details.
> 
> 1. 55071ea248 ("rebase: start implementing it as a builtin",
>     2018-08-07)
> 2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
> 3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
>     off", 2018-11-14)
> 3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/
> ---
> 
> Addresses Johannes's comments on v2, and improves the tests I'm adding
> to cover both the env var & config variable.
> 
>   .gitignore                      |   1 -
>   Documentation/config/rebase.txt |  17 +-
>   Makefile                        |   1 -
>   builtin/rebase.c                |  50 +--
>   git-legacy-rebase.sh            | 770 --------------------------------
>   t/README                        |   4 -
>   t/t3400-rebase.sh               |  16 +
>   t/t3404-rebase-interactive.sh   |   9 +-
>   8 files changed, 35 insertions(+), 833 deletions(-)
>   delete mode 100755 git-legacy-rebase.sh
> 
> diff --git a/.gitignore b/.gitignore
> index 7374587f9d..5cb84f1d1a 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -82,7 +82,6 @@
>   /git-init-db
>   /git-interpret-trailers
>   /git-instaweb
> -/git-legacy-rebase
>   /git-log
>   /git-ls-files
>   /git-ls-remote
> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
> index 331d250e04..c747452983 100644
> --- a/Documentation/config/rebase.txt
> +++ b/Documentation/config/rebase.txt
> @@ -1,16 +1,9 @@
>   rebase.useBuiltin::
> -	Set to `false` to use the legacy shellscript implementation of
> -	linkgit:git-rebase[1]. Is `true` by default, which means use
> -	the built-in rewrite of it in C.
> -+
> -The C rewrite is first included with Git version 2.20. This option
> -serves an an escape hatch to re-enable the legacy version in case any
> -bugs are found in the rewrite. This option and the shellscript version
> -of linkgit:git-rebase[1] will be removed in some future release.
> -+
> -If you find some reason to set this option to `false` other than
> -one-off testing you should report the behavior difference as a bug in
> -git.
> +	Unused configuration variable. Used between Git version 2.20
> +	and 2.21

If it is present in 2.21 then this is perhaps ambiguous, Iread it as < 
2.21 rather than <=2.21 (I just asked my wife what she thought it meant 
to make sure it wasn't just me and she says the same) so maybe

Used in Git versions 2.20 and 2.21

would be clearer

Best Wishes

Phillip

  as an escape hatch to enable the legacy shellscript
> +	implementation of rebase. Now the built-in rewrite of it in C
> +	is always used. Setting this will emit a warning, to alert any
> +	remaining users that setting this now does nothing.
>   
>   rebase.stat::
>   	Whether to show a diffstat of what changed upstream since the last
> diff --git a/Makefile b/Makefile
> index 537493822b..9f1159cffc 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -632,7 +632,6 @@ SCRIPT_SH += git-merge-one-file.sh
>   SCRIPT_SH += git-merge-resolve.sh
>   SCRIPT_SH += git-mergetool.sh
>   SCRIPT_SH += git-quiltimport.sh
> -SCRIPT_SH += git-legacy-rebase.sh
>   SCRIPT_SH += git-remote-testgit.sh
>   SCRIPT_SH += git-request-pull.sh
>   SCRIPT_SH += git-stash.sh
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 52114cbf0d..bc3dc629c1 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -46,29 +46,6 @@ enum rebase_type {
>   	REBASE_PRESERVE_MERGES
>   };
>   
> -static int use_builtin_rebase(void)
> -{
> -	struct child_process cp = CHILD_PROCESS_INIT;
> -	struct strbuf out = STRBUF_INIT;
> -	int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1);
> -
> -	if (env != -1)
> -		return env;
> -
> -	argv_array_pushl(&cp.args,
> -			 "config", "--bool", "rebase.usebuiltin", NULL);
> -	cp.git_cmd = 1;
> -	if (capture_command(&cp, &out, 6)) {
> -		strbuf_release(&out);
> -		return 1;
> -	}
> -
> -	strbuf_trim(&out);
> -	ret = !strcmp("true", out.buf);
> -	strbuf_release(&out);
> -	return ret;
> -}
> -
>   struct rebase_options {
>   	enum rebase_type type;
>   	const char *state_dir;
> @@ -106,6 +83,7 @@ struct rebase_options {
>   	char *strategy, *strategy_opts;
>   	struct strbuf git_format_patch_opt;
>   	int reschedule_failed_exec;
> +	int use_legacy_rebase;
>   };
>   
>   static int is_interactive(struct rebase_options *opts)
> @@ -869,6 +847,11 @@ static int rebase_config(const char *var, const char *value, void *data)
>   		return 0;
>   	}
>   
> +	if (!strcmp(var, "rebase.usebuiltin")) {
> +		opts->use_legacy_rebase = !git_config_bool(var, value);
> +		return 0;
> +	}
> +
>   	return git_default_config(var, value, data);
>   }
>   
> @@ -1143,22 +1126,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>   	};
>   	int i;
>   
> -	/*
> -	 * NEEDSWORK: Once the builtin rebase has been tested enough
> -	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
> -	 * can be removed.
> -	 */
> -
> -	if (!use_builtin_rebase()) {
> -		const char *path = mkpath("%s/git-legacy-rebase",
> -					  git_exec_path());
> -
> -		if (sane_execvp(path, (char **)argv) < 0)
> -			die_errno(_("could not exec %s"), path);
> -		else
> -			BUG("sane_execvp() returned???");
> -	}
> -
>   	if (argc == 2 && !strcmp(argv[1], "-h"))
>   		usage_with_options(builtin_rebase_usage,
>   				   builtin_rebase_options);
> @@ -1169,6 +1136,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>   
>   	git_config(rebase_config, &options);
>   
> +	if (options.use_legacy_rebase ||
> +	    !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
> +		warning(_("the rebase.useBuiltin support has been removed!\n"
> +			  "See its entry in 'git help config' for details."));
> +
>   	strbuf_reset(&buf);
>   	strbuf_addf(&buf, "%s/applying", apply_dir());
>   	if(file_exists(buf.buf))
> diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh
> deleted file mode 100755
> index 5c2c4e5276..0000000000
> --- a/git-legacy-rebase.sh
> +++ /dev/null
> @@ -1,770 +0,0 @@
> -#!/bin/sh
> -#
> -# Copyright (c) 2005 Junio C Hamano.
> -#
> -
> -SUBDIRECTORY_OK=Yes
> -OPTIONS_KEEPDASHDASH=
> -OPTIONS_STUCKLONG=t
> -OPTIONS_SPEC="\
> -git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
> -git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
> -git rebase --continue | --abort | --skip | --edit-todo
> ---
> - Available options are
> -v,verbose!         display a diffstat of what changed upstream
> -q,quiet!           be quiet. implies --no-stat
> -autostash          automatically stash/stash pop before and after
> -fork-point         use 'merge-base --fork-point' to refine upstream
> -onto=!             rebase onto given branch instead of upstream
> -r,rebase-merges?   try to rebase merges instead of skipping them
> -p,preserve-merges! try to recreate merges instead of ignoring them
> -s,strategy=!       use the given merge strategy
> -X,strategy-option=! pass the argument through to the merge strategy
> -no-ff!             cherry-pick all commits, even if unchanged
> -f,force-rebase!    cherry-pick all commits, even if unchanged
> -m,merge!           use merging strategies to rebase
> -i,interactive!     let the user edit the list of commits to rebase
> -x,exec=!           add exec lines after each commit of the editable list
> -k,keep-empty	   preserve empty commits during rebase
> -allow-empty-message allow rebasing commits with empty messages
> -stat!              display a diffstat of what changed upstream
> -n,no-stat!         do not show diffstat of what changed upstream
> -verify             allow pre-rebase hook to run
> -rerere-autoupdate  allow rerere to update index with resolved conflicts
> -root!              rebase all reachable commits up to the root(s)
> -autosquash         move commits that begin with squash!/fixup! under -i
> -signoff            add a Signed-off-by: line to each commit
> -committer-date-is-author-date! passed to 'git am'
> -ignore-date!       passed to 'git am'
> -whitespace=!       passed to 'git apply'
> -ignore-whitespace! passed to 'git apply'
> -C=!                passed to 'git apply'
> -S,gpg-sign?        GPG-sign commits
> - Actions:
> -continue!          continue
> -abort!             abort and check out the original branch
> -skip!              skip current patch and continue
> -edit-todo!         edit the todo list during an interactive rebase
> -quit!              abort but keep HEAD where it is
> -show-current-patch! show the patch file being applied or merged
> -reschedule-failed-exec automatically reschedule failed exec commands
> -"
> -. git-sh-setup
> -set_reflog_action rebase
> -require_work_tree_exists
> -cd_to_toplevel
> -
> -LF='
> -'
> -ok_to_skip_pre_rebase=
> -
> -squash_onto=
> -unset onto
> -unset restrict_revision
> -cmd=
> -strategy=
> -strategy_opts=
> -do_merge=
> -merge_dir="$GIT_DIR"/rebase-merge
> -apply_dir="$GIT_DIR"/rebase-apply
> -verbose=
> -diffstat=
> -test "$(git config --bool rebase.stat)" = true && diffstat=t
> -autostash="$(git config --bool rebase.autostash || echo false)"
> -fork_point=auto
> -git_am_opt=
> -git_format_patch_opt=
> -rebase_root=
> -force_rebase=
> -allow_rerere_autoupdate=
> -# Non-empty if a rebase was in progress when 'git rebase' was invoked
> -in_progress=
> -# One of {am, merge, interactive}
> -type=
> -# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
> -state_dir=
> -# One of {'', continue, skip, abort}, as parsed from command line
> -action=
> -rebase_merges=
> -rebase_cousins=
> -preserve_merges=
> -autosquash=
> -keep_empty=
> -allow_empty_message=--allow-empty-message
> -signoff=
> -reschedule_failed_exec=
> -test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
> -case "$(git config --bool commit.gpgsign)" in
> -true)	gpg_sign_opt=-S ;;
> -*)	gpg_sign_opt= ;;
> -esac
> -test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
> -reschedule_failed_exec=--reschedule-failed-exec
> -. git-rebase--common
> -
> -read_basic_state () {
> -	test -f "$state_dir/head-name" &&
> -	test -f "$state_dir/onto" &&
> -	head_name=$(cat "$state_dir"/head-name) &&
> -	onto=$(cat "$state_dir"/onto) &&
> -	# We always write to orig-head, but interactive rebase used to write to
> -	# head. Fall back to reading from head to cover for the case that the
> -	# user upgraded git with an ongoing interactive rebase.
> -	if test -f "$state_dir"/orig-head
> -	then
> -		orig_head=$(cat "$state_dir"/orig-head)
> -	else
> -		orig_head=$(cat "$state_dir"/head)
> -	fi &&
> -	test -f "$state_dir"/quiet && GIT_QUIET=t
> -	test -f "$state_dir"/verbose && verbose=t
> -	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
> -	test -f "$state_dir"/strategy_opts &&
> -		strategy_opts="$(cat "$state_dir"/strategy_opts)"
> -	test -f "$state_dir"/allow_rerere_autoupdate &&
> -		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
> -	test -f "$state_dir"/gpg_sign_opt &&
> -		gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
> -	test -f "$state_dir"/signoff && {
> -		signoff="$(cat "$state_dir"/signoff)"
> -		force_rebase=t
> -	}
> -	test -f "$state_dir"/reschedule-failed-exec &&
> -		reschedule_failed_exec=t
> -}
> -
> -finish_rebase () {
> -	rm -f "$(git rev-parse --git-path REBASE_HEAD)"
> -	apply_autostash &&
> -	{ git gc --auto || true; } &&
> -	rm -rf "$state_dir"
> -}
> -
> -run_interactive () {
> -	GIT_CHERRY_PICK_HELP="$resolvemsg"
> -	export GIT_CHERRY_PICK_HELP
> -
> -	test -n "$keep_empty" && keep_empty="--keep-empty"
> -	test -n "$rebase_merges" && rebase_merges="--rebase-merges"
> -	test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
> -	test -n "$autosquash" && autosquash="--autosquash"
> -	test -n "$verbose" && verbose="--verbose"
> -	test -n "$force_rebase" && force_rebase="--no-ff"
> -	test -n "$restrict_revision" && \
> -		restrict_revision="--restrict-revision=^$restrict_revision"
> -	test -n "$upstream" && upstream="--upstream=$upstream"
> -	test -n "$onto" && onto="--onto=$onto"
> -	test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
> -	test -n "$onto_name" && onto_name="--onto-name=$onto_name"
> -	test -n "$head_name" && head_name="--head-name=$head_name"
> -	test -n "$strategy" && strategy="--strategy=$strategy"
> -	test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
> -	test -n "$switch_to" && switch_to="--switch-to=$switch_to"
> -	test -n "$cmd" && cmd="--cmd=$cmd"
> -	test -n "$action" && action="--$action"
> -
> -	exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
> -		"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
> -		"$allow_empty_message" "$autosquash" "$verbose" \
> -		"$force_rebase" "$onto_name" "$head_name" "$strategy" \
> -		"$strategy_opts" "$cmd" "$switch_to" \
> -		"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
> -		"$reschedule_failed_exec"
> -}
> -
> -run_specific_rebase () {
> -	if [ "$interactive_rebase" = implied ]; then
> -		GIT_SEQUENCE_EDITOR=:
> -		export GIT_SEQUENCE_EDITOR
> -		autosquash=
> -	fi
> -
> -	if test -n "$interactive_rebase" -a -z "$preserve_merges"
> -	then
> -		run_interactive
> -	else
> -		. git-rebase--$type
> -
> -		if test -z "$preserve_merges"
> -		then
> -			git_rebase__$type
> -		else
> -			git_rebase__preserve_merges
> -		fi
> -	fi
> -
> -	ret=$?
> -	if test $ret -eq 0
> -	then
> -		finish_rebase
> -	elif test $ret -eq 2 # special exit status for rebase -p
> -	then
> -		apply_autostash &&
> -		rm -rf "$state_dir" &&
> -		die "Nothing to do"
> -	fi
> -	exit $ret
> -}
> -
> -run_pre_rebase_hook () {
> -	if test -z "$ok_to_skip_pre_rebase" &&
> -	   test -x "$(git rev-parse --git-path hooks/pre-rebase)"
> -	then
> -		"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
> -		die "$(gettext "The pre-rebase hook refused to rebase.")"
> -	fi
> -}
> -
> -test -f "$apply_dir"/applying &&
> -	die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
> -
> -if test -d "$apply_dir"
> -then
> -	type=am
> -	state_dir="$apply_dir"
> -elif test -d "$merge_dir"
> -then
> -	type=interactive
> -	if test -d "$merge_dir"/rewritten
> -	then
> -		type=preserve-merges
> -		interactive_rebase=explicit
> -		preserve_merges=t
> -	elif test -f "$merge_dir"/interactive
> -	then
> -		interactive_rebase=explicit
> -	fi
> -	state_dir="$merge_dir"
> -fi
> -test -n "$type" && in_progress=t
> -
> -total_argc=$#
> -while test $# != 0
> -do
> -	case "$1" in
> -	--no-verify)
> -		ok_to_skip_pre_rebase=yes
> -		;;
> -	--verify)
> -		ok_to_skip_pre_rebase=
> -		;;
> -	--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
> -		test $total_argc -eq 2 || usage
> -		action=${1##--}
> -		;;
> -	--onto=*)
> -		onto="${1#--onto=}"
> -		;;
> -	--exec=*)
> -		cmd="${cmd}exec ${1#--exec=}${LF}"
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--interactive)
> -		interactive_rebase=explicit
> -		;;
> -	--keep-empty)
> -		keep_empty=yes
> -		;;
> -	--allow-empty-message)
> -		allow_empty_message=--allow-empty-message
> -		;;
> -	--no-keep-empty)
> -		keep_empty=
> -		;;
> -	--rebase-merges)
> -		rebase_merges=t
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--rebase-merges=*)
> -		rebase_merges=t
> -		case "${1#*=}" in
> -		rebase-cousins) rebase_cousins=t;;
> -		no-rebase-cousins) rebase_cousins=;;
> -		*) die "Unknown mode: $1";;
> -		esac
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--preserve-merges)
> -		preserve_merges=t
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--autosquash)
> -		autosquash=t
> -		;;
> -	--no-autosquash)
> -		autosquash=
> -		;;
> -	--fork-point)
> -		fork_point=t
> -		;;
> -	--no-fork-point)
> -		fork_point=
> -		;;
> -	--merge)
> -		do_merge=t
> -		;;
> -	--strategy-option=*)
> -		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
> -		do_merge=t
> -		test -z "$strategy" && strategy=recursive
> -		;;
> -	--strategy=*)
> -		strategy="${1#--strategy=}"
> -		do_merge=t
> -		;;
> -	--no-stat)
> -		diffstat=
> -		;;
> -	--stat)
> -		diffstat=t
> -		;;
> -	--autostash)
> -		autostash=true
> -		;;
> -	--no-autostash)
> -		autostash=false
> -		;;
> -	--verbose)
> -		verbose=t
> -		diffstat=t
> -		GIT_QUIET=
> -		;;
> -	--quiet)
> -		GIT_QUIET=t
> -		git_am_opt="$git_am_opt -q"
> -		verbose=
> -		diffstat=
> -		;;
> -	--whitespace=*)
> -		git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
> -		case "${1#--whitespace=}" in
> -		fix|strip)
> -			force_rebase=t
> -			;;
> -		warn|nowarn|error|error-all)
> -			;; # okay, known whitespace option
> -		*)
> -			die "fatal: Invalid whitespace option: '${1#*=}'"
> -			;;
> -		esac
> -		;;
> -	--ignore-whitespace)
> -		git_am_opt="$git_am_opt $1"
> -		;;
> -	--signoff)
> -		signoff=--signoff
> -		;;
> -	--no-signoff)
> -		signoff=
> -		;;
> -	--committer-date-is-author-date|--ignore-date)
> -		git_am_opt="$git_am_opt $1"
> -		force_rebase=t
> -		;;
> -	-C*[!0-9]*)
> -		die "fatal: switch \`C' expects a numerical value"
> -		;;
> -	-C*)
> -		git_am_opt="$git_am_opt $1"
> -		;;
> -	--root)
> -		rebase_root=t
> -		;;
> -	--force-rebase|--no-ff)
> -		force_rebase=t
> -		;;
> -	--rerere-autoupdate|--no-rerere-autoupdate)
> -		allow_rerere_autoupdate="$1"
> -		;;
> -	--gpg-sign)
> -		gpg_sign_opt=-S
> -		;;
> -	--gpg-sign=*)
> -		gpg_sign_opt="-S${1#--gpg-sign=}"
> -		;;
> -	--reschedule-failed-exec)
> -		reschedule_failed_exec=--reschedule-failed-exec
> -		;;
> -	--no-reschedule-failed-exec)
> -		reschedule_failed_exec=
> -		;;
> -	--)
> -		shift
> -		break
> -		;;
> -	*)
> -		usage
> -		;;
> -	esac
> -	shift
> -done
> -test $# -gt 2 && usage
> -
> -if test -n "$action"
> -then
> -	test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
> -	# Only interactive rebase uses detailed reflog messages
> -	if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
> -	then
> -		GIT_REFLOG_ACTION="rebase -i ($action)"
> -		export GIT_REFLOG_ACTION
> -	fi
> -fi
> -
> -if test "$action" = "edit-todo" && test -z "$interactive_rebase"
> -then
> -	die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
> -fi
> -
> -case "$action" in
> -continue)
> -	# Sanity check
> -	git rev-parse --verify HEAD >/dev/null ||
> -		die "$(gettext "Cannot read HEAD")"
> -	git update-index --ignore-submodules --refresh &&
> -	git diff-files --quiet --ignore-submodules || {
> -		echo "$(gettext "You must edit all merge conflicts and then
> -mark them as resolved using git add")"
> -		exit 1
> -	}
> -	read_basic_state
> -	run_specific_rebase
> -	;;
> -skip)
> -	output git reset --hard HEAD || exit $?
> -	read_basic_state
> -	run_specific_rebase
> -	;;
> -abort)
> -	git rerere clear
> -	read_basic_state
> -	case "$head_name" in
> -	refs/*)
> -		git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
> -		die "$(eval_gettext "Could not move back to \$head_name")"
> -		;;
> -	esac
> -	output git reset --hard $orig_head
> -	finish_rebase
> -	exit
> -	;;
> -quit)
> -	exec rm -rf "$state_dir"
> -	;;
> -edit-todo)
> -	run_specific_rebase
> -	;;
> -show-current-patch)
> -	run_specific_rebase
> -	die "BUG: run_specific_rebase is not supposed to return here"
> -	;;
> -esac
> -
> -# Make sure no rebase is in progress
> -if test -n "$in_progress"
> -then
> -	state_dir_base=${state_dir##*/}
> -	cmd_live_rebase="git rebase (--continue | --abort | --skip)"
> -	cmd_clear_stale_rebase="rm -fr \"$state_dir\""
> -	die "
> -$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
> -I wonder if you are in the middle of another rebase.  If that is the
> -case, please try
> -	$cmd_live_rebase
> -If that is not the case, please
> -	$cmd_clear_stale_rebase
> -and run me again.  I am stopping in case you still have something
> -valuable there.')"
> -fi
> -
> -if test -n "$rebase_root" && test -z "$onto"
> -then
> -	test -z "$interactive_rebase" && interactive_rebase=implied
> -fi
> -
> -if test -n "$keep_empty"
> -then
> -	test -z "$interactive_rebase" && interactive_rebase=implied
> -fi
> -
> -actually_interactive=
> -if test -n "$interactive_rebase"
> -then
> -	if test -z "$preserve_merges"
> -	then
> -		type=interactive
> -	else
> -		type=preserve-merges
> -	fi
> -	actually_interactive=t
> -	state_dir="$merge_dir"
> -elif test -n "$do_merge"
> -then
> -	interactive_rebase=implied
> -	type=interactive
> -	state_dir="$merge_dir"
> -else
> -	type=am
> -	state_dir="$apply_dir"
> -fi
> -
> -if test -t 2 && test -z "$GIT_QUIET"
> -then
> -	git_format_patch_opt="$git_format_patch_opt --progress"
> -fi
> -
> -incompatible_opts=$(echo " $git_am_opt " | \
> -		    sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
> -if test -n "$incompatible_opts"
> -then
> -	if test -n "$actually_interactive" || test "$do_merge"
> -	then
> -		die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
> -	fi
> -fi
> -
> -if test -n "$signoff"
> -then
> -	test -n "$preserve_merges" &&
> -		die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
> -	git_am_opt="$git_am_opt $signoff"
> -	force_rebase=t
> -fi
> -
> -if test -n "$preserve_merges"
> -then
> -	# Note: incompatibility with --signoff handled in signoff block above
> -	# Note: incompatibility with --interactive is just a strong warning;
> -	#       git-rebase.txt caveats with "unless you know what you are doing"
> -	test -n "$rebase_merges" &&
> -		die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
> -
> -	test -n "$reschedule_failed_exec" &&
> -		die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
> -fi
> -
> -if test -n "$rebase_merges"
> -then
> -	test -n "$strategy_opts" &&
> -		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
> -	test -n "$strategy" &&
> -		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
> -fi
> -
> -if test -z "$rebase_root"
> -then
> -	case "$#" in
> -	0)
> -		if ! upstream_name=$(git rev-parse --symbolic-full-name \
> -			--verify -q @{upstream} 2>/dev/null)
> -		then
> -			. git-parse-remote
> -			error_on_missing_default_upstream "rebase" "rebase" \
> -				"against" "git rebase $(gettext '<branch>')"
> -		fi
> -
> -		test "$fork_point" = auto && fork_point=t
> -		;;
> -	*)	upstream_name="$1"
> -		if test "$upstream_name" = "-"
> -		then
> -			upstream_name="@{-1}"
> -		fi
> -		shift
> -		;;
> -	esac
> -	upstream=$(peel_committish "${upstream_name}") ||
> -	die "$(eval_gettext "invalid upstream '\$upstream_name'")"
> -	upstream_arg="$upstream_name"
> -else
> -	if test -z "$onto"
> -	then
> -		empty_tree=$(git hash-object -t tree /dev/null)
> -		onto=$(git commit-tree $empty_tree </dev/null)
> -		squash_onto="$onto"
> -	fi
> -	unset upstream_name
> -	unset upstream
> -	test $# -gt 1 && usage
> -	upstream_arg=--root
> -fi
> -
> -# Make sure the branch to rebase onto is valid.
> -onto_name=${onto-"$upstream_name"}
> -case "$onto_name" in
> -*...*)
> -	if	left=${onto_name%...*} right=${onto_name#*...} &&
> -		onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
> -	then
> -		case "$onto" in
> -		?*"$LF"?*)
> -			die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
> -			;;
> -		'')
> -			die "$(eval_gettext "\$onto_name: there is no merge base")"
> -			;;
> -		esac
> -	else
> -		die "$(eval_gettext "\$onto_name: there is no merge base")"
> -	fi
> -	;;
> -*)
> -	onto=$(peel_committish "$onto_name") ||
> -	die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
> -	;;
> -esac
> -
> -# If the branch to rebase is given, that is the branch we will rebase
> -# $branch_name -- branch/commit being rebased, or HEAD (already detached)
> -# $orig_head -- commit object name of tip of the branch before rebasing
> -# $head_name -- refs/heads/<that-branch> or "detached HEAD"
> -switch_to=
> -case "$#" in
> -1)
> -	# Is it "rebase other $branchname" or "rebase other $commit"?
> -	branch_name="$1"
> -	switch_to="$1"
> -
> -	# Is it a local branch?
> -	if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
> -	   orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
> -	then
> -		head_name="refs/heads/$branch_name"
> -	# If not is it a valid ref (branch or commit)?
> -	elif orig_head=$(git rev-parse -q --verify "$branch_name")
> -	then
> -		head_name="detached HEAD"
> -
> -	else
> -		die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
> -	fi
> -	;;
> -0)
> -	# Do not need to switch branches, we are already on it.
> -	if branch_name=$(git symbolic-ref -q HEAD)
> -	then
> -		head_name=$branch_name
> -		branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
> -	else
> -		head_name="detached HEAD"
> -		branch_name=HEAD
> -	fi
> -	orig_head=$(git rev-parse --verify HEAD) || exit
> -	;;
> -*)
> -	die "BUG: unexpected number of arguments left to parse"
> -	;;
> -esac
> -
> -if test "$fork_point" = t
> -then
> -	new_upstream=$(git merge-base --fork-point "$upstream_name" \
> -			"${switch_to:-HEAD}")
> -	if test -n "$new_upstream"
> -	then
> -		restrict_revision=$new_upstream
> -	fi
> -fi
> -
> -if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
> -then
> -	stash_sha1=$(git stash create "autostash") ||
> -	die "$(gettext 'Cannot autostash')"
> -
> -	mkdir -p "$state_dir" &&
> -	echo $stash_sha1 >"$state_dir/autostash" &&
> -	stash_abbrev=$(git rev-parse --short $stash_sha1) &&
> -	echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
> -	git reset --hard
> -fi
> -
> -require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
> -
> -# Now we are rebasing commits $upstream..$orig_head (or with --root,
> -# everything leading up to $orig_head) on top of $onto
> -
> -# Check if we are already based on $onto with linear history,
> -# but this should be done only when upstream and onto are the same
> -# and if this is not an interactive rebase.
> -mb=$(git merge-base "$onto" "$orig_head")
> -if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
> -	test "$mb" = "$onto" && test -z "$restrict_revision" &&
> -	# linear history?
> -	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
> -then
> -	if test -z "$force_rebase"
> -	then
> -		# Lazily switch to the target branch if needed...
> -		test -z "$switch_to" ||
> -		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
> -			git checkout -q "$switch_to" --
> -		if test "$branch_name" = "HEAD" &&
> -			 ! git symbolic-ref -q HEAD
> -		then
> -			say "$(eval_gettext "HEAD is up to date.")"
> -		else
> -			say "$(eval_gettext "Current branch \$branch_name is up to date.")"
> -		fi
> -		finish_rebase
> -		exit 0
> -	else
> -		if test "$branch_name" = "HEAD" &&
> -			 ! git symbolic-ref -q HEAD
> -		then
> -			say "$(eval_gettext "HEAD is up to date, rebase forced.")"
> -		else
> -			say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
> -		fi
> -	fi
> -fi
> -
> -# If a hook exists, give it a chance to interrupt
> -run_pre_rebase_hook "$upstream_arg" "$@"
> -
> -if test -n "$diffstat"
> -then
> -	if test -n "$verbose"
> -	then
> -		if test -z "$mb"
> -		then
> -			echo "$(eval_gettext "Changes to \$onto:")"
> -		else
> -			echo "$(eval_gettext "Changes from \$mb to \$onto:")"
> -		fi
> -	fi
> -	mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
> -	# We want color (if set), but no pager
> -	GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
> -fi
> -
> -if test -z "$actually_interactive" && test "$mb" = "$orig_head"
> -then
> -	say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
> -	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
> -		git checkout -q "$onto^0" || die "could not detach HEAD"
> -	# If the $onto is a proper descendant of the tip of the branch, then
> -	# we just fast-forwarded.
> -	git update-ref ORIG_HEAD $orig_head
> -	move_to_original_branch
> -	finish_rebase
> -	exit 0
> -fi
> -
> -test -n "$interactive_rebase" && run_specific_rebase
> -
> -# Detach HEAD and reset the tree
> -say "$(gettext "First, rewinding head to replay your work on top of it...")"
> -
> -GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
> -	git checkout -q "$onto^0" || die "could not detach HEAD"
> -git update-ref ORIG_HEAD $orig_head
> -
> -if test -n "$rebase_root"
> -then
> -	revisions="$onto..$orig_head"
> -else
> -	revisions="${restrict_revision-$upstream}..$orig_head"
> -fi
> -
> -run_specific_rebase
> diff --git a/t/README b/t/README
> index 7a3d582267..385262357b 100644
> --- a/t/README
> +++ b/t/README
> @@ -379,10 +379,6 @@ the --no-sparse command-line argument.
>   GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
>   by overriding the minimum number of cache entries required per thread.
>   
> -GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the
> -builtin version of git-rebase. See 'rebase.useBuiltin' in
> -git-config(1).
> -
>   GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
>   of the index for the whole test suite by bypassing the default number of
>   cache entries and thread minimums. Setting this to 1 will make the
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 3e73f7584c..a809de9304 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -311,4 +311,20 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
>   	)
>   '
>   
> +test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
> +	expected="rebase.useBuiltin support has been removed" &&
> +
> +	# Only warn when the legacy rebase is requested...
> +	test_must_fail git -c rebase.useBuiltin=false rebase 2>err &&
> +	test_i18ngrep "$expected" err &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err &&
> +	test_i18ngrep "$expected" err &&
> +
> +	# ...not when we would have used the built-in anyway
> +	test_must_fail git -c rebase.useBuiltin=true rebase 2>err &&
> +	test_must_be_empty err &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err &&
> +	test_must_be_empty err
> +'
> +
>   test_done
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index b60b11f9f2..1723e1a858 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>   
>   test_expect_success 'rebase -x with empty command fails' '
>   	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x "" @ 2>actual &&
> +	test_must_fail env git rebase -x "" @ 2>actual &&
>   	test_write_lines "error: empty exec command" >expected &&
>   	test_i18ncmp expected actual &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x " " @ 2>actual &&
> +	test_must_fail env git rebase -x " " @ 2>actual &&
>   	test_i18ncmp expected actual
>   '
>   
> @@ -162,8 +160,7 @@ LF='
>   '
>   test_expect_success 'rebase -x with newline in command fails' '
>   	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x "a${LF}b" @ 2>actual &&
> +	test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
>   	test_write_lines "error: exec commands cannot contain newlines" \
>   			 >expected &&
>   	test_i18ncmp expected actual
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v4] rebase: remove the rebase.useBuiltin setting
  2019-03-18 10:19                     ` Phillip Wood
@ 2019-03-18 11:01                       ` Ævar Arnfjörð Bjarmason
  2019-03-19 10:21                         ` Phillip Wood
  2021-03-23 15:23                         ` [PATCH] rebase: remove transitory rebase.useBuiltin setting & env Ævar Arnfjörð Bjarmason
  0 siblings, 2 replies; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2019-03-18 11:01 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason, Johannes Schindelin

Remove the rebase.useBuiltin setting, which was added as an escape
hatch to disable the builtin version of rebase first released with Git
2.20.

See [1] for the initial implementation of rebase.useBuiltin, and [2]
and [3] for the documentation and corresponding
GIT_TEST_REBASE_USE_BUILTIN option.

Carrying the legacy version is a maintenance burden as seen in
7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
version has been shown to be stable enough let's remove the legacy
version.

As noted in [3] having use_builtin_rebase() shell out to get its
config doesn't make any sense anymore, that was done for the purposes
of spawning the legacy rebase without having modified any global
state. Let's instead handle this case in rebase_config().

There's still a bunch of references to git-legacy-rebase in po/*.po,
but those will be dealt with in time by the i18n effort.

Even though this configuration variable only existed two releases
let's not entirely delete the entry from the docs, but note its
absence. Individual versions of git tend to be around for a while due
to distro packaging timelines, so e.g. if we're "lucky" a given
version like 2.21 might be installed on say OSX for half a decade.

That'll mean some people probably setting this in config, and then
when they later wonder if it's needed they can Google search the
config option name or check it in git-config. It also allows us to
refer to the docs from the warning for details.

1. 55071ea248 ("rebase: start implementing it as a builtin",
   2018-08-07)
2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
   off", 2018-11-14)
3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/

Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---

Fix wording issues pointed out by Phillip & incorporated the Acked-by
in Junio's push-out & added my SOB.

The confusion with "one release" was a) I'd initially written this
before 2.21 was cut and forgot to change that 2) I was then using
"between" in the inclusive sense "pick a number between 1 and
10". Phillip's suggestion is better.

Range-diff:
1:  799dd15e4fd ! 1:  9ca747cb1f5 rebase: remove the rebase.useBuiltin setting
    @@ -25,7 +25,7 @@
         There's still a bunch of references to git-legacy-rebase in po/*.po,
         but those will be dealt with in time by the i18n effort.
     
    -    Even though this configuration variable only existed for one release
    +    Even though this configuration variable only existed two releases
         let's not entirely delete the entry from the docs, but note its
         absence. Individual versions of git tend to be around for a while due
         to distro packaging timelines, so e.g. if we're "lucky" a given
    @@ -43,6 +43,9 @@
            off", 2018-11-14)
         3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/
     
    +    Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de>
    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
    +
      diff --git a/.gitignore b/.gitignore
      --- a/.gitignore
      +++ b/.gitignore
    @@ -72,8 +75,8 @@
     -If you find some reason to set this option to `false` other than
     -one-off testing you should report the behavior difference as a bug in
     -git.
    -+	Unused configuration variable. Used between Git version 2.20
    -+	and 2.21 as an escape hatch to enable the legacy shellscript
    ++	Unused configuration variable. Used in Git versions 2.20 and
    ++	2.21 as an escape hatch to enable the legacy shellscript
     +	implementation of rebase. Now the built-in rewrite of it in C
     +	is always used. Setting this will emit a warning, to alert any
     +	remaining users that setting this now does nothing.

 .gitignore                      |   1 -
 Documentation/config/rebase.txt |  17 +-
 Makefile                        |   1 -
 builtin/rebase.c                |  50 +--
 git-legacy-rebase.sh            | 770 --------------------------------
 t/README                        |   4 -
 t/t3400-rebase.sh               |  16 +
 t/t3404-rebase-interactive.sh   |   9 +-
 8 files changed, 35 insertions(+), 833 deletions(-)
 delete mode 100755 git-legacy-rebase.sh

diff --git a/.gitignore b/.gitignore
index 7374587f9df..5cb84f1d1a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,7 +82,6 @@
 /git-init-db
 /git-interpret-trailers
 /git-instaweb
-/git-legacy-rebase
 /git-log
 /git-ls-files
 /git-ls-remote
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 331d250e046..d98e32d812e 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -1,16 +1,9 @@
 rebase.useBuiltin::
-	Set to `false` to use the legacy shellscript implementation of
-	linkgit:git-rebase[1]. Is `true` by default, which means use
-	the built-in rewrite of it in C.
-+
-The C rewrite is first included with Git version 2.20. This option
-serves an an escape hatch to re-enable the legacy version in case any
-bugs are found in the rewrite. This option and the shellscript version
-of linkgit:git-rebase[1] will be removed in some future release.
-+
-If you find some reason to set this option to `false` other than
-one-off testing you should report the behavior difference as a bug in
-git.
+	Unused configuration variable. Used in Git versions 2.20 and
+	2.21 as an escape hatch to enable the legacy shellscript
+	implementation of rebase. Now the built-in rewrite of it in C
+	is always used. Setting this will emit a warning, to alert any
+	remaining users that setting this now does nothing.
 
 rebase.stat::
 	Whether to show a diffstat of what changed upstream since the last
diff --git a/Makefile b/Makefile
index 537493822b1..9f1159cffcb 100644
--- a/Makefile
+++ b/Makefile
@@ -632,7 +632,6 @@ SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-legacy-rebase.sh
 SCRIPT_SH += git-remote-testgit.sh
 SCRIPT_SH += git-request-pull.sh
 SCRIPT_SH += git-stash.sh
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 52114cbf0d9..bc3dc629c16 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -46,29 +46,6 @@ enum rebase_type {
 	REBASE_PRESERVE_MERGES
 };
 
-static int use_builtin_rebase(void)
-{
-	struct child_process cp = CHILD_PROCESS_INIT;
-	struct strbuf out = STRBUF_INIT;
-	int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1);
-
-	if (env != -1)
-		return env;
-
-	argv_array_pushl(&cp.args,
-			 "config", "--bool", "rebase.usebuiltin", NULL);
-	cp.git_cmd = 1;
-	if (capture_command(&cp, &out, 6)) {
-		strbuf_release(&out);
-		return 1;
-	}
-
-	strbuf_trim(&out);
-	ret = !strcmp("true", out.buf);
-	strbuf_release(&out);
-	return ret;
-}
-
 struct rebase_options {
 	enum rebase_type type;
 	const char *state_dir;
@@ -106,6 +83,7 @@ struct rebase_options {
 	char *strategy, *strategy_opts;
 	struct strbuf git_format_patch_opt;
 	int reschedule_failed_exec;
+	int use_legacy_rebase;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -869,6 +847,11 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "rebase.usebuiltin")) {
+		opts->use_legacy_rebase = !git_config_bool(var, value);
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -1143,22 +1126,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	};
 	int i;
 
-	/*
-	 * NEEDSWORK: Once the builtin rebase has been tested enough
-	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
-	 * can be removed.
-	 */
-
-	if (!use_builtin_rebase()) {
-		const char *path = mkpath("%s/git-legacy-rebase",
-					  git_exec_path());
-
-		if (sane_execvp(path, (char **)argv) < 0)
-			die_errno(_("could not exec %s"), path);
-		else
-			BUG("sane_execvp() returned???");
-	}
-
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_rebase_usage,
 				   builtin_rebase_options);
@@ -1169,6 +1136,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	git_config(rebase_config, &options);
 
+	if (options.use_legacy_rebase ||
+	    !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
+		warning(_("the rebase.useBuiltin support has been removed!\n"
+			  "See its entry in 'git help config' for details."));
+
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "%s/applying", apply_dir());
 	if(file_exists(buf.buf))
diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh
deleted file mode 100755
index 5c2c4e5276d..00000000000
--- a/git-legacy-rebase.sh
+++ /dev/null
@@ -1,770 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano.
-#
-
-SUBDIRECTORY_OK=Yes
-OPTIONS_KEEPDASHDASH=
-OPTIONS_STUCKLONG=t
-OPTIONS_SPEC="\
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
-git rebase --continue | --abort | --skip | --edit-todo
---
- Available options are
-v,verbose!         display a diffstat of what changed upstream
-q,quiet!           be quiet. implies --no-stat
-autostash          automatically stash/stash pop before and after
-fork-point         use 'merge-base --fork-point' to refine upstream
-onto=!             rebase onto given branch instead of upstream
-r,rebase-merges?   try to rebase merges instead of skipping them
-p,preserve-merges! try to recreate merges instead of ignoring them
-s,strategy=!       use the given merge strategy
-X,strategy-option=! pass the argument through to the merge strategy
-no-ff!             cherry-pick all commits, even if unchanged
-f,force-rebase!    cherry-pick all commits, even if unchanged
-m,merge!           use merging strategies to rebase
-i,interactive!     let the user edit the list of commits to rebase
-x,exec=!           add exec lines after each commit of the editable list
-k,keep-empty	   preserve empty commits during rebase
-allow-empty-message allow rebasing commits with empty messages
-stat!              display a diffstat of what changed upstream
-n,no-stat!         do not show diffstat of what changed upstream
-verify             allow pre-rebase hook to run
-rerere-autoupdate  allow rerere to update index with resolved conflicts
-root!              rebase all reachable commits up to the root(s)
-autosquash         move commits that begin with squash!/fixup! under -i
-signoff            add a Signed-off-by: line to each commit
-committer-date-is-author-date! passed to 'git am'
-ignore-date!       passed to 'git am'
-whitespace=!       passed to 'git apply'
-ignore-whitespace! passed to 'git apply'
-C=!                passed to 'git apply'
-S,gpg-sign?        GPG-sign commits
- Actions:
-continue!          continue
-abort!             abort and check out the original branch
-skip!              skip current patch and continue
-edit-todo!         edit the todo list during an interactive rebase
-quit!              abort but keep HEAD where it is
-show-current-patch! show the patch file being applied or merged
-reschedule-failed-exec automatically reschedule failed exec commands
-"
-. git-sh-setup
-set_reflog_action rebase
-require_work_tree_exists
-cd_to_toplevel
-
-LF='
-'
-ok_to_skip_pre_rebase=
-
-squash_onto=
-unset onto
-unset restrict_revision
-cmd=
-strategy=
-strategy_opts=
-do_merge=
-merge_dir="$GIT_DIR"/rebase-merge
-apply_dir="$GIT_DIR"/rebase-apply
-verbose=
-diffstat=
-test "$(git config --bool rebase.stat)" = true && diffstat=t
-autostash="$(git config --bool rebase.autostash || echo false)"
-fork_point=auto
-git_am_opt=
-git_format_patch_opt=
-rebase_root=
-force_rebase=
-allow_rerere_autoupdate=
-# Non-empty if a rebase was in progress when 'git rebase' was invoked
-in_progress=
-# One of {am, merge, interactive}
-type=
-# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
-state_dir=
-# One of {'', continue, skip, abort}, as parsed from command line
-action=
-rebase_merges=
-rebase_cousins=
-preserve_merges=
-autosquash=
-keep_empty=
-allow_empty_message=--allow-empty-message
-signoff=
-reschedule_failed_exec=
-test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
-case "$(git config --bool commit.gpgsign)" in
-true)	gpg_sign_opt=-S ;;
-*)	gpg_sign_opt= ;;
-esac
-test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
-reschedule_failed_exec=--reschedule-failed-exec
-. git-rebase--common
-
-read_basic_state () {
-	test -f "$state_dir/head-name" &&
-	test -f "$state_dir/onto" &&
-	head_name=$(cat "$state_dir"/head-name) &&
-	onto=$(cat "$state_dir"/onto) &&
-	# We always write to orig-head, but interactive rebase used to write to
-	# head. Fall back to reading from head to cover for the case that the
-	# user upgraded git with an ongoing interactive rebase.
-	if test -f "$state_dir"/orig-head
-	then
-		orig_head=$(cat "$state_dir"/orig-head)
-	else
-		orig_head=$(cat "$state_dir"/head)
-	fi &&
-	test -f "$state_dir"/quiet && GIT_QUIET=t
-	test -f "$state_dir"/verbose && verbose=t
-	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
-	test -f "$state_dir"/strategy_opts &&
-		strategy_opts="$(cat "$state_dir"/strategy_opts)"
-	test -f "$state_dir"/allow_rerere_autoupdate &&
-		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
-	test -f "$state_dir"/gpg_sign_opt &&
-		gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
-	test -f "$state_dir"/signoff && {
-		signoff="$(cat "$state_dir"/signoff)"
-		force_rebase=t
-	}
-	test -f "$state_dir"/reschedule-failed-exec &&
-		reschedule_failed_exec=t
-}
-
-finish_rebase () {
-	rm -f "$(git rev-parse --git-path REBASE_HEAD)"
-	apply_autostash &&
-	{ git gc --auto || true; } &&
-	rm -rf "$state_dir"
-}
-
-run_interactive () {
-	GIT_CHERRY_PICK_HELP="$resolvemsg"
-	export GIT_CHERRY_PICK_HELP
-
-	test -n "$keep_empty" && keep_empty="--keep-empty"
-	test -n "$rebase_merges" && rebase_merges="--rebase-merges"
-	test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
-	test -n "$autosquash" && autosquash="--autosquash"
-	test -n "$verbose" && verbose="--verbose"
-	test -n "$force_rebase" && force_rebase="--no-ff"
-	test -n "$restrict_revision" && \
-		restrict_revision="--restrict-revision=^$restrict_revision"
-	test -n "$upstream" && upstream="--upstream=$upstream"
-	test -n "$onto" && onto="--onto=$onto"
-	test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
-	test -n "$onto_name" && onto_name="--onto-name=$onto_name"
-	test -n "$head_name" && head_name="--head-name=$head_name"
-	test -n "$strategy" && strategy="--strategy=$strategy"
-	test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
-	test -n "$switch_to" && switch_to="--switch-to=$switch_to"
-	test -n "$cmd" && cmd="--cmd=$cmd"
-	test -n "$action" && action="--$action"
-
-	exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
-		"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
-		"$allow_empty_message" "$autosquash" "$verbose" \
-		"$force_rebase" "$onto_name" "$head_name" "$strategy" \
-		"$strategy_opts" "$cmd" "$switch_to" \
-		"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
-		"$reschedule_failed_exec"
-}
-
-run_specific_rebase () {
-	if [ "$interactive_rebase" = implied ]; then
-		GIT_SEQUENCE_EDITOR=:
-		export GIT_SEQUENCE_EDITOR
-		autosquash=
-	fi
-
-	if test -n "$interactive_rebase" -a -z "$preserve_merges"
-	then
-		run_interactive
-	else
-		. git-rebase--$type
-
-		if test -z "$preserve_merges"
-		then
-			git_rebase__$type
-		else
-			git_rebase__preserve_merges
-		fi
-	fi
-
-	ret=$?
-	if test $ret -eq 0
-	then
-		finish_rebase
-	elif test $ret -eq 2 # special exit status for rebase -p
-	then
-		apply_autostash &&
-		rm -rf "$state_dir" &&
-		die "Nothing to do"
-	fi
-	exit $ret
-}
-
-run_pre_rebase_hook () {
-	if test -z "$ok_to_skip_pre_rebase" &&
-	   test -x "$(git rev-parse --git-path hooks/pre-rebase)"
-	then
-		"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
-		die "$(gettext "The pre-rebase hook refused to rebase.")"
-	fi
-}
-
-test -f "$apply_dir"/applying &&
-	die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
-
-if test -d "$apply_dir"
-then
-	type=am
-	state_dir="$apply_dir"
-elif test -d "$merge_dir"
-then
-	type=interactive
-	if test -d "$merge_dir"/rewritten
-	then
-		type=preserve-merges
-		interactive_rebase=explicit
-		preserve_merges=t
-	elif test -f "$merge_dir"/interactive
-	then
-		interactive_rebase=explicit
-	fi
-	state_dir="$merge_dir"
-fi
-test -n "$type" && in_progress=t
-
-total_argc=$#
-while test $# != 0
-do
-	case "$1" in
-	--no-verify)
-		ok_to_skip_pre_rebase=yes
-		;;
-	--verify)
-		ok_to_skip_pre_rebase=
-		;;
-	--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
-		test $total_argc -eq 2 || usage
-		action=${1##--}
-		;;
-	--onto=*)
-		onto="${1#--onto=}"
-		;;
-	--exec=*)
-		cmd="${cmd}exec ${1#--exec=}${LF}"
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--interactive)
-		interactive_rebase=explicit
-		;;
-	--keep-empty)
-		keep_empty=yes
-		;;
-	--allow-empty-message)
-		allow_empty_message=--allow-empty-message
-		;;
-	--no-keep-empty)
-		keep_empty=
-		;;
-	--rebase-merges)
-		rebase_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--rebase-merges=*)
-		rebase_merges=t
-		case "${1#*=}" in
-		rebase-cousins) rebase_cousins=t;;
-		no-rebase-cousins) rebase_cousins=;;
-		*) die "Unknown mode: $1";;
-		esac
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--preserve-merges)
-		preserve_merges=t
-		test -z "$interactive_rebase" && interactive_rebase=implied
-		;;
-	--autosquash)
-		autosquash=t
-		;;
-	--no-autosquash)
-		autosquash=
-		;;
-	--fork-point)
-		fork_point=t
-		;;
-	--no-fork-point)
-		fork_point=
-		;;
-	--merge)
-		do_merge=t
-		;;
-	--strategy-option=*)
-		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
-		do_merge=t
-		test -z "$strategy" && strategy=recursive
-		;;
-	--strategy=*)
-		strategy="${1#--strategy=}"
-		do_merge=t
-		;;
-	--no-stat)
-		diffstat=
-		;;
-	--stat)
-		diffstat=t
-		;;
-	--autostash)
-		autostash=true
-		;;
-	--no-autostash)
-		autostash=false
-		;;
-	--verbose)
-		verbose=t
-		diffstat=t
-		GIT_QUIET=
-		;;
-	--quiet)
-		GIT_QUIET=t
-		git_am_opt="$git_am_opt -q"
-		verbose=
-		diffstat=
-		;;
-	--whitespace=*)
-		git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
-		case "${1#--whitespace=}" in
-		fix|strip)
-			force_rebase=t
-			;;
-		warn|nowarn|error|error-all)
-			;; # okay, known whitespace option
-		*)
-			die "fatal: Invalid whitespace option: '${1#*=}'"
-			;;
-		esac
-		;;
-	--ignore-whitespace)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--signoff)
-		signoff=--signoff
-		;;
-	--no-signoff)
-		signoff=
-		;;
-	--committer-date-is-author-date|--ignore-date)
-		git_am_opt="$git_am_opt $1"
-		force_rebase=t
-		;;
-	-C*[!0-9]*)
-		die "fatal: switch \`C' expects a numerical value"
-		;;
-	-C*)
-		git_am_opt="$git_am_opt $1"
-		;;
-	--root)
-		rebase_root=t
-		;;
-	--force-rebase|--no-ff)
-		force_rebase=t
-		;;
-	--rerere-autoupdate|--no-rerere-autoupdate)
-		allow_rerere_autoupdate="$1"
-		;;
-	--gpg-sign)
-		gpg_sign_opt=-S
-		;;
-	--gpg-sign=*)
-		gpg_sign_opt="-S${1#--gpg-sign=}"
-		;;
-	--reschedule-failed-exec)
-		reschedule_failed_exec=--reschedule-failed-exec
-		;;
-	--no-reschedule-failed-exec)
-		reschedule_failed_exec=
-		;;
-	--)
-		shift
-		break
-		;;
-	*)
-		usage
-		;;
-	esac
-	shift
-done
-test $# -gt 2 && usage
-
-if test -n "$action"
-then
-	test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
-	# Only interactive rebase uses detailed reflog messages
-	if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
-	then
-		GIT_REFLOG_ACTION="rebase -i ($action)"
-		export GIT_REFLOG_ACTION
-	fi
-fi
-
-if test "$action" = "edit-todo" && test -z "$interactive_rebase"
-then
-	die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
-fi
-
-case "$action" in
-continue)
-	# Sanity check
-	git rev-parse --verify HEAD >/dev/null ||
-		die "$(gettext "Cannot read HEAD")"
-	git update-index --ignore-submodules --refresh &&
-	git diff-files --quiet --ignore-submodules || {
-		echo "$(gettext "You must edit all merge conflicts and then
-mark them as resolved using git add")"
-		exit 1
-	}
-	read_basic_state
-	run_specific_rebase
-	;;
-skip)
-	output git reset --hard HEAD || exit $?
-	read_basic_state
-	run_specific_rebase
-	;;
-abort)
-	git rerere clear
-	read_basic_state
-	case "$head_name" in
-	refs/*)
-		git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
-		die "$(eval_gettext "Could not move back to \$head_name")"
-		;;
-	esac
-	output git reset --hard $orig_head
-	finish_rebase
-	exit
-	;;
-quit)
-	exec rm -rf "$state_dir"
-	;;
-edit-todo)
-	run_specific_rebase
-	;;
-show-current-patch)
-	run_specific_rebase
-	die "BUG: run_specific_rebase is not supposed to return here"
-	;;
-esac
-
-# Make sure no rebase is in progress
-if test -n "$in_progress"
-then
-	state_dir_base=${state_dir##*/}
-	cmd_live_rebase="git rebase (--continue | --abort | --skip)"
-	cmd_clear_stale_rebase="rm -fr \"$state_dir\""
-	die "
-$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
-I wonder if you are in the middle of another rebase.  If that is the
-case, please try
-	$cmd_live_rebase
-If that is not the case, please
-	$cmd_clear_stale_rebase
-and run me again.  I am stopping in case you still have something
-valuable there.')"
-fi
-
-if test -n "$rebase_root" && test -z "$onto"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-if test -n "$keep_empty"
-then
-	test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-actually_interactive=
-if test -n "$interactive_rebase"
-then
-	if test -z "$preserve_merges"
-	then
-		type=interactive
-	else
-		type=preserve-merges
-	fi
-	actually_interactive=t
-	state_dir="$merge_dir"
-elif test -n "$do_merge"
-then
-	interactive_rebase=implied
-	type=interactive
-	state_dir="$merge_dir"
-else
-	type=am
-	state_dir="$apply_dir"
-fi
-
-if test -t 2 && test -z "$GIT_QUIET"
-then
-	git_format_patch_opt="$git_format_patch_opt --progress"
-fi
-
-incompatible_opts=$(echo " $git_am_opt " | \
-		    sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
-if test -n "$incompatible_opts"
-then
-	if test -n "$actually_interactive" || test "$do_merge"
-	then
-		die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
-	fi
-fi
-
-if test -n "$signoff"
-then
-	test -n "$preserve_merges" &&
-		die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
-	git_am_opt="$git_am_opt $signoff"
-	force_rebase=t
-fi
-
-if test -n "$preserve_merges"
-then
-	# Note: incompatibility with --signoff handled in signoff block above
-	# Note: incompatibility with --interactive is just a strong warning;
-	#       git-rebase.txt caveats with "unless you know what you are doing"
-	test -n "$rebase_merges" &&
-		die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
-
-	test -n "$reschedule_failed_exec" &&
-		die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
-fi
-
-if test -n "$rebase_merges"
-then
-	test -n "$strategy_opts" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
-	test -n "$strategy" &&
-		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
-fi
-
-if test -z "$rebase_root"
-then
-	case "$#" in
-	0)
-		if ! upstream_name=$(git rev-parse --symbolic-full-name \
-			--verify -q @{upstream} 2>/dev/null)
-		then
-			. git-parse-remote
-			error_on_missing_default_upstream "rebase" "rebase" \
-				"against" "git rebase $(gettext '<branch>')"
-		fi
-
-		test "$fork_point" = auto && fork_point=t
-		;;
-	*)	upstream_name="$1"
-		if test "$upstream_name" = "-"
-		then
-			upstream_name="@{-1}"
-		fi
-		shift
-		;;
-	esac
-	upstream=$(peel_committish "${upstream_name}") ||
-	die "$(eval_gettext "invalid upstream '\$upstream_name'")"
-	upstream_arg="$upstream_name"
-else
-	if test -z "$onto"
-	then
-		empty_tree=$(git hash-object -t tree /dev/null)
-		onto=$(git commit-tree $empty_tree </dev/null)
-		squash_onto="$onto"
-	fi
-	unset upstream_name
-	unset upstream
-	test $# -gt 1 && usage
-	upstream_arg=--root
-fi
-
-# Make sure the branch to rebase onto is valid.
-onto_name=${onto-"$upstream_name"}
-case "$onto_name" in
-*...*)
-	if	left=${onto_name%...*} right=${onto_name#*...} &&
-		onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
-	then
-		case "$onto" in
-		?*"$LF"?*)
-			die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
-			;;
-		'')
-			die "$(eval_gettext "\$onto_name: there is no merge base")"
-			;;
-		esac
-	else
-		die "$(eval_gettext "\$onto_name: there is no merge base")"
-	fi
-	;;
-*)
-	onto=$(peel_committish "$onto_name") ||
-	die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
-	;;
-esac
-
-# If the branch to rebase is given, that is the branch we will rebase
-# $branch_name -- branch/commit being rebased, or HEAD (already detached)
-# $orig_head -- commit object name of tip of the branch before rebasing
-# $head_name -- refs/heads/<that-branch> or "detached HEAD"
-switch_to=
-case "$#" in
-1)
-	# Is it "rebase other $branchname" or "rebase other $commit"?
-	branch_name="$1"
-	switch_to="$1"
-
-	# Is it a local branch?
-	if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
-	   orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
-	then
-		head_name="refs/heads/$branch_name"
-	# If not is it a valid ref (branch or commit)?
-	elif orig_head=$(git rev-parse -q --verify "$branch_name")
-	then
-		head_name="detached HEAD"
-
-	else
-		die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
-	fi
-	;;
-0)
-	# Do not need to switch branches, we are already on it.
-	if branch_name=$(git symbolic-ref -q HEAD)
-	then
-		head_name=$branch_name
-		branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
-	else
-		head_name="detached HEAD"
-		branch_name=HEAD
-	fi
-	orig_head=$(git rev-parse --verify HEAD) || exit
-	;;
-*)
-	die "BUG: unexpected number of arguments left to parse"
-	;;
-esac
-
-if test "$fork_point" = t
-then
-	new_upstream=$(git merge-base --fork-point "$upstream_name" \
-			"${switch_to:-HEAD}")
-	if test -n "$new_upstream"
-	then
-		restrict_revision=$new_upstream
-	fi
-fi
-
-if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
-then
-	stash_sha1=$(git stash create "autostash") ||
-	die "$(gettext 'Cannot autostash')"
-
-	mkdir -p "$state_dir" &&
-	echo $stash_sha1 >"$state_dir/autostash" &&
-	stash_abbrev=$(git rev-parse --short $stash_sha1) &&
-	echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
-	git reset --hard
-fi
-
-require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
-
-# Now we are rebasing commits $upstream..$orig_head (or with --root,
-# everything leading up to $orig_head) on top of $onto
-
-# Check if we are already based on $onto with linear history,
-# but this should be done only when upstream and onto are the same
-# and if this is not an interactive rebase.
-mb=$(git merge-base "$onto" "$orig_head")
-if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
-	test "$mb" = "$onto" && test -z "$restrict_revision" &&
-	# linear history?
-	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
-then
-	if test -z "$force_rebase"
-	then
-		# Lazily switch to the target branch if needed...
-		test -z "$switch_to" ||
-		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
-			git checkout -q "$switch_to" --
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date.")"
-		fi
-		finish_rebase
-		exit 0
-	else
-		if test "$branch_name" = "HEAD" &&
-			 ! git symbolic-ref -q HEAD
-		then
-			say "$(eval_gettext "HEAD is up to date, rebase forced.")"
-		else
-			say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
-		fi
-	fi
-fi
-
-# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook "$upstream_arg" "$@"
-
-if test -n "$diffstat"
-then
-	if test -n "$verbose"
-	then
-		if test -z "$mb"
-		then
-			echo "$(eval_gettext "Changes to \$onto:")"
-		else
-			echo "$(eval_gettext "Changes from \$mb to \$onto:")"
-		fi
-	fi
-	mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
-	# We want color (if set), but no pager
-	GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
-fi
-
-if test -z "$actually_interactive" && test "$mb" = "$orig_head"
-then
-	say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
-	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-		git checkout -q "$onto^0" || die "could not detach HEAD"
-	# If the $onto is a proper descendant of the tip of the branch, then
-	# we just fast-forwarded.
-	git update-ref ORIG_HEAD $orig_head
-	move_to_original_branch
-	finish_rebase
-	exit 0
-fi
-
-test -n "$interactive_rebase" && run_specific_rebase
-
-# Detach HEAD and reset the tree
-say "$(gettext "First, rewinding head to replay your work on top of it...")"
-
-GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
-	git checkout -q "$onto^0" || die "could not detach HEAD"
-git update-ref ORIG_HEAD $orig_head
-
-if test -n "$rebase_root"
-then
-	revisions="$onto..$orig_head"
-else
-	revisions="${restrict_revision-$upstream}..$orig_head"
-fi
-
-run_specific_rebase
diff --git a/t/README b/t/README
index 7a3d582267c..385262357b5 100644
--- a/t/README
+++ b/t/README
@@ -379,10 +379,6 @@ the --no-sparse command-line argument.
 GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
 by overriding the minimum number of cache entries required per thread.
 
-GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the
-builtin version of git-rebase. See 'rebase.useBuiltin' in
-git-config(1).
-
 GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
 of the index for the whole test suite by bypassing the default number of
 cache entries and thread minimums. Setting this to 1 will make the
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 3e73f7584ce..a809de93047 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -311,4 +311,20 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
 	)
 '
 
+test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
+	expected="rebase.useBuiltin support has been removed" &&
+
+	# Only warn when the legacy rebase is requested...
+	test_must_fail git -c rebase.useBuiltin=false rebase 2>err &&
+	test_i18ngrep "$expected" err &&
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err &&
+	test_i18ngrep "$expected" err &&
+
+	# ...not when we would have used the built-in anyway
+	test_must_fail git -c rebase.useBuiltin=true rebase 2>err &&
+	test_must_be_empty err &&
+	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err &&
+	test_must_be_empty err
+'
+
 test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index b60b11f9f2f..1723e1a8585 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
 
 test_expect_success 'rebase -x with empty command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x "" @ 2>actual &&
+	test_must_fail env git rebase -x "" @ 2>actual &&
 	test_write_lines "error: empty exec command" >expected &&
 	test_i18ncmp expected actual &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x " " @ 2>actual &&
+	test_must_fail env git rebase -x " " @ 2>actual &&
 	test_i18ncmp expected actual
 '
 
@@ -162,8 +160,7 @@ LF='
 '
 test_expect_success 'rebase -x with newline in command fails' '
 	test_when_finished "git rebase --abort ||:" &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
-		git rebase -x "a${LF}b" @ 2>actual &&
+	test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
 	test_write_lines "error: exec commands cannot contain newlines" \
 			 >expected &&
 	test_i18ncmp expected actual
-- 
2.21.0.360.g471c308f928


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v4] rebase: remove the rebase.useBuiltin setting
  2019-03-18 11:01                       ` [PATCH v4] " Ævar Arnfjörð Bjarmason
@ 2019-03-19 10:21                         ` Phillip Wood
  2021-03-23 15:23                         ` [PATCH] rebase: remove transitory rebase.useBuiltin setting & env Ævar Arnfjörð Bjarmason
  1 sibling, 0 replies; 31+ messages in thread
From: Phillip Wood @ 2019-03-19 10:21 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Junio C Hamano, Phillip Wood, Johannes Schindelin

Hi Ævar
On 18/03/2019 11:01, Ævar Arnfjörð Bjarmason wrote:
> Remove the rebase.useBuiltin setting, which was added as an escape
> hatch to disable the builtin version of rebase first released with Git
> 2.20.
> 
> See [1] for the initial implementation of rebase.useBuiltin, and [2]
> and [3] for the documentation and corresponding
> GIT_TEST_REBASE_USE_BUILTIN option.
> 
> Carrying the legacy version is a maintenance burden as seen in
> 7e097e27d3 ("legacy-rebase: backport -C<n> and --whitespace=<option>
> checks", 2018-11-20) and 9aea5e9286 ("rebase: fix regression in
> rebase.useBuiltin=false test mode", 2019-02-13). Since the built-in
> version has been shown to be stable enough let's remove the legacy
> version.
> 
> As noted in [3] having use_builtin_rebase() shell out to get its
> config doesn't make any sense anymore, that was done for the purposes
> of spawning the legacy rebase without having modified any global
> state. Let's instead handle this case in rebase_config().
> 
> There's still a bunch of references to git-legacy-rebase in po/*.po,
> but those will be dealt with in time by the i18n effort.
> 
> Even though this configuration variable only existed two releases
> let's not entirely delete the entry from the docs, but note its
> absence. Individual versions of git tend to be around for a while due
> to distro packaging timelines, so e.g. if we're "lucky" a given
> version like 2.21 might be installed on say OSX for half a decade.
> 
> That'll mean some people probably setting this in config, and then
> when they later wonder if it's needed they can Google search the
> config option name or check it in git-config. It also allows us to
> refer to the docs from the warning for details.
> 
> 1. 55071ea248 ("rebase: start implementing it as a builtin",
>     2018-08-07)
> 2. d8d0a546f0 ("rebase doc: document rebase.useBuiltin", 2018-11-14)
> 3. 62c23938fa ("tests: add a special setup where rebase.useBuiltin is
>     off", 2018-11-14)
> 3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/
> 
> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
> 
> Fix wording issues pointed out by Phillip & incorporated the Acked-by
> in Junio's push-out & added my SOB.
> 
> The confusion with "one release" was a) I'd initially written this
> before 2.21 was cut and forgot to change that

Ah I wondered if that was the case. The new version looks great

Thanks

Phillip

  2) I was then using
> "between" in the inclusive sense "pick a number between 1 and
> 10". Phillip's suggestion is better.
> 
> Range-diff:
> 1:  799dd15e4fd ! 1:  9ca747cb1f5 rebase: remove the rebase.useBuiltin setting
>      @@ -25,7 +25,7 @@
>           There's still a bunch of references to git-legacy-rebase in po/*.po,
>           but those will be dealt with in time by the i18n effort.
>       
>      -    Even though this configuration variable only existed for one release
>      +    Even though this configuration variable only existed two releases
>           let's not entirely delete the entry from the docs, but note its
>           absence. Individual versions of git tend to be around for a while due
>           to distro packaging timelines, so e.g. if we're "lucky" a given
>      @@ -43,6 +43,9 @@
>              off", 2018-11-14)
>           3. https://public-inbox.org/git/nycvar.QRO.7.76.6.1903141544110.41@tvgsbejvaqbjf.bet/
>       
>      +    Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de>
>      +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>      +
>        diff --git a/.gitignore b/.gitignore
>        --- a/.gitignore
>        +++ b/.gitignore
>      @@ -72,8 +75,8 @@
>       -If you find some reason to set this option to `false` other than
>       -one-off testing you should report the behavior difference as a bug in
>       -git.
>      -+	Unused configuration variable. Used between Git version 2.20
>      -+	and 2.21 as an escape hatch to enable the legacy shellscript
>      ++	Unused configuration variable. Used in Git versions 2.20 and
>      ++	2.21 as an escape hatch to enable the legacy shellscript
>       +	implementation of rebase. Now the built-in rewrite of it in C
>       +	is always used. Setting this will emit a warning, to alert any
>       +	remaining users that setting this now does nothing.
> 
>   .gitignore                      |   1 -
>   Documentation/config/rebase.txt |  17 +-
>   Makefile                        |   1 -
>   builtin/rebase.c                |  50 +--
>   git-legacy-rebase.sh            | 770 --------------------------------
>   t/README                        |   4 -
>   t/t3400-rebase.sh               |  16 +
>   t/t3404-rebase-interactive.sh   |   9 +-
>   8 files changed, 35 insertions(+), 833 deletions(-)
>   delete mode 100755 git-legacy-rebase.sh
> 
> diff --git a/.gitignore b/.gitignore
> index 7374587f9df..5cb84f1d1a9 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -82,7 +82,6 @@
>   /git-init-db
>   /git-interpret-trailers
>   /git-instaweb
> -/git-legacy-rebase
>   /git-log
>   /git-ls-files
>   /git-ls-remote
> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
> index 331d250e046..d98e32d812e 100644
> --- a/Documentation/config/rebase.txt
> +++ b/Documentation/config/rebase.txt
> @@ -1,16 +1,9 @@
>   rebase.useBuiltin::
> -	Set to `false` to use the legacy shellscript implementation of
> -	linkgit:git-rebase[1]. Is `true` by default, which means use
> -	the built-in rewrite of it in C.
> -+
> -The C rewrite is first included with Git version 2.20. This option
> -serves an an escape hatch to re-enable the legacy version in case any
> -bugs are found in the rewrite. This option and the shellscript version
> -of linkgit:git-rebase[1] will be removed in some future release.
> -+
> -If you find some reason to set this option to `false` other than
> -one-off testing you should report the behavior difference as a bug in
> -git.
> +	Unused configuration variable. Used in Git versions 2.20 and
> +	2.21 as an escape hatch to enable the legacy shellscript
> +	implementation of rebase. Now the built-in rewrite of it in C
> +	is always used. Setting this will emit a warning, to alert any
> +	remaining users that setting this now does nothing.
>   
>   rebase.stat::
>   	Whether to show a diffstat of what changed upstream since the last
> diff --git a/Makefile b/Makefile
> index 537493822b1..9f1159cffcb 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -632,7 +632,6 @@ SCRIPT_SH += git-merge-one-file.sh
>   SCRIPT_SH += git-merge-resolve.sh
>   SCRIPT_SH += git-mergetool.sh
>   SCRIPT_SH += git-quiltimport.sh
> -SCRIPT_SH += git-legacy-rebase.sh
>   SCRIPT_SH += git-remote-testgit.sh
>   SCRIPT_SH += git-request-pull.sh
>   SCRIPT_SH += git-stash.sh
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 52114cbf0d9..bc3dc629c16 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -46,29 +46,6 @@ enum rebase_type {
>   	REBASE_PRESERVE_MERGES
>   };
>   
> -static int use_builtin_rebase(void)
> -{
> -	struct child_process cp = CHILD_PROCESS_INIT;
> -	struct strbuf out = STRBUF_INIT;
> -	int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1);
> -
> -	if (env != -1)
> -		return env;
> -
> -	argv_array_pushl(&cp.args,
> -			 "config", "--bool", "rebase.usebuiltin", NULL);
> -	cp.git_cmd = 1;
> -	if (capture_command(&cp, &out, 6)) {
> -		strbuf_release(&out);
> -		return 1;
> -	}
> -
> -	strbuf_trim(&out);
> -	ret = !strcmp("true", out.buf);
> -	strbuf_release(&out);
> -	return ret;
> -}
> -
>   struct rebase_options {
>   	enum rebase_type type;
>   	const char *state_dir;
> @@ -106,6 +83,7 @@ struct rebase_options {
>   	char *strategy, *strategy_opts;
>   	struct strbuf git_format_patch_opt;
>   	int reschedule_failed_exec;
> +	int use_legacy_rebase;
>   };
>   
>   static int is_interactive(struct rebase_options *opts)
> @@ -869,6 +847,11 @@ static int rebase_config(const char *var, const char *value, void *data)
>   		return 0;
>   	}
>   
> +	if (!strcmp(var, "rebase.usebuiltin")) {
> +		opts->use_legacy_rebase = !git_config_bool(var, value);
> +		return 0;
> +	}
> +
>   	return git_default_config(var, value, data);
>   }
>   
> @@ -1143,22 +1126,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>   	};
>   	int i;
>   
> -	/*
> -	 * NEEDSWORK: Once the builtin rebase has been tested enough
> -	 * and git-legacy-rebase.sh is retired to contrib/, this preamble
> -	 * can be removed.
> -	 */
> -
> -	if (!use_builtin_rebase()) {
> -		const char *path = mkpath("%s/git-legacy-rebase",
> -					  git_exec_path());
> -
> -		if (sane_execvp(path, (char **)argv) < 0)
> -			die_errno(_("could not exec %s"), path);
> -		else
> -			BUG("sane_execvp() returned???");
> -	}
> -
>   	if (argc == 2 && !strcmp(argv[1], "-h"))
>   		usage_with_options(builtin_rebase_usage,
>   				   builtin_rebase_options);
> @@ -1169,6 +1136,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>   
>   	git_config(rebase_config, &options);
>   
> +	if (options.use_legacy_rebase ||
> +	    !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
> +		warning(_("the rebase.useBuiltin support has been removed!\n"
> +			  "See its entry in 'git help config' for details."));
> +
>   	strbuf_reset(&buf);
>   	strbuf_addf(&buf, "%s/applying", apply_dir());
>   	if(file_exists(buf.buf))
> diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh
> deleted file mode 100755
> index 5c2c4e5276d..00000000000
> --- a/git-legacy-rebase.sh
> +++ /dev/null
> @@ -1,770 +0,0 @@
> -#!/bin/sh
> -#
> -# Copyright (c) 2005 Junio C Hamano.
> -#
> -
> -SUBDIRECTORY_OK=Yes
> -OPTIONS_KEEPDASHDASH=
> -OPTIONS_STUCKLONG=t
> -OPTIONS_SPEC="\
> -git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
> -git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
> -git rebase --continue | --abort | --skip | --edit-todo
> ---
> - Available options are
> -v,verbose!         display a diffstat of what changed upstream
> -q,quiet!           be quiet. implies --no-stat
> -autostash          automatically stash/stash pop before and after
> -fork-point         use 'merge-base --fork-point' to refine upstream
> -onto=!             rebase onto given branch instead of upstream
> -r,rebase-merges?   try to rebase merges instead of skipping them
> -p,preserve-merges! try to recreate merges instead of ignoring them
> -s,strategy=!       use the given merge strategy
> -X,strategy-option=! pass the argument through to the merge strategy
> -no-ff!             cherry-pick all commits, even if unchanged
> -f,force-rebase!    cherry-pick all commits, even if unchanged
> -m,merge!           use merging strategies to rebase
> -i,interactive!     let the user edit the list of commits to rebase
> -x,exec=!           add exec lines after each commit of the editable list
> -k,keep-empty	   preserve empty commits during rebase
> -allow-empty-message allow rebasing commits with empty messages
> -stat!              display a diffstat of what changed upstream
> -n,no-stat!         do not show diffstat of what changed upstream
> -verify             allow pre-rebase hook to run
> -rerere-autoupdate  allow rerere to update index with resolved conflicts
> -root!              rebase all reachable commits up to the root(s)
> -autosquash         move commits that begin with squash!/fixup! under -i
> -signoff            add a Signed-off-by: line to each commit
> -committer-date-is-author-date! passed to 'git am'
> -ignore-date!       passed to 'git am'
> -whitespace=!       passed to 'git apply'
> -ignore-whitespace! passed to 'git apply'
> -C=!                passed to 'git apply'
> -S,gpg-sign?        GPG-sign commits
> - Actions:
> -continue!          continue
> -abort!             abort and check out the original branch
> -skip!              skip current patch and continue
> -edit-todo!         edit the todo list during an interactive rebase
> -quit!              abort but keep HEAD where it is
> -show-current-patch! show the patch file being applied or merged
> -reschedule-failed-exec automatically reschedule failed exec commands
> -"
> -. git-sh-setup
> -set_reflog_action rebase
> -require_work_tree_exists
> -cd_to_toplevel
> -
> -LF='
> -'
> -ok_to_skip_pre_rebase=
> -
> -squash_onto=
> -unset onto
> -unset restrict_revision
> -cmd=
> -strategy=
> -strategy_opts=
> -do_merge=
> -merge_dir="$GIT_DIR"/rebase-merge
> -apply_dir="$GIT_DIR"/rebase-apply
> -verbose=
> -diffstat=
> -test "$(git config --bool rebase.stat)" = true && diffstat=t
> -autostash="$(git config --bool rebase.autostash || echo false)"
> -fork_point=auto
> -git_am_opt=
> -git_format_patch_opt=
> -rebase_root=
> -force_rebase=
> -allow_rerere_autoupdate=
> -# Non-empty if a rebase was in progress when 'git rebase' was invoked
> -in_progress=
> -# One of {am, merge, interactive}
> -type=
> -# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
> -state_dir=
> -# One of {'', continue, skip, abort}, as parsed from command line
> -action=
> -rebase_merges=
> -rebase_cousins=
> -preserve_merges=
> -autosquash=
> -keep_empty=
> -allow_empty_message=--allow-empty-message
> -signoff=
> -reschedule_failed_exec=
> -test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
> -case "$(git config --bool commit.gpgsign)" in
> -true)	gpg_sign_opt=-S ;;
> -*)	gpg_sign_opt= ;;
> -esac
> -test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
> -reschedule_failed_exec=--reschedule-failed-exec
> -. git-rebase--common
> -
> -read_basic_state () {
> -	test -f "$state_dir/head-name" &&
> -	test -f "$state_dir/onto" &&
> -	head_name=$(cat "$state_dir"/head-name) &&
> -	onto=$(cat "$state_dir"/onto) &&
> -	# We always write to orig-head, but interactive rebase used to write to
> -	# head. Fall back to reading from head to cover for the case that the
> -	# user upgraded git with an ongoing interactive rebase.
> -	if test -f "$state_dir"/orig-head
> -	then
> -		orig_head=$(cat "$state_dir"/orig-head)
> -	else
> -		orig_head=$(cat "$state_dir"/head)
> -	fi &&
> -	test -f "$state_dir"/quiet && GIT_QUIET=t
> -	test -f "$state_dir"/verbose && verbose=t
> -	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
> -	test -f "$state_dir"/strategy_opts &&
> -		strategy_opts="$(cat "$state_dir"/strategy_opts)"
> -	test -f "$state_dir"/allow_rerere_autoupdate &&
> -		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
> -	test -f "$state_dir"/gpg_sign_opt &&
> -		gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
> -	test -f "$state_dir"/signoff && {
> -		signoff="$(cat "$state_dir"/signoff)"
> -		force_rebase=t
> -	}
> -	test -f "$state_dir"/reschedule-failed-exec &&
> -		reschedule_failed_exec=t
> -}
> -
> -finish_rebase () {
> -	rm -f "$(git rev-parse --git-path REBASE_HEAD)"
> -	apply_autostash &&
> -	{ git gc --auto || true; } &&
> -	rm -rf "$state_dir"
> -}
> -
> -run_interactive () {
> -	GIT_CHERRY_PICK_HELP="$resolvemsg"
> -	export GIT_CHERRY_PICK_HELP
> -
> -	test -n "$keep_empty" && keep_empty="--keep-empty"
> -	test -n "$rebase_merges" && rebase_merges="--rebase-merges"
> -	test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
> -	test -n "$autosquash" && autosquash="--autosquash"
> -	test -n "$verbose" && verbose="--verbose"
> -	test -n "$force_rebase" && force_rebase="--no-ff"
> -	test -n "$restrict_revision" && \
> -		restrict_revision="--restrict-revision=^$restrict_revision"
> -	test -n "$upstream" && upstream="--upstream=$upstream"
> -	test -n "$onto" && onto="--onto=$onto"
> -	test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
> -	test -n "$onto_name" && onto_name="--onto-name=$onto_name"
> -	test -n "$head_name" && head_name="--head-name=$head_name"
> -	test -n "$strategy" && strategy="--strategy=$strategy"
> -	test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
> -	test -n "$switch_to" && switch_to="--switch-to=$switch_to"
> -	test -n "$cmd" && cmd="--cmd=$cmd"
> -	test -n "$action" && action="--$action"
> -
> -	exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
> -		"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
> -		"$allow_empty_message" "$autosquash" "$verbose" \
> -		"$force_rebase" "$onto_name" "$head_name" "$strategy" \
> -		"$strategy_opts" "$cmd" "$switch_to" \
> -		"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
> -		"$reschedule_failed_exec"
> -}
> -
> -run_specific_rebase () {
> -	if [ "$interactive_rebase" = implied ]; then
> -		GIT_SEQUENCE_EDITOR=:
> -		export GIT_SEQUENCE_EDITOR
> -		autosquash=
> -	fi
> -
> -	if test -n "$interactive_rebase" -a -z "$preserve_merges"
> -	then
> -		run_interactive
> -	else
> -		. git-rebase--$type
> -
> -		if test -z "$preserve_merges"
> -		then
> -			git_rebase__$type
> -		else
> -			git_rebase__preserve_merges
> -		fi
> -	fi
> -
> -	ret=$?
> -	if test $ret -eq 0
> -	then
> -		finish_rebase
> -	elif test $ret -eq 2 # special exit status for rebase -p
> -	then
> -		apply_autostash &&
> -		rm -rf "$state_dir" &&
> -		die "Nothing to do"
> -	fi
> -	exit $ret
> -}
> -
> -run_pre_rebase_hook () {
> -	if test -z "$ok_to_skip_pre_rebase" &&
> -	   test -x "$(git rev-parse --git-path hooks/pre-rebase)"
> -	then
> -		"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
> -		die "$(gettext "The pre-rebase hook refused to rebase.")"
> -	fi
> -}
> -
> -test -f "$apply_dir"/applying &&
> -	die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
> -
> -if test -d "$apply_dir"
> -then
> -	type=am
> -	state_dir="$apply_dir"
> -elif test -d "$merge_dir"
> -then
> -	type=interactive
> -	if test -d "$merge_dir"/rewritten
> -	then
> -		type=preserve-merges
> -		interactive_rebase=explicit
> -		preserve_merges=t
> -	elif test -f "$merge_dir"/interactive
> -	then
> -		interactive_rebase=explicit
> -	fi
> -	state_dir="$merge_dir"
> -fi
> -test -n "$type" && in_progress=t
> -
> -total_argc=$#
> -while test $# != 0
> -do
> -	case "$1" in
> -	--no-verify)
> -		ok_to_skip_pre_rebase=yes
> -		;;
> -	--verify)
> -		ok_to_skip_pre_rebase=
> -		;;
> -	--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
> -		test $total_argc -eq 2 || usage
> -		action=${1##--}
> -		;;
> -	--onto=*)
> -		onto="${1#--onto=}"
> -		;;
> -	--exec=*)
> -		cmd="${cmd}exec ${1#--exec=}${LF}"
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--interactive)
> -		interactive_rebase=explicit
> -		;;
> -	--keep-empty)
> -		keep_empty=yes
> -		;;
> -	--allow-empty-message)
> -		allow_empty_message=--allow-empty-message
> -		;;
> -	--no-keep-empty)
> -		keep_empty=
> -		;;
> -	--rebase-merges)
> -		rebase_merges=t
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--rebase-merges=*)
> -		rebase_merges=t
> -		case "${1#*=}" in
> -		rebase-cousins) rebase_cousins=t;;
> -		no-rebase-cousins) rebase_cousins=;;
> -		*) die "Unknown mode: $1";;
> -		esac
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--preserve-merges)
> -		preserve_merges=t
> -		test -z "$interactive_rebase" && interactive_rebase=implied
> -		;;
> -	--autosquash)
> -		autosquash=t
> -		;;
> -	--no-autosquash)
> -		autosquash=
> -		;;
> -	--fork-point)
> -		fork_point=t
> -		;;
> -	--no-fork-point)
> -		fork_point=
> -		;;
> -	--merge)
> -		do_merge=t
> -		;;
> -	--strategy-option=*)
> -		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
> -		do_merge=t
> -		test -z "$strategy" && strategy=recursive
> -		;;
> -	--strategy=*)
> -		strategy="${1#--strategy=}"
> -		do_merge=t
> -		;;
> -	--no-stat)
> -		diffstat=
> -		;;
> -	--stat)
> -		diffstat=t
> -		;;
> -	--autostash)
> -		autostash=true
> -		;;
> -	--no-autostash)
> -		autostash=false
> -		;;
> -	--verbose)
> -		verbose=t
> -		diffstat=t
> -		GIT_QUIET=
> -		;;
> -	--quiet)
> -		GIT_QUIET=t
> -		git_am_opt="$git_am_opt -q"
> -		verbose=
> -		diffstat=
> -		;;
> -	--whitespace=*)
> -		git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
> -		case "${1#--whitespace=}" in
> -		fix|strip)
> -			force_rebase=t
> -			;;
> -		warn|nowarn|error|error-all)
> -			;; # okay, known whitespace option
> -		*)
> -			die "fatal: Invalid whitespace option: '${1#*=}'"
> -			;;
> -		esac
> -		;;
> -	--ignore-whitespace)
> -		git_am_opt="$git_am_opt $1"
> -		;;
> -	--signoff)
> -		signoff=--signoff
> -		;;
> -	--no-signoff)
> -		signoff=
> -		;;
> -	--committer-date-is-author-date|--ignore-date)
> -		git_am_opt="$git_am_opt $1"
> -		force_rebase=t
> -		;;
> -	-C*[!0-9]*)
> -		die "fatal: switch \`C' expects a numerical value"
> -		;;
> -	-C*)
> -		git_am_opt="$git_am_opt $1"
> -		;;
> -	--root)
> -		rebase_root=t
> -		;;
> -	--force-rebase|--no-ff)
> -		force_rebase=t
> -		;;
> -	--rerere-autoupdate|--no-rerere-autoupdate)
> -		allow_rerere_autoupdate="$1"
> -		;;
> -	--gpg-sign)
> -		gpg_sign_opt=-S
> -		;;
> -	--gpg-sign=*)
> -		gpg_sign_opt="-S${1#--gpg-sign=}"
> -		;;
> -	--reschedule-failed-exec)
> -		reschedule_failed_exec=--reschedule-failed-exec
> -		;;
> -	--no-reschedule-failed-exec)
> -		reschedule_failed_exec=
> -		;;
> -	--)
> -		shift
> -		break
> -		;;
> -	*)
> -		usage
> -		;;
> -	esac
> -	shift
> -done
> -test $# -gt 2 && usage
> -
> -if test -n "$action"
> -then
> -	test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
> -	# Only interactive rebase uses detailed reflog messages
> -	if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
> -	then
> -		GIT_REFLOG_ACTION="rebase -i ($action)"
> -		export GIT_REFLOG_ACTION
> -	fi
> -fi
> -
> -if test "$action" = "edit-todo" && test -z "$interactive_rebase"
> -then
> -	die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
> -fi
> -
> -case "$action" in
> -continue)
> -	# Sanity check
> -	git rev-parse --verify HEAD >/dev/null ||
> -		die "$(gettext "Cannot read HEAD")"
> -	git update-index --ignore-submodules --refresh &&
> -	git diff-files --quiet --ignore-submodules || {
> -		echo "$(gettext "You must edit all merge conflicts and then
> -mark them as resolved using git add")"
> -		exit 1
> -	}
> -	read_basic_state
> -	run_specific_rebase
> -	;;
> -skip)
> -	output git reset --hard HEAD || exit $?
> -	read_basic_state
> -	run_specific_rebase
> -	;;
> -abort)
> -	git rerere clear
> -	read_basic_state
> -	case "$head_name" in
> -	refs/*)
> -		git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
> -		die "$(eval_gettext "Could not move back to \$head_name")"
> -		;;
> -	esac
> -	output git reset --hard $orig_head
> -	finish_rebase
> -	exit
> -	;;
> -quit)
> -	exec rm -rf "$state_dir"
> -	;;
> -edit-todo)
> -	run_specific_rebase
> -	;;
> -show-current-patch)
> -	run_specific_rebase
> -	die "BUG: run_specific_rebase is not supposed to return here"
> -	;;
> -esac
> -
> -# Make sure no rebase is in progress
> -if test -n "$in_progress"
> -then
> -	state_dir_base=${state_dir##*/}
> -	cmd_live_rebase="git rebase (--continue | --abort | --skip)"
> -	cmd_clear_stale_rebase="rm -fr \"$state_dir\""
> -	die "
> -$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
> -I wonder if you are in the middle of another rebase.  If that is the
> -case, please try
> -	$cmd_live_rebase
> -If that is not the case, please
> -	$cmd_clear_stale_rebase
> -and run me again.  I am stopping in case you still have something
> -valuable there.')"
> -fi
> -
> -if test -n "$rebase_root" && test -z "$onto"
> -then
> -	test -z "$interactive_rebase" && interactive_rebase=implied
> -fi
> -
> -if test -n "$keep_empty"
> -then
> -	test -z "$interactive_rebase" && interactive_rebase=implied
> -fi
> -
> -actually_interactive=
> -if test -n "$interactive_rebase"
> -then
> -	if test -z "$preserve_merges"
> -	then
> -		type=interactive
> -	else
> -		type=preserve-merges
> -	fi
> -	actually_interactive=t
> -	state_dir="$merge_dir"
> -elif test -n "$do_merge"
> -then
> -	interactive_rebase=implied
> -	type=interactive
> -	state_dir="$merge_dir"
> -else
> -	type=am
> -	state_dir="$apply_dir"
> -fi
> -
> -if test -t 2 && test -z "$GIT_QUIET"
> -then
> -	git_format_patch_opt="$git_format_patch_opt --progress"
> -fi
> -
> -incompatible_opts=$(echo " $git_am_opt " | \
> -		    sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
> -if test -n "$incompatible_opts"
> -then
> -	if test -n "$actually_interactive" || test "$do_merge"
> -	then
> -		die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
> -	fi
> -fi
> -
> -if test -n "$signoff"
> -then
> -	test -n "$preserve_merges" &&
> -		die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
> -	git_am_opt="$git_am_opt $signoff"
> -	force_rebase=t
> -fi
> -
> -if test -n "$preserve_merges"
> -then
> -	# Note: incompatibility with --signoff handled in signoff block above
> -	# Note: incompatibility with --interactive is just a strong warning;
> -	#       git-rebase.txt caveats with "unless you know what you are doing"
> -	test -n "$rebase_merges" &&
> -		die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
> -
> -	test -n "$reschedule_failed_exec" &&
> -		die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
> -fi
> -
> -if test -n "$rebase_merges"
> -then
> -	test -n "$strategy_opts" &&
> -		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
> -	test -n "$strategy" &&
> -		die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
> -fi
> -
> -if test -z "$rebase_root"
> -then
> -	case "$#" in
> -	0)
> -		if ! upstream_name=$(git rev-parse --symbolic-full-name \
> -			--verify -q @{upstream} 2>/dev/null)
> -		then
> -			. git-parse-remote
> -			error_on_missing_default_upstream "rebase" "rebase" \
> -				"against" "git rebase $(gettext '<branch>')"
> -		fi
> -
> -		test "$fork_point" = auto && fork_point=t
> -		;;
> -	*)	upstream_name="$1"
> -		if test "$upstream_name" = "-"
> -		then
> -			upstream_name="@{-1}"
> -		fi
> -		shift
> -		;;
> -	esac
> -	upstream=$(peel_committish "${upstream_name}") ||
> -	die "$(eval_gettext "invalid upstream '\$upstream_name'")"
> -	upstream_arg="$upstream_name"
> -else
> -	if test -z "$onto"
> -	then
> -		empty_tree=$(git hash-object -t tree /dev/null)
> -		onto=$(git commit-tree $empty_tree </dev/null)
> -		squash_onto="$onto"
> -	fi
> -	unset upstream_name
> -	unset upstream
> -	test $# -gt 1 && usage
> -	upstream_arg=--root
> -fi
> -
> -# Make sure the branch to rebase onto is valid.
> -onto_name=${onto-"$upstream_name"}
> -case "$onto_name" in
> -*...*)
> -	if	left=${onto_name%...*} right=${onto_name#*...} &&
> -		onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
> -	then
> -		case "$onto" in
> -		?*"$LF"?*)
> -			die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
> -			;;
> -		'')
> -			die "$(eval_gettext "\$onto_name: there is no merge base")"
> -			;;
> -		esac
> -	else
> -		die "$(eval_gettext "\$onto_name: there is no merge base")"
> -	fi
> -	;;
> -*)
> -	onto=$(peel_committish "$onto_name") ||
> -	die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
> -	;;
> -esac
> -
> -# If the branch to rebase is given, that is the branch we will rebase
> -# $branch_name -- branch/commit being rebased, or HEAD (already detached)
> -# $orig_head -- commit object name of tip of the branch before rebasing
> -# $head_name -- refs/heads/<that-branch> or "detached HEAD"
> -switch_to=
> -case "$#" in
> -1)
> -	# Is it "rebase other $branchname" or "rebase other $commit"?
> -	branch_name="$1"
> -	switch_to="$1"
> -
> -	# Is it a local branch?
> -	if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
> -	   orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
> -	then
> -		head_name="refs/heads/$branch_name"
> -	# If not is it a valid ref (branch or commit)?
> -	elif orig_head=$(git rev-parse -q --verify "$branch_name")
> -	then
> -		head_name="detached HEAD"
> -
> -	else
> -		die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
> -	fi
> -	;;
> -0)
> -	# Do not need to switch branches, we are already on it.
> -	if branch_name=$(git symbolic-ref -q HEAD)
> -	then
> -		head_name=$branch_name
> -		branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
> -	else
> -		head_name="detached HEAD"
> -		branch_name=HEAD
> -	fi
> -	orig_head=$(git rev-parse --verify HEAD) || exit
> -	;;
> -*)
> -	die "BUG: unexpected number of arguments left to parse"
> -	;;
> -esac
> -
> -if test "$fork_point" = t
> -then
> -	new_upstream=$(git merge-base --fork-point "$upstream_name" \
> -			"${switch_to:-HEAD}")
> -	if test -n "$new_upstream"
> -	then
> -		restrict_revision=$new_upstream
> -	fi
> -fi
> -
> -if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
> -then
> -	stash_sha1=$(git stash create "autostash") ||
> -	die "$(gettext 'Cannot autostash')"
> -
> -	mkdir -p "$state_dir" &&
> -	echo $stash_sha1 >"$state_dir/autostash" &&
> -	stash_abbrev=$(git rev-parse --short $stash_sha1) &&
> -	echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
> -	git reset --hard
> -fi
> -
> -require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
> -
> -# Now we are rebasing commits $upstream..$orig_head (or with --root,
> -# everything leading up to $orig_head) on top of $onto
> -
> -# Check if we are already based on $onto with linear history,
> -# but this should be done only when upstream and onto are the same
> -# and if this is not an interactive rebase.
> -mb=$(git merge-base "$onto" "$orig_head")
> -if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
> -	test "$mb" = "$onto" && test -z "$restrict_revision" &&
> -	# linear history?
> -	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
> -then
> -	if test -z "$force_rebase"
> -	then
> -		# Lazily switch to the target branch if needed...
> -		test -z "$switch_to" ||
> -		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
> -			git checkout -q "$switch_to" --
> -		if test "$branch_name" = "HEAD" &&
> -			 ! git symbolic-ref -q HEAD
> -		then
> -			say "$(eval_gettext "HEAD is up to date.")"
> -		else
> -			say "$(eval_gettext "Current branch \$branch_name is up to date.")"
> -		fi
> -		finish_rebase
> -		exit 0
> -	else
> -		if test "$branch_name" = "HEAD" &&
> -			 ! git symbolic-ref -q HEAD
> -		then
> -			say "$(eval_gettext "HEAD is up to date, rebase forced.")"
> -		else
> -			say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
> -		fi
> -	fi
> -fi
> -
> -# If a hook exists, give it a chance to interrupt
> -run_pre_rebase_hook "$upstream_arg" "$@"
> -
> -if test -n "$diffstat"
> -then
> -	if test -n "$verbose"
> -	then
> -		if test -z "$mb"
> -		then
> -			echo "$(eval_gettext "Changes to \$onto:")"
> -		else
> -			echo "$(eval_gettext "Changes from \$mb to \$onto:")"
> -		fi
> -	fi
> -	mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
> -	# We want color (if set), but no pager
> -	GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
> -fi
> -
> -if test -z "$actually_interactive" && test "$mb" = "$orig_head"
> -then
> -	say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
> -	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
> -		git checkout -q "$onto^0" || die "could not detach HEAD"
> -	# If the $onto is a proper descendant of the tip of the branch, then
> -	# we just fast-forwarded.
> -	git update-ref ORIG_HEAD $orig_head
> -	move_to_original_branch
> -	finish_rebase
> -	exit 0
> -fi
> -
> -test -n "$interactive_rebase" && run_specific_rebase
> -
> -# Detach HEAD and reset the tree
> -say "$(gettext "First, rewinding head to replay your work on top of it...")"
> -
> -GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
> -	git checkout -q "$onto^0" || die "could not detach HEAD"
> -git update-ref ORIG_HEAD $orig_head
> -
> -if test -n "$rebase_root"
> -then
> -	revisions="$onto..$orig_head"
> -else
> -	revisions="${restrict_revision-$upstream}..$orig_head"
> -fi
> -
> -run_specific_rebase
> diff --git a/t/README b/t/README
> index 7a3d582267c..385262357b5 100644
> --- a/t/README
> +++ b/t/README
> @@ -379,10 +379,6 @@ the --no-sparse command-line argument.
>   GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
>   by overriding the minimum number of cache entries required per thread.
>   
> -GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the
> -builtin version of git-rebase. See 'rebase.useBuiltin' in
> -git-config(1).
> -
>   GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
>   of the index for the whole test suite by bypassing the default number of
>   cache entries and thread minimums. Setting this to 1 will make the
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 3e73f7584ce..a809de93047 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -311,4 +311,20 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
>   	)
>   '
>   
> +test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
> +	expected="rebase.useBuiltin support has been removed" &&
> +
> +	# Only warn when the legacy rebase is requested...
> +	test_must_fail git -c rebase.useBuiltin=false rebase 2>err &&
> +	test_i18ngrep "$expected" err &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err &&
> +	test_i18ngrep "$expected" err &&
> +
> +	# ...not when we would have used the built-in anyway
> +	test_must_fail git -c rebase.useBuiltin=true rebase 2>err &&
> +	test_must_be_empty err &&
> +	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err &&
> +	test_must_be_empty err
> +'
> +
>   test_done
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index b60b11f9f2f..1723e1a8585 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
>   
>   test_expect_success 'rebase -x with empty command fails' '
>   	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x "" @ 2>actual &&
> +	test_must_fail env git rebase -x "" @ 2>actual &&
>   	test_write_lines "error: empty exec command" >expected &&
>   	test_i18ncmp expected actual &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x " " @ 2>actual &&
> +	test_must_fail env git rebase -x " " @ 2>actual &&
>   	test_i18ncmp expected actual
>   '
>   
> @@ -162,8 +160,7 @@ LF='
>   '
>   test_expect_success 'rebase -x with newline in command fails' '
>   	test_when_finished "git rebase --abort ||:" &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \
> -		git rebase -x "a${LF}b" @ 2>actual &&
> +	test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
>   	test_write_lines "error: exec commands cannot contain newlines" \
>   			 >expected &&
>   	test_i18ncmp expected actual
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH] rebase: remove transitory rebase.useBuiltin setting & env
  2019-03-18 11:01                       ` [PATCH v4] " Ævar Arnfjörð Bjarmason
  2019-03-19 10:21                         ` Phillip Wood
@ 2021-03-23 15:23                         ` Ævar Arnfjörð Bjarmason
  2021-03-23 20:42                           ` Junio C Hamano
  2021-03-23 20:52                           ` Johannes Schindelin
  1 sibling, 2 replies; 31+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-23 15:23 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Phillip Wood,
	Ævar Arnfjörð Bjarmason

Remove the rebase.useBuiltin setting and the now-obsolete
GIT_TEST_REBASE_USE_BUILTIN test flag.

This was left in place after my d03ebd411c6 (rebase: remove the
rebase.useBuiltin setting, 2019-03-18) to help anyone who'd used the
experimental flag and wanted to know that it was the default, or that
they should transition their test environment to use the builtin
rebase unconditionally.

It's been more than long enough for those users to get a headsup about
this. So remove all the scaffolding that was left inplace after
d03ebd411c6. I'm also removing the documentation entry, if anyone
still has this left in their configuration they can do some source
archaeology to figure out what it used to do, which makes more sense
than exposing every git user reading the documentation to this legacy
configuration switch.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/config/rebase.txt |  7 -------
 builtin/rebase.c                | 11 -----------
 t/t3400-rebase.sh               | 16 ----------------
 3 files changed, 34 deletions(-)

diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
index 214f31b451f..8c979cb20f2 100644
--- a/Documentation/config/rebase.txt
+++ b/Documentation/config/rebase.txt
@@ -1,10 +1,3 @@
-rebase.useBuiltin::
-	Unused configuration variable. Used in Git versions 2.20 and
-	2.21 as an escape hatch to enable the legacy shellscript
-	implementation of rebase. Now the built-in rewrite of it in C
-	is always used. Setting this will emit a warning, to alert any
-	remaining users that setting this now does nothing.
-
 rebase.backend::
 	Default backend to use for rebasing.  Possible choices are
 	'apply' or 'merge'.  In the future, if the merge backend gains
diff --git a/builtin/rebase.c b/builtin/rebase.c
index de400f9a197..783b526f6e7 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -100,7 +100,6 @@ struct rebase_options {
 	char *strategy, *strategy_opts;
 	struct strbuf git_format_patch_opt;
 	int reschedule_failed_exec;
-	int use_legacy_rebase;
 	int reapply_cherry_picks;
 	int fork_point;
 };
@@ -1102,11 +1101,6 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
-	if (!strcmp(var, "rebase.usebuiltin")) {
-		opts->use_legacy_rebase = !git_config_bool(var, value);
-		return 0;
-	}
-
 	if (!strcmp(var, "rebase.backend")) {
 		return git_config_string(&opts->default_backend, var, value);
 	}
@@ -1441,11 +1435,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	gpg_sign = options.gpg_sign_opt ? "" : NULL;
 	FREE_AND_NULL(options.gpg_sign_opt);
 
-	if (options.use_legacy_rebase ||
-	    !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
-		warning(_("the rebase.useBuiltin support has been removed!\n"
-			  "See its entry in 'git help config' for details."));
-
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "%s/applying", apply_dir());
 	if(file_exists(buf.buf))
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 587b408063a..0bb88aa982b 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -388,22 +388,6 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
 	)
 '
 
-test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
-	expected="rebase.useBuiltin support has been removed" &&
-
-	# Only warn when the legacy rebase is requested...
-	test_must_fail git -c rebase.useBuiltin=false rebase 2>err &&
-	test_i18ngrep "$expected" err &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err &&
-	test_i18ngrep "$expected" err &&
-
-	# ...not when we would have used the built-in anyway
-	test_must_fail git -c rebase.useBuiltin=true rebase 2>err &&
-	test_must_be_empty err &&
-	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err &&
-	test_must_be_empty err
-'
-
 test_expect_success 'switch to branch checked out here' '
 	git checkout main &&
 	git rebase main main
-- 
2.31.0.366.g75c23356abd


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase: remove transitory rebase.useBuiltin setting & env
  2021-03-23 15:23                         ` [PATCH] rebase: remove transitory rebase.useBuiltin setting & env Ævar Arnfjörð Bjarmason
@ 2021-03-23 20:42                           ` Junio C Hamano
  2021-03-23 20:52                           ` Johannes Schindelin
  1 sibling, 0 replies; 31+ messages in thread
From: Junio C Hamano @ 2021-03-23 20:42 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Johannes Schindelin, Phillip Wood

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> It's been more than long enough for those users to get a headsup about
> this. So remove all the scaffolding that was left inplace after
> d03ebd411c6. I'm also removing the documentation entry, if anyone
> still has this left in their configuration they can do some source
> archaeology to figure out what it used to do, which makes more sense
> than exposing every git user reading the documentation to this legacy
> configuration switch.

OK, this concludes the long journey of replacing the scripted "git
rebase" with its reimplementation in C by removing the last trace
of the former.

It would be nice to have Acks from those involved in the
reimplementation effort, to celebrate the occasion.

> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  Documentation/config/rebase.txt |  7 -------
>  builtin/rebase.c                | 11 -----------
>  t/t3400-rebase.sh               | 16 ----------------
>  3 files changed, 34 deletions(-)
>
> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
> index 214f31b451f..8c979cb20f2 100644
> --- a/Documentation/config/rebase.txt
> +++ b/Documentation/config/rebase.txt
> @@ -1,10 +1,3 @@
> -rebase.useBuiltin::
> -	Unused configuration variable. Used in Git versions 2.20 and
> -	2.21 as an escape hatch to enable the legacy shellscript
> -	implementation of rebase. Now the built-in rewrite of it in C
> -	is always used. Setting this will emit a warning, to alert any
> -	remaining users that setting this now does nothing.
> -

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] rebase: remove transitory rebase.useBuiltin setting & env
  2021-03-23 15:23                         ` [PATCH] rebase: remove transitory rebase.useBuiltin setting & env Ævar Arnfjörð Bjarmason
  2021-03-23 20:42                           ` Junio C Hamano
@ 2021-03-23 20:52                           ` Johannes Schindelin
  1 sibling, 0 replies; 31+ messages in thread
From: Johannes Schindelin @ 2021-03-23 20:52 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Junio C Hamano, Phillip Wood

[-- Attachment #1: Type: text/plain, Size: 4346 bytes --]

Hi Ævar,

On Tue, 23 Mar 2021, Ævar Arnfjörð Bjarmason wrote:

> Remove the rebase.useBuiltin setting and the now-obsolete
> GIT_TEST_REBASE_USE_BUILTIN test flag.
>
> This was left in place after my d03ebd411c6 (rebase: remove the
> rebase.useBuiltin setting, 2019-03-18) to help anyone who'd used the
> experimental flag and wanted to know that it was the default, or that
> they should transition their test environment to use the builtin
> rebase unconditionally.
>
> It's been more than long enough for those users to get a headsup about
> this. So remove all the scaffolding that was left inplace after
> d03ebd411c6. I'm also removing the documentation entry, if anyone
> still has this left in their configuration they can do some source
> archaeology to figure out what it used to do, which makes more sense
> than exposing every git user reading the documentation to this legacy
> configuration switch.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

ACK!
Dscho

> ---
>  Documentation/config/rebase.txt |  7 -------
>  builtin/rebase.c                | 11 -----------
>  t/t3400-rebase.sh               | 16 ----------------
>  3 files changed, 34 deletions(-)
>
> diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt
> index 214f31b451f..8c979cb20f2 100644
> --- a/Documentation/config/rebase.txt
> +++ b/Documentation/config/rebase.txt
> @@ -1,10 +1,3 @@
> -rebase.useBuiltin::
> -	Unused configuration variable. Used in Git versions 2.20 and
> -	2.21 as an escape hatch to enable the legacy shellscript
> -	implementation of rebase. Now the built-in rewrite of it in C
> -	is always used. Setting this will emit a warning, to alert any
> -	remaining users that setting this now does nothing.
> -
>  rebase.backend::
>  	Default backend to use for rebasing.  Possible choices are
>  	'apply' or 'merge'.  In the future, if the merge backend gains
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index de400f9a197..783b526f6e7 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -100,7 +100,6 @@ struct rebase_options {
>  	char *strategy, *strategy_opts;
>  	struct strbuf git_format_patch_opt;
>  	int reschedule_failed_exec;
> -	int use_legacy_rebase;
>  	int reapply_cherry_picks;
>  	int fork_point;
>  };
> @@ -1102,11 +1101,6 @@ static int rebase_config(const char *var, const char *value, void *data)
>  		return 0;
>  	}
>
> -	if (!strcmp(var, "rebase.usebuiltin")) {
> -		opts->use_legacy_rebase = !git_config_bool(var, value);
> -		return 0;
> -	}
> -
>  	if (!strcmp(var, "rebase.backend")) {
>  		return git_config_string(&opts->default_backend, var, value);
>  	}
> @@ -1441,11 +1435,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  	gpg_sign = options.gpg_sign_opt ? "" : NULL;
>  	FREE_AND_NULL(options.gpg_sign_opt);
>
> -	if (options.use_legacy_rebase ||
> -	    !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
> -		warning(_("the rebase.useBuiltin support has been removed!\n"
> -			  "See its entry in 'git help config' for details."));
> -
>  	strbuf_reset(&buf);
>  	strbuf_addf(&buf, "%s/applying", apply_dir());
>  	if(file_exists(buf.buf))
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 587b408063a..0bb88aa982b 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -388,22 +388,6 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
>  	)
>  '
>
> -test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
> -	expected="rebase.useBuiltin support has been removed" &&
> -
> -	# Only warn when the legacy rebase is requested...
> -	test_must_fail git -c rebase.useBuiltin=false rebase 2>err &&
> -	test_i18ngrep "$expected" err &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err &&
> -	test_i18ngrep "$expected" err &&
> -
> -	# ...not when we would have used the built-in anyway
> -	test_must_fail git -c rebase.useBuiltin=true rebase 2>err &&
> -	test_must_be_empty err &&
> -	test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err &&
> -	test_must_be_empty err
> -'
> -
>  test_expect_success 'switch to branch checked out here' '
>  	git checkout main &&
>  	git rebase main main
> --
> 2.31.0.366.g75c23356abd
>
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2021-03-23 20:53 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-28 10:26 [PATCH] rebase -x: sanity check command Phillip Wood
2019-01-28 18:23 ` Junio C Hamano
2019-01-28 21:56   ` Johannes Schindelin
2019-01-29 11:40     ` Phillip Wood
2019-01-29 15:35       ` Johannes Schindelin
2019-01-28 22:03 ` Johannes Schindelin
2019-01-29 11:34   ` Phillip Wood
2019-01-29 15:32     ` Johannes Schindelin
2019-01-29 18:43       ` [PATCH v2] " Phillip Wood
2019-01-29 21:53         ` Junio C Hamano
2019-01-30 12:25         ` Johannes Schindelin
2019-02-13 13:31         ` Ævar Arnfjörð Bjarmason
2019-02-13 14:22           ` [PATCH] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
2019-02-13 16:25             ` Johannes Schindelin
2019-02-13 20:46             ` Junio C Hamano
2019-02-13 21:49               ` [PATCH] rebase: fix regression in rebase.useBuiltin=false test mode Ævar Arnfjörð Bjarmason
2019-02-13 23:21                 ` Junio C Hamano
2019-02-14 16:12                 ` Phillip Wood
2019-03-14 13:24             ` [PATCH v2] rebase: remove the rebase.useBuiltin setting Ævar Arnfjörð Bjarmason
2019-03-14 14:58               ` Johannes Schindelin
2019-03-14 15:27                 ` Ævar Arnfjörð Bjarmason
2019-03-15 13:45                   ` [PATCH v3] " Ævar Arnfjörð Bjarmason
2019-03-15 15:44                     ` Johannes Schindelin
2019-03-15 16:11                       ` Ævar Arnfjörð Bjarmason
2019-03-18  6:06                         ` Junio C Hamano
2019-03-18 10:19                     ` Phillip Wood
2019-03-18 11:01                       ` [PATCH v4] " Ævar Arnfjörð Bjarmason
2019-03-19 10:21                         ` Phillip Wood
2021-03-23 15:23                         ` [PATCH] rebase: remove transitory rebase.useBuiltin setting & env Ævar Arnfjörð Bjarmason
2021-03-23 20:42                           ` Junio C Hamano
2021-03-23 20:52                           ` Johannes Schindelin

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