Subject: Re: Feature request: rebase -i inside of rebase -i

From: George Spelvin <[email-masked]>
Date: Thu, 26 Mar 2020 00:18:21 +0000

On Wed, Mar 25, 2020 at 08:26:48PM +0100, Johannes Schindelin wrote:
> On Sat, 21 Mar 2020, George Spelvin wrote:
>> My assumption has been that, for simplicity, there would only be one
>> commit in progress, and aborting it aborts everything.
>
> But that does not necessarily make sense. Imagine that you rebase the
> latest three commits, interactively. Then a merge conflict in the third
> makes you realize that the first commit is no longer needed.
> 
> Enter the nested rebase. You manually re-schedule the failed `pick` via
> `git rebase --edit-todo` and then run the nested rebase: `git reset --hard
> && git rebase -i --nested HEAD~2`.
> 
> Except that you made a typo and said `HEAD~3` instead of `HEAD~2`. You
> delete the entire todo list to get a chance to restart the nested rebase.
> 
> But now the entire rebase gets aborted?

Um, this example is not persuasive.  If I just leave the excess commit at 
the front of the to-do list, then it will be recreated without change.

(Note that if I choose too *small* a nubmer by accident, I can insert a 
"break" at the front of the list and then rebase --nested starting from 
there.)

Okay, but what if I screw up worse and type HEAD^55 instead of HEAD^5?
nd that includes multiple merges and other messy stuff?

Well, perhaps a general-purpose optimization could be applied: for the 
first, mandatory, edit-todo, don't actually check out the tree until the 
edit is complete.  When it is, chop off any prefix of unaltered commits 
and start the rebase at the first change.

That would make inadvertently specifying a start point too far back
reasonably harmless.

It would also provide one level of nested abort in the case of a nested 
rebase.  Until you save the initial todo, the rebase doesn't do anything 
except some bookkeeping.  So you could have that be a special case, 
without providing a more general nested --abort.

The main problem with a full nested rebase is that you need to define when 
the inner rebase completes and the outer rebase resumes.  I very much 
want the ability to move commits around between the outer rebase and the 
inner one, which makes that distinction ill-defined.

> If that would happen to me, I would unleash a whole slew of rarely used
> words in the vague direction of whoever implemented the nested rebase
> feature...

The thing is, it's already quite possible to make a mess of a rebase
halfway through and need to abort after you've put a lot of work in.

I think a more general-purpose recovery mechanism might be more
useful.

For example, if the --edit-todo included a (commented-out) list of what 
had already been done, then after realizing that you screwed up
conflict resolve b' and have now committed bad resolutions c' and d'
on top of it, you could easily rebase --nested and replace b', c' and d'
with the original b, c and d.

Without aborting and throwing away a' as well, which was perhaps a lot of
work.

>> If I delete any of those five commits, then rebase.missingCommitsCheck
>> will trigger.  If I put y in the list, save it, then change my mind and
>> --edit-todo and delete y, it will also trigger.
> 
> As I said, I am not using that feature myself, so I do not even know what
> "trigger" means in this context. It might totally be okay to use the
> existing code as-is in the context of a nested rebase. That remains to be
> verified, though, I think.

What I mean by "trigger" is thatthe check would notice a missing commit
and produce a warning or error, as configured.