{"thread":{"id":"53043","subject":"Feature request: rebase -i inside of rebase -i","startedAt":"2020-03-20T22:38:04Z","lastAt":"2020-04-07T19:03:53Z","messageCount":25,"participants":["George Spelvin","Junio C Hamano","Johannes Sixt","Johannes Schindelin","Philip Oakley","Phillip Wood","Sebastien Bruckert"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"393564","messageId":"20200320223015.GA19579@SDF.ORG","threadId":"53043","inReplyTo":null,"subject":"Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-03-20T22:30:15Z","receivedAt":"2020-03-20T22:38:04Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"I'm cleaning up a patch series for submission, and came across a fixup in\npatch #4/20 that belongs in #2/20.\n\nUnfortunately, I can't go back two patches to apply the fix until I get to \nthe end of the current rebase, then go back down to clean it up. :-(\n\nThinking about it, I realized that a rebase in a rebase is a perfectly \nwell defined operation.  *If* you don't bother setting a new abort point \n(it's not a fully nested transaction), *and* require that the tree be \nclean (no stashing allowed; create a WIP commit instead), it's just a \nmatter of putting some commits back on the front of the todo-list and \nchecking out the old version.\n\nThis would make rebase work more like quilt.\n\nI'm not sure how difficult this would be, but it might be worth looking\ninto.  (Possibly gated by an extra option like --nested.)\n\n\n(A second thing that would be nice would be a documented way to break out \nof a reword and change the commit.  A few times I've been improving\nthe documentation of a patch and realized that I should change the \nfunction name.)\n\n"},{"id":"393567","messageId":"xmqq36a2bpxz.fsf@gitster.c.googlers.com","threadId":"53043","inReplyTo":"20200320223015.GA19579@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-03-20T22:51:20Z","receivedAt":"2020-03-20T22:51:24Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"George Spelvin <lkml@SDF.ORG> writes:\n\n> I'm cleaning up a patch series for submission, and came across a fixup in\n> patch #4/20 that belongs in #2/20.\n>\n> Unfortunately, I can't go back two patches to apply the fix until I get to \n> the end of the current rebase, then go back down to clean it up. :-(\n>\n> Thinking about it, I realized that a rebase in a rebase is a perfectly \n> well defined operation.  *If* you don't bother setting a new abort point \n> (it's not a fully nested transaction), *and* require that the tree be \n> clean (no stashing allowed; create a WIP commit instead), it's just a \n> matter of putting some commits back on the front of the todo-list and \n> checking out the old version.\n\nI thought that \"git rebase -i\" allows the todo file (i.e. list of\nsteps still to be performed) to be edited before continuing; would\nyour use case be supported by using that?\n"},{"id":"393570","messageId":"20200320233528.GB19579@SDF.ORG","threadId":"53043","inReplyTo":"xmqq36a2bpxz.fsf@gitster.c.googlers.com","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-03-20T23:35:28Z","receivedAt":"2020-03-20T23:35:41Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"On Fri, Mar 20, 2020 at 03:51:20PM -0700, Junio C Hamano wrote:\n> I thought that \"git rebase -i\" allows the todo file (i.e. list of\n> steps still to be performed) to be edited before continuing; would\n> your use case be supported by using that?\n\nMostly, if I do it very carefully, which is why I thought it would\nbe easy to add.\n\nI think I could manually add the commits to the start of the todo file,\nreset --hard to the old state, and rebase --continue.\n\nBut cutting and pasting commit IDs from git log into the todo file,\nand putting fixup commits in the right place is annoyingly fiddly.\nThat's exactly the sort of thing computers are good at.\n"},{"id":"393585","messageId":"35c25a8e-f526-e5c9-5dc1-ef02315a1e97@kdbg.org","threadId":"53043","inReplyTo":"20200320223015.GA19579@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2020-03-21T08:47:41Z","receivedAt":"2020-03-21T08:51:37Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 20.03.20 um 23:30 schrieb George Spelvin:\n> I'm cleaning up a patch series for submission, and came across a fixup in\n> patch #4/20 that belongs in #2/20.\n> \n> Unfortunately, I can't go back two patches to apply the fix until I get to \n> the end of the current rebase, then go back down to clean it up. :-(\n\nIn such cases, I usually\n\n- unstage the changes of the current commit\n- stage the fixup\n- `git commit --fixup @~2`\n- stage what I had unstaged first\n- then continue\n\nAt the end of the current rebase, a `git rebase -i --autosquash` does\nthe final cleanup.\n\n-- Hannes\n"},{"id":"393613","messageId":"nycvar.QRO.7.76.6.2003211135380.46@tvgsbejvaqbjf.bet","threadId":"53043","inReplyTo":"20200320233528.GB19579@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-03-21T10:51:10Z","receivedAt":"2020-03-21T10:51:20Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 20 Mar 2020, George Spelvin wrote:\n\n> On Fri, Mar 20, 2020 at 03:51:20PM -0700, Junio C Hamano wrote:\n> > I thought that \"git rebase -i\" allows the todo file (i.e. list of\n> > steps still to be performed) to be edited before continuing; would\n> > your use case be supported by using that?\n>\n> Mostly, if I do it very carefully, which is why I thought it would\n> be easy to add.\n>\n> I think I could manually add the commits to the start of the todo file,\n> reset --hard to the old state, and rebase --continue.\n>\n> But cutting and pasting commit IDs from git log into the todo file,\n> and putting fixup commits in the right place is annoyingly fiddly.\n> That's exactly the sort of thing computers are good at.\n\nFWIW I have a super-hacky work-around for this use case that I am using in\nmy automation of continuously rebasing Git for Windows' `master` onto the\nfour integration branches of git.git:\n\n1. create a throw-away worktree without checking out the commit\n\n2. fake-run a new `rebase -i` in that worktree, with a custom \"editor\"\n   (which is actually the same script) that simply consumes the todo list,\n   aborts the `rebase -i` in the worktree, then deletes the worktree, and\n   then inserts that todo list in the original todo list.\n\n3. continue the rebase\n\nI never got around to implement that as a proper \"nested\" mode of `git\nrebase -i`, but it should not be too hard. The user interface would\nprobably look somewhat like `git rebase -i --nested <arguments>...` and it\nwould _expect_ an active interactive rebase, and it would insert the todo\nlist into the existing one, at the beginning, with proper commenting, then\nreset `HEAD` after the user edited the todo list.\n\nMy biggest caveat is that I had to force-exit the rebase at some stage\ndue to reasons I only vaguely remember. It had something to do with the\nreplacement cache not being updated when an `exec` is executed that adds a\nreplacement object via `git replace` [*1*]. This issue might have\n_nothing_ to do with nested rebases, but as I said, my recollection is\nvague.\n\nThere are a couple more concerns, of course, such as: what to do if the\nuser deletes the entire todo list (which is traditionally the only way to\nabort a rebase)? My gut feeling is that it should go back to the\n_previous_ version of the todo list.\n\nAnother big concern is what to do about `rebase.missingCommitsCheck`: with\nnested rebases, this will get increasingly tricky. Like, imagine you are\nrebasing 5 commits, the third of them results in merge conflicts, you\nrealize that it is obsolete and so is now the first, already rebased\ncommit. You do a nested rebase of the latest two commits to drop them, but\nthey don't have their original commit hashes any longer. So it gets a bit\nfinicky to keep track of what commit has been dropped on purpose and what\nwas forgotten to pick instead.\n\nCiao,\nDscho\n\nFootnote *1*: to refresh my recollection, I would have to scour the\nhistory of the automation script, see\nhttps://github.com/git-for-windows/build-extra/commits/master/ever-green.sh\n"},{"id":"393630","messageId":"20200321175612.GC19579@SDF.ORG","threadId":"53043","inReplyTo":"nycvar.QRO.7.76.6.2003211135380.46@tvgsbejvaqbjf.bet","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-03-21T17:56:12Z","receivedAt":"2020-03-21T17:56:30Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"On Sat, Mar 21, 2020 at 11:51:10AM +0100, Johannes Schindelin wrote:\n> My biggest caveat is that I had to force-exit the rebase at some stage\n> due to reasons I only vaguely remember. It had something to do with the\n> replacement cache not being updated when an `exec` is executed that adds a\n> replacement object via `git replace` [*1*]. This issue might have\n> _nothing_ to do with nested rebases, but as I said, my recollection is\n> vague.\n\nThis is the sort of internal implementation gotcha I worry about.\n\n> There are a couple more concerns, of course, such as: what to do if the\n> user deletes the entire todo list (which is traditionally the only way to\n> abort a rebase)? My gut feeling is that it should go back to the\n> _previous_ version of the todo list.\n\nMy assumption has been that, for simplicity, there would only be one \ncommit in progress, and aborting it aborts everything.\n\n> Another big concern is what to do about `rebase.missingCommitsCheck`: with\n> nested rebases, this will get increasingly tricky. Like, imagine you are\n> rebasing 5 commits, the third of them results in merge conflicts, you\n> realize that it is obsolete and so is now the first, already rebased\n> commit. You do a nested rebase of the latest two commits to drop them, but\n> they don't have their original commit hashes any longer. So it gets a bit\n> finicky to keep track of what commit has been dropped on purpose and what\n> was forgotten to pick instead.\n\nThis doesn't *seem* difficult, but I don't know how the current mechanism\nworks.\n\nIt just checks that all commits that were on the to-do list when the \neditor started are still listed (possibly marked \"drop\") when it exits.\n\nWhen you do a nested commit, additional commits are prepended to the to-do \nlist, you're dropped into the editor, and the same check is made when the \neditor returns.\n\nIf rebase.missingCommitsCheck = error is triggered, you end up with the \n<upstream> tree state with nothing applied and may either --continue to \nignore the error or --edit-todo to put back the missing commits.\n\n\nLet me give an example.  Suppose I have commits a-b-c-d-e, and start\nwith rebase -i b.\n\nMy to-do list starts out as c-d-e, but suppose I decide to cherry-pick\nz and add it to the list, so it's now z-c-d-e.\n\nSo I start rebasing, and it turns out that d creates a merge conflict\nbecause I forgot a prerequisite patch y.  And I really want y and z before\nb, anyway.\n\nSo the tree state is currently a-b-z'-c', with d in progress and e yet to \ndo.  In my simple model, I have to resolve and commit d, so the tree\nstate is a-b-z'-c'-d'.  Then I can rebase -i a, and am presented with\na to-do list of b-z'-c'-d'-e.\n\nIf I delete any of those five commits, then rebase.missingCommitsCheck \nwill trigger.  If I put y in the list, save it, then change my mind and\n--edit-todo and delete y, it will also trigger.\n\nNow, it sould be nice if there were a way to say \"screw this mess; just\ncheck out HEAD and put d back on the to-do list\", but that could \ncreate a bit of a mess if I've split d and already committed half of \nit.  If I used that after doung that, I'd have a to-do list of \nb-z'-c'-d'-d-e which might be awkward, but maybe it wouldn't be too bad.\n"},{"id":"393997","messageId":"nycvar.QRO.7.76.6.2003252008490.46@tvgsbejvaqbjf.bet","threadId":"53043","inReplyTo":"20200321175612.GC19579@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-03-25T19:26:48Z","receivedAt":"2020-03-25T19:27:00Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi George,\n\nOn Sat, 21 Mar 2020, George Spelvin wrote:\n\n> On Sat, Mar 21, 2020 at 11:51:10AM +0100, Johannes Schindelin wrote:\n> > My biggest caveat is that I had to force-exit the rebase at some stage\n> > due to reasons I only vaguely remember. It had something to do with the\n> > replacement cache not being updated when an `exec` is executed that adds a\n> > replacement object via `git replace` [*1*]. This issue might have\n> > _nothing_ to do with nested rebases, but as I said, my recollection is\n> > vague.\n>\n> This is the sort of internal implementation gotcha I worry about.\n\nThere's plenty more gotchas like that ;-)\n\n> > There are a couple more concerns, of course, such as: what to do if the\n> > user deletes the entire todo list (which is traditionally the only way to\n> > abort a rebase)? My gut feeling is that it should go back to the\n> > _previous_ version of the todo list.\n>\n> My assumption has been that, for simplicity, there would only be one\n> commit in progress, and aborting it aborts everything.\n\nBut that does not necessarily make sense. Imagine that you rebase the\nlatest three commits, interactively. Then a merge conflict in the third\nmakes you realize that the first commit is no longer needed.\n\nEnter the nested rebase. You manually re-schedule the failed `pick` via\n`git rebase --edit-todo` and then run the nested rebase: `git reset --hard\n&& git rebase -i --nested HEAD~2`.\n\nExcept that you made a typo and said `HEAD~3` instead of `HEAD~2`. You\ndelete the entire todo list to get a chance to restart the nested rebase.\n\nBut now the entire rebase gets aborted?\n\nIf that would happen to me, I would unleash a whole slew of rarely used\nwords in the vague direction of whoever implemented the nested rebase\nfeature...\n\n> > Another big concern is what to do about `rebase.missingCommitsCheck`: with\n> > nested rebases, this will get increasingly tricky. Like, imagine you are\n> > rebasing 5 commits, the third of them results in merge conflicts, you\n> > realize that it is obsolete and so is now the first, already rebased\n> > commit. You do a nested rebase of the latest two commits to drop them, but\n> > they don't have their original commit hashes any longer. So it gets a bit\n> > finicky to keep track of what commit has been dropped on purpose and what\n> > was forgotten to pick instead.\n>\n> This doesn't *seem* difficult, but I don't know how the current mechanism\n> works.\n\nThe implementation details do not matter at this stage. You have to get\nthe design of the feature right.\n\nI am unfamiliar with the design of the feature as it is implemented right\nnow, but I imagine that it needs to be adjusted for nested rebases, as we\nno longer have a single original todo list to roll back to.\n\n> It just checks that all commits that were on the to-do list when the\n> editor started are still listed (possibly marked \"drop\") when it exits.\n>\n> When you do a nested commit, additional commits are prepended to the to-do\n> list, you're dropped into the editor, and the same check is made when the\n> editor returns.\n>\n> If rebase.missingCommitsCheck = error is triggered, you end up with the\n> <upstream> tree state with nothing applied and may either --continue to\n> ignore the error or --edit-todo to put back the missing commits.\n>\n>\n> Let me give an example.  Suppose I have commits a-b-c-d-e, and start\n> with rebase -i b.\n>\n> My to-do list starts out as c-d-e, but suppose I decide to cherry-pick\n> z and add it to the list, so it's now z-c-d-e.\n>\n> So I start rebasing, and it turns out that d creates a merge conflict\n> because I forgot a prerequisite patch y.  And I really want y and z before\n> b, anyway.\n>\n> So the tree state is currently a-b-z'-c', with d in progress and e yet to\n> do.  In my simple model, I have to resolve and commit d, so the tree\n> state is a-b-z'-c'-d'.  Then I can rebase -i a, and am presented with\n> a to-do list of b-z'-c'-d'-e.\n>\n> If I delete any of those five commits, then rebase.missingCommitsCheck\n> will trigger.  If I put y in the list, save it, then change my mind and\n> --edit-todo and delete y, it will also trigger.\n\nAs I said, I am not using that feature myself, so I do not even know what\n\"trigger\" means in this context. It might totally be okay to use the\nexisting code as-is in the context of a nested rebase. That remains to be\nverified, though, I think.\n\n> Now, it sould be nice if there were a way to say \"screw this mess; just\n> check out HEAD and put d back on the to-do list\", but that could\n> create a bit of a mess if I've split d and already committed half of\n> it.  If I used that after doung that, I'd have a to-do list of\n> b-z'-c'-d'-d-e which might be awkward, but maybe it wouldn't be too bad.\n\nThere is all kind of opportunity for messes, all right.\n\nCiao,\nJohannes\n"},{"id":"394032","messageId":"20200326001821.GB8865@SDF.ORG","threadId":"53043","inReplyTo":"nycvar.QRO.7.76.6.2003252008490.46@tvgsbejvaqbjf.bet","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-03-26T00:18:21Z","receivedAt":"2020-03-26T00:18:31Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"On Wed, Mar 25, 2020 at 08:26:48PM +0100, Johannes Schindelin wrote:\n> On Sat, 21 Mar 2020, George Spelvin wrote:\n>> My assumption has been that, for simplicity, there would only be one\n>> commit in progress, and aborting it aborts everything.\n>\n> But that does not necessarily make sense. Imagine that you rebase the\n> latest three commits, interactively. Then a merge conflict in the third\n> makes you realize that the first commit is no longer needed.\n> \n> Enter the nested rebase. You manually re-schedule the failed `pick` via\n> `git rebase --edit-todo` and then run the nested rebase: `git reset --hard\n> && git rebase -i --nested HEAD~2`.\n> \n> Except that you made a typo and said `HEAD~3` instead of `HEAD~2`. You\n> delete the entire todo list to get a chance to restart the nested rebase.\n> \n> But now the entire rebase gets aborted?\n\nUm, this example is not persuasive.  If I just leave the excess commit at \nthe front of the to-do list, then it will be recreated without change.\n\n(Note that if I choose too *small* a nubmer by accident, I can insert a \n\"break\" at the front of the list and then rebase --nested starting from \nthere.)\n\nOkay, but what if I screw up worse and type HEAD^55 instead of HEAD^5?\nnd that includes multiple merges and other messy stuff?\n\nWell, perhaps a general-purpose optimization could be applied: for the \nfirst, mandatory, edit-todo, don't actually check out the tree until the \nedit is complete.  When it is, chop off any prefix of unaltered commits \nand start the rebase at the first change.\n\nThat would make inadvertently specifying a start point too far back\nreasonably harmless.\n\nIt would also provide one level of nested abort in the case of a nested \nrebase.  Until you save the initial todo, the rebase doesn't do anything \nexcept some bookkeeping.  So you could have that be a special case, \nwithout providing a more general nested --abort.\n\nThe main problem with a full nested rebase is that you need to define when \nthe inner rebase completes and the outer rebase resumes.  I very much \nwant the ability to move commits around between the outer rebase and the \ninner one, which makes that distinction ill-defined.\n\n> If that would happen to me, I would unleash a whole slew of rarely used\n> words in the vague direction of whoever implemented the nested rebase\n> feature...\n\nThe thing is, it's already quite possible to make a mess of a rebase\nhalfway through and need to abort after you've put a lot of work in.\n\nI think a more general-purpose recovery mechanism might be more\nuseful.\n\nFor example, if the --edit-todo included a (commented-out) list of what \nhad already been done, then after realizing that you screwed up\nconflict resolve b' and have now committed bad resolutions c' and d'\non top of it, you could easily rebase --nested and replace b', c' and d'\nwith the original b, c and d.\n\nWithout aborting and throwing away a' as well, which was perhaps a lot of\nwork.\n\n>> If I delete any of those five commits, then rebase.missingCommitsCheck\n>> will trigger.  If I put y in the list, save it, then change my mind and\n>> --edit-todo and delete y, it will also trigger.\n> \n> As I said, I am not using that feature myself, so I do not even know what\n> \"trigger\" means in this context. It might totally be okay to use the\n> existing code as-is in the context of a nested rebase. That remains to be\n> verified, though, I think.\n\nWhat I mean by \"trigger\" is thatthe check would notice a missing commit\nand produce a warning or error, as configured.\n"},{"id":"394228","messageId":"nycvar.QRO.7.76.6.2003281510260.46@tvgsbejvaqbjf.bet","threadId":"53043","inReplyTo":"20200326001821.GB8865@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-03-28T14:25:06Z","receivedAt":"2020-03-28T14:25:14Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi George,\n\nOn Thu, 26 Mar 2020, George Spelvin wrote:\n\n> On Wed, Mar 25, 2020 at 08:26:48PM +0100, Johannes Schindelin wrote:\n> > On Sat, 21 Mar 2020, George Spelvin wrote:\n> >> My assumption has been that, for simplicity, there would only be one\n> >> commit in progress, and aborting it aborts everything.\n> >\n> > But that does not necessarily make sense. Imagine that you rebase the\n> > latest three commits, interactively. Then a merge conflict in the third\n> > makes you realize that the first commit is no longer needed.\n> >\n> > Enter the nested rebase. You manually re-schedule the failed `pick` via\n> > `git rebase --edit-todo` and then run the nested rebase: `git reset --hard\n> > && git rebase -i --nested HEAD~2`.\n> >\n> > Except that you made a typo and said `HEAD~3` instead of `HEAD~2`. You\n> > delete the entire todo list to get a chance to restart the nested rebase.\n> >\n> > But now the entire rebase gets aborted?\n>\n> Um, this example is not persuasive.  If I just leave the excess commit at\n> the front of the to-do list, then it will be recreated without change.\n\nThere are _many_ ways to mess up a nested rebase, including (but not\nlimited to) `--onto`, forgetting `-r`, editing the todo list too much in\nan editor without undo.\n\nIf you are suggesting that a nested `git rebase -i` would not need a way\nto abort _just_ the nested rebase, then I fear we must stop the\nconversation right here. That's not going to fly.\n\n> (Note that if I choose too *small* a nubmer by accident, I can insert a\n> \"break\" at the front of the list and then rebase --nested starting from\n> there.)\n\nThere are many ways how a savvy user would be able to work around the\nabsence of a proper way to abort a nested rebase. The common theme for all\nof those is:\n\n- they are all quite involved and require knowledge of internals\n\n- they won't change the fact that it would be seriously negligent for us\n  to _not_ offer a way to abort nested rebases.\n\n> Okay, but what if I screw up worse and type HEAD^55 instead of HEAD^5?\n> nd that includes multiple merges and other messy stuff?\n\nAnd Ctrl+C while the nested rebase tries to generate the todo list.\n\n> Well, perhaps a general-purpose optimization could be applied: for the\n> first, mandatory, edit-todo, don't actually check out the tree until the\n> edit is complete.  When it is, chop off any prefix of unaltered commits\n> and start the rebase at the first change.\n>\n> That would make inadvertently specifying a start point too far back\n> reasonably harmless.\n>\n> It would also provide one level of nested abort in the case of a nested\n> rebase.  Until you save the initial todo, the rebase doesn't do anything\n> except some bookkeeping.  So you could have that be a special case,\n> without providing a more general nested --abort.\n>\n> The main problem with a full nested rebase is that you need to define when\n> the inner rebase completes and the outer rebase resumes.  I very much\n> want the ability to move commits around between the outer rebase and the\n> inner one, which makes that distinction ill-defined.\n\nThat probably means that we have not thought through the problem, at least\nnot enough. If we have nested levels, then we might need to record those\nnested levels, including the equivalent of `ORIG_HEAD`, `onto` and the\ntodo list. And of course make them accessible to the user.\n\nBy default, we can still work on the \"inner-most\" rebase. The output of\n`git status` can hint at the nested level, to give an indication, as can\nthe prompt.\n\nWe should strive to make this as easy to use as possible, while still\nsupporting more involved use cases (for power users such as myself, at the\nleast).\n\nMind you: I do not necessarily request a perfect design. I just don't want\nto slam the door shut when it comes to more sophisticated use cases. I\n_really_ would like to have a way to \"just redo the latest 5 commands\",\nfor example, but I have no illusion about getting that any time soon.\n\n> > If that would happen to me, I would unleash a whole slew of rarely used\n> > words in the vague direction of whoever implemented the nested rebase\n> > feature...\n>\n> The thing is, it's already quite possible to make a mess of a rebase\n> halfway through and need to abort after you've put a lot of work in.\n\nTell me about it!\n\n> I think a more general-purpose recovery mechanism might be more\n> useful.\n>\n> For example, if the --edit-todo included a (commented-out) list of what\n> had already been done, then after realizing that you screwed up\n> conflict resolve b' and have now committed bad resolutions c' and d'\n> on top of it, you could easily rebase --nested and replace b', c' and d'\n> with the original b, c and d.\n>\n> Without aborting and throwing away a' as well, which was perhaps a lot of\n> work.\n\nWe do have the `done` file, but that does not discern between commands\nin the todo list that have been there in the first place and commands that\nhave been added by the user _during_ the rebase. And of course it does not\nreflect any commands that have been removed/changed by the user during the\nrebase.\n\nSo yeah, something like a journal, maybe.\n\n> >> If I delete any of those five commits, then rebase.missingCommitsCheck\n> >> will trigger.  If I put y in the list, save it, then change my mind and\n> >> --edit-todo and delete y, it will also trigger.\n> >\n> > As I said, I am not using that feature myself, so I do not even know what\n> > \"trigger\" means in this context. It might totally be okay to use the\n> > existing code as-is in the context of a nested rebase. That remains to be\n> > verified, though, I think.\n>\n> What I mean by \"trigger\" is thatthe check would notice a missing commit\n> and produce a warning or error, as configured.\n\nI guess `missingCOmmitsCheck` really only kicks in right before/after the\nuser edits the todo list. So maybe I was worried for nothing in this\ninstance.\n\nThank you for thinking about this feature, and for discussing it with me.\nI think it will be a really nice feature to have, and I want to avoid\nproblems with a design that simply won't allow for certain use cases\n(remember how `git rebase --preserve-merges` does not allow for reordering\ncommits, and how the design of that feature simply made this bug\nunfixable? I _dearly_ regret not thinking that through).\n\nCiao,\nDscho\n"},{"id":"394238","messageId":"20200328163024.GA26885@SDF.ORG","threadId":"53043","inReplyTo":"nycvar.QRO.7.76.6.2003281510260.46@tvgsbejvaqbjf.bet","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-03-28T16:30:24Z","receivedAt":"2020-03-28T16:30:40Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"On Sat, Mar 28, 2020 at 03:25:06PM +0100, Johannes Schindelin wrote:\n> There are _many_ ways to mess up a nested rebase, including (but not\n> limited to) `--onto`, forgetting `-r`, editing the todo list too much in\n> an editor without undo.\n> \n> If you are suggesting that a nested `git rebase -i` would not need a way\n> to abort _just_ the nested rebase, then I fear we must stop the\n> conversation right here. That's not going to fly.\n\nYes, I'm seriously suggesting that.  My arguments are:\n\n* The benefit is limited, because you can do pretty much all the\n  same things with just plain --edit-todo, and I don't see the\n  point of handing the user a loaded gun and ensuring they can't\n  shoot themselves in their *left* foot.\n\n* The cost in implementation complexity is considerable.  Even the\n  *semantics* are awkward.  In particular, if you reorder patches\n  between the outer and inner rebases, how do you define the end of\n  the inner rebase?\n\nNow, I *did* agree that being able to abort just the nested rebase\n*from the initial todo edit* is useful and achievable.  That can\nbe handled as a special case.  It's allowing \"git rebase --abort\"\nfrom halfway throuigh the nested rebasethat introduces all kinds\nof hair.\n\n>> The main problem with a full nested rebase is that you need to define when\n>> the inner rebase completes and the outer rebase resumes.  I very much\n>> want the ability to move commits around between the outer rebase and the\n>> inner one, which makes that distinction ill-defined.\n> \n> That probably means that we have not thought through the problem, at least\n> not enough. If we have nested levels, then we might need to record those\n> nested levels, including the equivalent of `ORIG_HEAD`, `onto` and the\n> todo list. And of course make them accessible to the user.\n\nI worry that's too much conceptual complexity being foisted on the user.\n\n> Mind you: I do not necessarily request a perfect design. I just don't want\n> to slam the door shut when it comes to more sophisticated use cases. I\n> _really_ would like to have a way to \"just redo the latest 5 commands\",\n> for example, but I have no illusion about getting that any time soon.\n\nThe big use cases I see are:\n- Wanting to back up in the current rebase, \"quilt pop\" style.\n  Many times I've found a hunk in patch #4 that should have been\n  part of patch #2.\n- Wanting to move the base back a bit further than originally\n  planned.  (This is often an alternate form of the preceeding;\n  I find a hunk that should have been in patch #-2.)\n- Wanting to rearrange commits across the current commit.  I've\n  gone and edited patch #4 and introduced a dependency on patch #7.\n  I want to move patch #7 back so that my revised #4 can be tested.\n\nI think of the feature as an \"edit-todo\" that includes some already-\napplied patches.\n\n>> The thing is, it's already quite possible to make a mess of a rebase\n>> halfway through and need to abort after you've put a lot of work in.\n> \n> Tell me about it!\n\nThus, my comment above about protecting the user's left foot.  If\nthey still need to be careful to not shoot off their right foot,\nare we saving them any mental effort?\n\nMy goal for the nested-rebase feature is that it can be useful for\n*recovering* from such messes.  Back up a few steps to before the\ntrouble started, but *not* a full abort.\n\n>> I think a more general-purpose recovery mechanism might be more\n>> useful.\n>>\n>> For example, if the --edit-todo included a (commented-out) list of what\n>> had already been done, then after realizing that you screwed up\n>> conflict resolve b' and have now committed bad resolutions c' and d'\n>> on top of it, you could easily rebase --nested and replace b', c' and d'\n>> with the original b, c and d.\n>>\n>> Without aborting and throwing away a' as well, which was perhaps a lot of\n>> work.\n> \n> We do have the `done` file, but that does not discern between commands\n> in the todo list that have been there in the first place and commands that\n> have been added by the user _during_ the rebase. And of course it does not\n> reflect any commands that have been removed/changed by the user during the\n> rebase.\n> \n> So yeah, something like a journal, maybe.\n\nI was thinking of the \"done\" file.  At a low level, we already have\nthe reflog, and giving the user yet another transaction log to remember\nis undesirable.\n\nIf we just added the original commit ID to the automatically\ngenerated reflog entry, si it also records the higher-level intention,\nthat might do it.  I.e. change\n\nbc56134cfe278 HEAD@{3}: rebase (pick): wilc1000: Use crc7 in lib/ rather than a private copy\n\tto\nbc56134cfe278 HEAD@{3}: rebase (pick 01cb7b5b7851): wilc1000: Use crc7 in lib/ rather than a private copy\n\nOh!  What if we recorded, for the duration of the rebase, the todo\nlist state corresponding to reflog entries?  (Or, equivalently,\nthe reflog state at each step through the todo list.)  Then we\ncould back up the rebase with just a reflog entry pointer.\n\nI like this precisely because it doesn't give the user a new entity\nto keep track of; it just makes an existing entity more useful.\n\n> Thank you for thinking about this feature, and for discussing it with me.\n> I think it will be a really nice feature to have, and I want to avoid\n> problems with a design that simply won't allow for certain use cases\n> (remember how `git rebase --preserve-merges` does not allow for reordering\n> commits, and how the design of that feature simply made this bug\n> unfixable? I _dearly_ regret not thinking that through).\n\nDefinitely, let's think it through.  But remember that \"perfection\nis achieved, not when there is nothing more to add, but when there\nis nothing left to take away.\"  KISS is a design *goal*, not just\na necessary compromise.\n"},{"id":"394354","messageId":"0eef4721-1646-48f2-1102-71159d06b049@iee.email","threadId":"53043","inReplyTo":"nycvar.QRO.7.76.6.2003281510260.46@tvgsbejvaqbjf.bet","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2020-03-30T14:01:28Z","receivedAt":"2020-03-30T14:01:37Z","isPatch":false,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi all,\n\nOn 28/03/2020 14:25, Johannes Schindelin wrote:\n> Hi George,\n>\n> On Thu, 26 Mar 2020, George Spelvin wrote:\n>\n>> On Wed, Mar 25, 2020 at 08:26:48PM +0100, Johannes Schindelin wrote:\n>>> On Sat, 21 Mar 2020, George Spelvin wrote:\n>>>> My assumption has been that, for simplicity, there would only be one\n>>>> commit in progress, and aborting it aborts everything.\n>>> But that does not necessarily make sense. Imagine that you rebase the\n>>> latest three commits, interactively. Then a merge conflict in the third\n>>> makes you realize that the first commit is no longer needed.\n>>>\n>>> Enter the nested rebase. You manually re-schedule the failed `pick` via\n>>> `git rebase --edit-todo` and then run the nested rebase: `git reset --hard\n>>> && git rebase -i --nested HEAD~2`.\n>>>\n>>> Except that you made a typo and said `HEAD~3` instead of `HEAD~2`. You\n>>> delete the entire todo list to get a chance to restart the nested rebase.\n>>>\n>>> But now the entire rebase gets aborted?\n>> Um, this example is not persuasive.  If I just leave the excess commit at\n>> the front of the to-do list, then it will be recreated without change.\n> There are _many_ ways to mess up a nested rebase, including (but not\n> limited to) `--onto`, forgetting `-r`, editing the todo list too much in\n> an editor without undo.\n>\n> If you are suggesting that a nested `git rebase -i` would not need a way\n> to abort _just_ the nested rebase, then I fear we must stop the\n> conversation right here. That's not going to fly.\n>\n>> (Note that if I choose too *small* a nubmer by accident, I can insert a\n>> \"break\" at the front of the list and then rebase --nested starting from\n>> there.)\n> There are many ways how a savvy user would be able to work around the\n> absence of a proper way to abort a nested rebase. The common theme for all\n> of those is:\n>\n> - they are all quite involved and require knowledge of internals\n>\n> - they won't change the fact that it would be seriously negligent for us\n>   to _not_ offer a way to abort nested rebases.\n>\nPerhaps we can go the other way on this one.\n\nI'd agree that attempting to nest (misunderstood mistaken) rebases is\ndigging a too deep hole that we'd not get out of. However we do have\nother rebases available, specifically the \"rebasing merges\"\nhttps://git-scm.com/docs/git-rebase#_rebasing_merges.\n\nI know rebasing merges is way down the man page, but it has all the\npower and flexibility needed _if_ we can step across from the mistaken\nrebase step (we are at the command prompt aren't we?) into the rebasing\nmerge mode.\n\nThis will require a little bit of expansion of the insn (instruction)\nsheet so as to _include commented lines of the rebase steps completed_\nso far, along with the labels, resets, merges, etc, so that the user can\n_see_ where they they are within their failed progress (along with a\ntitle line telling them their initial command and that they are now on a\nrebasing merge insn;-).\n\nFrom there they can update the insn to reset back to the correct point,\nredo the correct picks, and then get back to their remaining rebase steps.\n\nIt's a thought anyway.\n\nHTH\n\nPhilip\n\n\n"},{"id":"394389","messageId":"20200330181812.GB9199@SDF.ORG","threadId":"53043","inReplyTo":"0eef4721-1646-48f2-1102-71159d06b049@iee.email","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-03-30T18:18:12Z","receivedAt":"2020-03-30T18:18:33Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"On Mon, Mar 30, 2020 at 03:01:28PM +0100, Philip Oakley wrote:\n> Perhaps we can go the other way on this one.\n> \n> I'd agree that attempting to nest (misunderstood mistaken) rebases is\n> digging a too deep hole that we'd not get out of. However we do have\n> other rebases available, specifically the \"rebasing merges\"\n> https://git-scm.com/docs/git-rebase#_rebasing_merges.\n> \n> I know rebasing merges is way down the man page, but it has all the\n> power and flexibility needed _if_ we can step across from the mistaken\n> rebase step (we are at the command prompt aren't we?) into the rebasing\n> merge mode.\n> \n> This will require a little bit of expansion of the insn (instruction)\n> sheet so as to _include commented lines of the rebase steps completed_\n> so far, along with the labels, resets, merges, etc, so that the user can\n> _see_ where they they are within their failed progress (along with a\n> title line telling them their initial command and that they are now on a\n> rebasing merge insn;-).\n> \n> From there they can update the insn to reset back to the correct point,\n> redo the correct picks, and then get back to their remaining rebase steps.\n> \n> It's a thought anyway.\n\nI'm confused.  *How* does --rebase-merge mode help?  You're saying\n\"hey, if we use this, it solves the issue\" but I don't see how to\npound this nail with that screwdriver.\n\nI don't see how creating a branching history helps, and I don't see how to \nuse the reset/label/merge commands to do anything but create a branching \nhistory.\n\nI suppose it is possible to use the \"reset\" command in isolation\nto describe the jump to a new base.  So you could have a history of:\n\n# Command already executed:\n# reset base\n# pick A\n# pick B\n# pick C\n# label rebase-1  User asked for a nested rebase\n# reset A'\n\n# Commands pending:\npick B'\npick C'\n# rebase-2 complete, resume rebase-1\npick D\npick E\n\nIs that what you were getting at?\n\nI was thinking of it being implicit, but it might be nice for the initial\n\"reset\" in each rebase to be explicit, *and not yet executed during\nthe initial todo edit*.\n\nThat makes it really clear that deleting the todo list entirely\nresults in no change to the tree.\n"},{"id":"394395","messageId":"8f6fb826-7f9f-57ea-725f-dc3c512a4b18@iee.email","threadId":"53043","inReplyTo":"20200330181812.GB9199@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2020-03-30T21:53:05Z","receivedAt":"2020-03-30T21:53:16Z","isPatch":false,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi George,\n\nI wasn't suggesting that there already exists a complete solution...\n\nOn 30/03/2020 19:18, George Spelvin wrote:\n> On Mon, Mar 30, 2020 at 03:01:28PM +0100, Philip Oakley wrote:\n>> Perhaps we can go the other way on this one.\n>>\n>> I'd agree that attempting to nest (misunderstood mistaken) rebases is\n>> digging a too deep hole that we'd not get out of. However we do have\n>> other rebases available, specifically the \"rebasing merges\"\n>> https://git-scm.com/docs/git-rebase#_rebasing_merges.\n\nI was mainly saying that folks like their \"all on one page, flow chart\nsequence planning\", and that we already have something close to that\nthat could be extended.  \n>>\n>> I know rebasing merges is way down the man page, but it has all the\n>> power and flexibility needed _if_ we can step across from the mistaken\n>> rebase step (we are at the command prompt aren't we?) into the rebasing\n>> merge mode.\n>>\n>> This will require a little bit of expansion of the insn (instruction)\n>> sheet so as to _include commented lines of the rebase steps completed_\n>> so far, along with the labels, resets, merges, etc, so that the user can\n>> _see_ where they they are within their failed progress (along with a\n>> title line telling them their initial command and that they are now on a\n>> rebasing merge insn;-).\n>>\n>> From there they can update the insn to reset back to the correct point,\n>> redo the correct picks, and then get back to their remaining rebase steps.\n>>\n>> It's a thought anyway.\n> I'm confused.  *How* does --rebase-merge mode help?  You're saying\n> \"hey, if we use this, it solves the issue\" but I don't see how to\n> pound this nail with that screwdriver.\nRemember that rebasing is just a variant of creating and building a new\nbranch in our WORM (Write once Read many) repo..\nSo it is \"just\" a case of taking the partially complete rebase, and\nre-working it, just like you can with an arbitrary merging rebase.\n>\n> I don't see how creating a branching history helps, and I don't see how to \n> use the reset/label/merge commands to do anything but create a branching \n> history.\n\nIt is more that we could create a full instruction sheet that spans time\nfrom the start of the rebase (including labelling and resetting to get\nstarted), upto and including the current state (so you can pick from\nyour new commits[*]), with those history steps being hash \"#\" commented,\nas well as the remaining rebase instructions.\n> I suppose it is possible to use the \"reset\" command in isolation\n> to describe the jump to a new base.  So you could have a history of:\n>\n> # Command already executed:\n#git rebase <command options> (for reference & immediate use)\n> # reset base\n> # pick A\n> # pick B\n> # pick C\n> # label rebase-1  User asked for a nested rebase\n> # reset A'\n[*] We are missing a list of the current state of new commits,\n# reset base (done, see above)\n# placed A' (you'll need this listed if you need to pick/edit/reword\n#  You are now at deadbeef, rebasing 23 of 75 commits .... (..suitable\nstatus message)\n\n\n> # Commands pending:\n> pick B'\n> pick C'\n> # rebase-2 complete, resume rebase-1\n> pick D\n> pick E\n>\n> Is that what you were getting at?\n\nCorrect. Given the global state problem, and the mental picture issues,\nlet's give the user a full picture, flow chart style (it's a solid old\ntechnique that works well, even for beginners)\n>\n> I was thinking of it being implicit, but it might be nice for the initial\n> \"reset\" in each rebase to be explicit, *and not yet executed during\n> the initial todo edit*.\n>\n> That makes it really clear that deleting the todo list entirely\n> results in no change to the tree. (folks rarely notice omissions, we'll still need to tell them that it's a valid solution! sometimes empty means 'no change, carry on what you were doing';-)\n\nPhilip\n"},{"id":"394397","messageId":"20200331000018.GD9199@SDF.ORG","threadId":"53043","inReplyTo":"20200328163024.GA26885@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-03-31T00:00:18Z","receivedAt":"2020-03-31T00:00:36Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"Thinking about Philip Oakley's suggestion, it dawned on me that\nwe can *already* do a nested rebase manually, and having a less\nmanual alias for the procedure would be reasonable.\n\nSuppose the last four commits are O-A-B-C, and whether they were created \nby this rebase or existed before is irrelevant.\n\nIf I want to rebase --nested -i O, then I --edit-todo and\nprepend the following four lines:\nreset O\npick A\npick B\npick C\n\nIf a nested rebase command does just that, I think it would cover my\nuse case.  If it adds a comment saying \"nested rebase ends here\",\nit's easy to cancel the nested rebase if there was a mistake.\n\nA slightly fancier thing a nestrd rebase could do is see if any of the \nnewly created picks are also used in merges that were already in the todo \nlist.  In that case, follow the pick by a label command and update the \nlater merge to refer to the label.\n"},{"id":"394409","messageId":"7fbe0ddc-74a3-b6b5-09b1-bff171382d0e@iee.email","threadId":"53043","inReplyTo":"20200331000018.GD9199@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2020-03-31T10:57:16Z","receivedAt":"2020-03-31T10:57:24Z","isPatch":false,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi george,\n\nOn 31/03/2020 01:00, George Spelvin wrote:\n> Thinking about Philip Oakley's suggestion, it dawned on me that\n> we can *already* do a nested rebase manually, and having a less\n> manual alias for the procedure would be reasonable.\n>\n> Suppose the last four commits are O-A-B-C, and whether they were created \n> by this rebase or existed before is irrelevant.\n>\n> If I want to rebase --nested -i O, then I --edit-todo and\n\nMaybe `--rework` as a possible alternate option name, if the concept of\nit being truly nested process does not work out?\n\n> prepend the following four lines:\n> reset O\n> pick A\n> pick B\n> pick C\n>\n> If a nested rebase command does just that, I think it would cover my\n> use case.  If it adds a comment saying \"nested rebase ends here\",\n> it's easy to cancel the nested rebase if there was a mistake.\n>\n> A slightly fancier thing a nestrd rebase could do is see if any of the \n> newly created picks are also used in merges that were already in the todo \n> list.  In that case, follow the pick by a label command and update the \n> later merge to refer to the label.\n\n"},{"id":"394418","messageId":"ef1a1475-45b3-8696-ed1e-b28f7b655ece@gmail.com","threadId":"53043","inReplyTo":"7fbe0ddc-74a3-b6b5-09b1-bff171382d0e@iee.email","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2020-03-31T13:36:59Z","receivedAt":"2020-03-31T13:37:07Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Philip, George and Johannes\n\nI really like the idea of being able to extend or rewind an existing \nrebase to reedit commits.\n\nOn 31/03/2020 11:57, Philip Oakley wrote:\n> Hi george,\n> \n> On 31/03/2020 01:00, George Spelvin wrote:\n>> Thinking about Philip Oakley's suggestion, it dawned on me that\n>> we can *already* do a nested rebase manually, and having a less\n>> manual alias for the procedure would be reasonable.\n>>\n>> Suppose the last four commits are O-A-B-C, and whether they were created\n>> by this rebase or existed before is irrelevant.\n>>\n>> If I want to rebase --nested -i O, then I --edit-todo and\n> \n> Maybe `--rework` as a possible alternate option name, if the concept of\n> it being truly nested process does not work out?\n\nor `--rewind` ?\n\n>> prepend the following four lines:\n>> reset O\n>> pick A\n>> pick B\n>> pick C\n>>\n>> If a nested rebase command does just that, I think it would cover my\n>> use case.  If it adds a comment saying \"nested rebase ends here\",\n>> it's easy to cancel the nested rebase if there was a mistake.\n>>\n>> A slightly fancier thing a nestrd rebase could do is see if any of the\n>> newly created picks are also used in merges that were already in the todo\n>> list.  In that case, follow the pick by a label command and update the\n>> later merge to refer to the label.\n\nIf we're going to support rewinding a rebase that creates merges then \nthis is a prerequisite otherwise it wont work properly. It will also \nneed to update any existing labels that refer to a commits that get \nrewritten when rewinding.\n\nWhen cancelling the nested rebase we need to take care to restore any \nlabels to their previous value if they have been updated by the nested \nrebase. We also need to restore the list or rewritten commits so that we \ndon't report that we've rewritten the commits from the nested rebase \nthat we're aborting. These two requirements unfortunately make it \ndifficult to implement the nested rebase just by updating the todo list. \nIt needs to save the current labels (and reference the commits somewhere \nso they don't get gc'd) and the rewritten-list. `git rebase --abort` (or \nwhatever we end up using to abort the nested part of the rebase) needs \nto restore the labels and rewritten-list. I think it should probably \nrestore the todo list as well - if the original part of the todo list \ngets edited during the nested rebase should we drop those changes to the \nlist or keep them when the nested rebase is aborted?\n\nBest Wishes\n\nPhillip\n"},{"id":"394504","messageId":"60cd00c2-7aba-3d74-11fa-d4443f6cd83e@iee.email","threadId":"53043","inReplyTo":"ef1a1475-45b3-8696-ed1e-b28f7b655ece@gmail.com","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2020-04-01T16:43:33Z","receivedAt":"2020-04-01T16:43:46Z","isPatch":false,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi Phillip,\n\nOn 31/03/2020 14:36, Phillip Wood wrote:\n> Hi Philip, George and Johannes\n>\n> I really like the idea of being able to extend or rewind an existing\n> rebase to reedit commits.\n>\n> On 31/03/2020 11:57, Philip Oakley wrote:\n>> Hi george,\n>>\n>> On 31/03/2020 01:00, George Spelvin wrote:\n>>> Thinking about Philip Oakley's suggestion, it dawned on me that\n>>> we can *already* do a nested rebase manually, and having a less\n>>> manual alias for the procedure would be reasonable.\n>>>\n>>> Suppose the last four commits are O-A-B-C, and whether they were\n>>> created\n>>> by this rebase or existed before is irrelevant.\n>>>\n>>> If I want to rebase --nested -i O, then I --edit-todo and\n>>\n>> Maybe `--rework` as a possible alternate option name, if the concept of\n>> it being truly nested process does not work out?\n>\n> or `--rewind` ?\n\nA possibility, though it feels a bit narrow in suggesting the capabilities\n>\n>>> prepend the following four lines:\n>>> reset O\n>>> pick A\n>>> pick B\n>>> pick C\n>>>\n>>> If a nested rebase command does just that, I think it would cover my\n>>> use case.  If it adds a comment saying \"nested rebase ends here\",\n>>> it's easy to cancel the nested rebase if there was a mistake.\n>>>\n>>> A slightly fancier thing a nestrd rebase could do is see if any of the\n>>> newly created picks are also used in merges that were already in the\n>>> todo\n>>> list.  In that case, follow the pick by a label command and update the\n>>> later merge to refer to the label.\n>\n> If we're going to support rewinding a rebase that creates merges then\n> this is a prerequisite otherwise it wont work properly. It will also\n> need to update any existing labels that refer to a commits that get\n> rewritten when rewinding.\n\nI would agree that the `label` instruction would need expanding to allow\narbitrary refs (e.g. specific oids and other branches) to be labelled\nrather than just a presumed 'HEAD' ref. I did notice the man page\ndoesn't actually define the format of the extra instructions (there was\nfun with awkward chars in label names on Windows).\n\nI'm of the opinion that we don't re-label/rename the previous labels -\nthey are what they are, but we do offer the ability to provide new\nlabels. Hence the extension to the label format to allow the labelling\nof arbitrary refs, not just HEAD, along with showing existing progress,\nso folks can _see_ the new oids etc.\n>\n> When cancelling the nested rebase we need to take care to restore any\n> labels to their previous value if they have been updated by the nested\n> rebase. We also need to restore the list or rewritten commits so that\n> we don't report that we've rewritten the commits from the nested\n> rebase that we're aborting. These two requirements unfortunately make\n> it difficult to implement the nested rebase just by updating the todo\n> list. \n\nI'm against the original conceptual idea of 'nesting' (or rewinding).\nWhat's done is done, it's in the object store, as is all the old\noriginal work, so we have a wider foundation to build from.  Clearly we\nare not in a clean work-state, with the half complete jobs, so it's more\nof a recovery activity than clean coding (from the user perspective).\n\n> It needs to save the current labels (and reference the commits\n> somewhere so they don't get gc'd) and the rewritten-list. `git rebase\n> --abort` (or whatever we end up using to abort the nested part of the\n> rebase) needs to restore the labels and rewritten-list. I think it\n> should probably restore the todo list as well - if the original part\n> of the todo list gets edited during the nested rebase should we drop\n> those changes to the list or keep them when the nested rebase is aborted?\n\nIf we haven't aborted, then we just have the actual sequence of work,\nwith some of the commits, ultimately, being left as unconnected stubs\n(once their temporary tips have gone upon completion of the rebase -\ncould they be explicitly dropped?).  On completion, those abandoned\ncommits could be explicitly marked as having been removed in the various\nbook-keeping lists and logs (if it was useful and helpful). I think this\nis a different conceptual view of the work of the rebase - resolve process.\n>\n> Best Wishes\n>\n> Phillip\n--\nPhilip\n"},{"id":"394763","messageId":"nycvar.QRO.7.76.6.2004041414370.46@tvgsbejvaqbjf.bet","threadId":"53043","inReplyTo":"20200331000018.GD9199@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-04-04T12:17:17Z","receivedAt":"2020-04-04T12:17:27Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi George,\n\nOn Tue, 31 Mar 2020, George Spelvin wrote:\n\n> Thinking about Philip Oakley's suggestion, it dawned on me that\n> we can *already* do a nested rebase manually, and having a less\n> manual alias for the procedure would be reasonable.\n>\n> Suppose the last four commits are O-A-B-C, and whether they were created\n> by this rebase or existed before is irrelevant.\n>\n> If I want to rebase --nested -i O, then I --edit-todo and\n> prepend the following four lines:\n> reset O\n> pick A\n> pick B\n> pick C\n>\n> If a nested rebase command does just that, I think it would cover my\n> use case.  If it adds a comment saying \"nested rebase ends here\",\n> it's easy to cancel the nested rebase if there was a mistake.\n\nFWIW this is precisely what I do in\nhttps://github.com/git-for-windows/build-extra/blob/70d940d1b/ever-green.sh#L184-L246\n\nI create a new worktree (without checking out anything), start a rebase\nwith a custom (fake) editor that simply grabs the todo list and aborts\nthat rebase. Then I remove that worktree and insert the grabbed todo list\ninto the current one.\n\nHowever, I find that it is not at all easy to cancel the nested rebase\nbecause the current `HEAD` is recorded _nowhere_.\n\nCiao,\nDscho\n\n> A slightly fancier thing a nestrd rebase could do is see if any of the\n> newly created picks are also used in merges that were already in the todo\n> list.  In that case, follow the pick by a label command and update the\n> later merge to refer to the label.\n>\n"},{"id":"394764","messageId":"nycvar.QRO.7.76.6.2004041417420.46@tvgsbejvaqbjf.bet","threadId":"53043","inReplyTo":"20200328163024.GA26885@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-04-04T12:39:26Z","receivedAt":"2020-04-04T12:39:35Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi George,\n\nOn Sat, 28 Mar 2020, George Spelvin wrote:\n\n> On Sat, Mar 28, 2020 at 03:25:06PM +0100, Johannes Schindelin wrote:\n> > There are _many_ ways to mess up a nested rebase, including (but not\n> > limited to) `--onto`, forgetting `-r`, editing the todo list too much in\n> > an editor without undo.\n> >\n> > If you are suggesting that a nested `git rebase -i` would not need a way\n> > to abort _just_ the nested rebase, then I fear we must stop the\n> > conversation right here. That's not going to fly.\n>\n> Yes, I'm seriously suggesting that.  My arguments are:\n>\n> * The benefit is limited, because you can do pretty much all the\n>   same things with just plain --edit-todo, and I don't see the\n>   point of handing the user a loaded gun and ensuring they can't\n>   shoot themselves in their *left* foot.\n\nNo, the benefit is in getting out of a fix without having to know\nimplementation details.\n\nWe do allow aborting rebases, so users will rightfully expect to be able\nto abort nested rebases, too.\n\n> * The cost in implementation complexity is considerable.  Even the\n>   *semantics* are awkward.  In particular, if you reorder patches\n>   between the outer and inner rebases, how do you define the end of\n>   the inner rebase?\n\nThe cost of Git's implementation complexity is also considerable. That on\nits own is not a reason not to do it.\n\nBesides, there are quite a few ways to achieve this on the cheap, so I\nwould even context that it is too complex.\n\nOne very trivial idea, for example, would be to rename `rebase-merge` to\n`rebase-nested-1` (and if that exists, find the next `rebase-nested-<n>`\nname and use that instead). Then run the nested rebase as per usual. Upon\nconclusion of the rebase (or if the user aborts it), rename back and\ncontinue.\n\nThat approach has the advantage that nested rebases can use different\noptions (such as a different merge strategy) than the enclosing rebase.\n\n> Now, I *did* agree that being able to abort just the nested rebase\n> *from the initial todo edit* is useful and achievable.  That can\n> be handled as a special case.  It's allowing \"git rebase --abort\"\n> from halfway throuigh the nested rebasethat introduces all kinds\n> of hair.\n\nThis is too narrow a view. If I run a rebase, in the middle decide to try\na nested rebase, and half-way through realize that the nested rebase was a\nbad idea, you want to _not_ give me a way to return to the enclosing\nrebase.\n\nThat is a bad idea.\n\n> >> The main problem with a full nested rebase is that you need to define when\n> >> the inner rebase completes and the outer rebase resumes.  I very much\n> >> want the ability to move commits around between the outer rebase and the\n> >> inner one, which makes that distinction ill-defined.\n> >\n> > That probably means that we have not thought through the problem, at least\n> > not enough. If we have nested levels, then we might need to record those\n> > nested levels, including the equivalent of `ORIG_HEAD`, `onto` and the\n> > todo list. And of course make them accessible to the user.\n>\n> I worry that's too much conceptual complexity being foisted on the user.\n>\n> > Mind you: I do not necessarily request a perfect design. I just don't want\n> > to slam the door shut when it comes to more sophisticated use cases. I\n> > _really_ would like to have a way to \"just redo the latest 5 commands\",\n> > for example, but I have no illusion about getting that any time soon.\n>\n> The big use cases I see are:\n> - Wanting to back up in the current rebase, \"quilt pop\" style.\n>   Many times I've found a hunk in patch #4 that should have been\n>   part of patch #2.\n> - Wanting to move the base back a bit further than originally\n>   planned.  (This is often an alternate form of the preceeding;\n>   I find a hunk that should have been in patch #-2.)\n> - Wanting to rearrange commits across the current commit.  I've\n>   gone and edited patch #4 and introduced a dependency on patch #7.\n>   I want to move patch #7 back so that my revised #4 can be tested.\n>\n> I think of the feature as an \"edit-todo\" that includes some already-\n> applied patches.\n>\n> >> The thing is, it's already quite possible to make a mess of a rebase\n> >> halfway through and need to abort after you've put a lot of work in.\n> >\n> > Tell me about it!\n>\n> Thus, my comment above about protecting the user's left foot.  If\n> they still need to be careful to not shoot off their right foot,\n> are we saving them any mental effort?\n>\n> My goal for the nested-rebase feature is that it can be useful for\n> *recovering* from such messes.  Back up a few steps to before the\n> trouble started, but *not* a full abort.\n\nThat might actually be better accomplished as a `--rewind` as suggested by\nPhillip. It does not necessarily need a full-blown nested rebase.\n\nBut as Philip hinted at, this might be quite complicated in the\n`--rebase-merges` case, as you cannot necessarily infer the correct\nlabels. Example:\n\n\tlabel onto\n\n\t# Branch: one\n\treset onto\n\tpick first\n\tlabel one\n\n\t# Branch: two\n\treset one\n\tpick second\n\tlabel two\n\nIf you try to redo both `first` and `second`, how on Earth should a nested\n(or rewinding) rebase figure out that it has to re-label `one`?\n\nDone right, this will be a super useful feature. I will use it all the\ntime. It has to be done right, though, and not limit me in annoying ways.\n\n> >> I think a more general-purpose recovery mechanism might be more\n> >> useful.\n> >>\n> >> For example, if the --edit-todo included a (commented-out) list of what\n> >> had already been done, then after realizing that you screwed up\n> >> conflict resolve b' and have now committed bad resolutions c' and d'\n> >> on top of it, you could easily rebase --nested and replace b', c' and d'\n> >> with the original b, c and d.\n> >>\n> >> Without aborting and throwing away a' as well, which was perhaps a lot of\n> >> work.\n> >\n> > We do have the `done` file, but that does not discern between commands\n> > in the todo list that have been there in the first place and commands that\n> > have been added by the user _during_ the rebase. And of course it does not\n> > reflect any commands that have been removed/changed by the user during the\n> > rebase.\n> >\n> > So yeah, something like a journal, maybe.\n>\n> I was thinking of the \"done\" file.\n\nThe `done` file will not record what commands were rescheduled, so you can\nend up with \"double entries\".\n\n> At a low level, we already have the reflog, and giving the user yet\n> another transaction log to remember is undesirable.\n\nThe reflog does not record `label` commands.\n\nIn other words, neither will give you what you need.\n\nIf you want to have a record what the todo list looked like, and what\n`HEAD` was, at the beginning of a nested rebase, you will have to actually\nrecord both.\n\n> If we just added the original commit ID to the automatically\n> generated reflog entry, si it also records the higher-level intention,\n> that might do it.  I.e. change\n>\n> bc56134cfe278 HEAD@{3}: rebase (pick): wilc1000: Use crc7 in lib/ rather than a private copy\n> \tto\n> bc56134cfe278 HEAD@{3}: rebase (pick 01cb7b5b7851): wilc1000: Use crc7 in lib/ rather than a private copy\n>\n> Oh!  What if we recorded, for the duration of the rebase, the todo\n> list state corresponding to reflog entries?  (Or, equivalently,\n> the reflog state at each step through the todo list.)  Then we\n> could back up the rebase with just a reflog entry pointer.\n>\n> I like this precisely because it doesn't give the user a new entity\n> to keep track of; it just makes an existing entity more useful.\n>\n> > Thank you for thinking about this feature, and for discussing it with me.\n> > I think it will be a really nice feature to have, and I want to avoid\n> > problems with a design that simply won't allow for certain use cases\n> > (remember how `git rebase --preserve-merges` does not allow for reordering\n> > commits, and how the design of that feature simply made this bug\n> > unfixable? I _dearly_ regret not thinking that through).\n>\n> Definitely, let's think it through.  But remember that \"perfection\n> is achieved, not when there is nothing more to add, but when there\n> is nothing left to take away.\"  KISS is a design *goal*, not just\n> a necessary compromise.\n\nRight. I am not even talking about adding features. I am talking about not\nchiseling away the features that I _need_.\n\nCiao,\nDscho\n"},{"id":"394780","messageId":"20200404174116.GB11944@SDF.ORG","threadId":"53043","inReplyTo":"nycvar.QRO.7.76.6.2004041417420.46@tvgsbejvaqbjf.bet","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-04-04T17:41:16Z","receivedAt":"2020-04-04T17:41:25Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"I'm just trying to make the point that guardrails on \"git rebase\n--nested\" which don't exist on the more powerful and dangerous \"git\nrebase --edit-todo\" are a case of installing a high-security lock on a\nscreen door.\n\nIf you can come up with something that works for both, then great. But \ngoing to significant trouble (especially in terms of design complexity and \nlegacy burden; I'm not worrying about SMOP) for a special-case solution \nthat only works for one is a waste of effort.\n\nBoth, or neither.  Just one is bad design.\n\nRegarding the semantics, consider the following case:\n\n* Initial branch history is O-A-B-C-D\n* I initially \"git rebase A\"\n* Then realize that I made a mistake and \"git rebase --nested A^\"\n* I reverse the order of the commits to D-C-B-A\n* The rebase continues, and I successfully pick D and C.\n   (remaining commands are \"pick B\" and \"pick A\"\n* Then I \"git rebase --abort\".\n\nWhat state should I expect to be returned to?\n\n(Without separately abortable nested rebases, the state after the nested\nrebase is exactly the same as if I'd used \"git rebase A^\" in the first\nplace, which doesn't seem like a terribly bad thing.)\n\n"},{"id":"394822","messageId":"CA+KXf2C0XytyNEAAdTOZAzw5YTQuv3PSjJ7RgyWqTj9MPp6BDQ@mail.gmail.com","threadId":"53043","inReplyTo":"20200404174116.GB11944@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Sebastien Bruckert","fromEmail":"sbruckert.dev@gmail.com","sentAt":"2020-04-06T10:40:07Z","receivedAt":"2020-04-06T09:46:42Z","isPatch":false,"sender":{"key":"sbruckert.dev@gmail.com","avatar":null},"body":"Hi all,\n\nWhat is your problem actually ? You want to edit a commit before where\nyou are in a rebase ?\n\nO --- A --- B --- C --- D\n* You are in a middle of a rebase at commit C.\n* You want to edit A without finishing all your actual rebase.\n\nIs that right ?\n\nThen, why making a whole new rebase for that operation ?\n\nIn this example, you are finally editing A with some sort of new\nnested operation. This operation should not do anything else than\nthis. Like something atomical, you edit the commit / add a commit /\nremove one, and that's all. End of the story. Back to the original\nrebase, and back to commit C. If that \"nested\" operation  made\nconflict with B, we can move the actual rebase to B to clean the mess\nyou made with the \"nested\" operation. But you are still in only one\nrebase. If you abort, everything gets cleaned up.\n\nI don't know if any of this is pertinent / understandable, but I hope\nit gave a fresh view on that. You guys are maybe a bit too focused on\nwhat to do in case of an abort of a nested rebase. However, we don't\nactually know if a nested rebase is the best solution for this job.\n\nMy two cents\n"},{"id":"394846","messageId":"20200406152450.GA9609@SDF.ORG","threadId":"53043","inReplyTo":"CA+KXf2C0XytyNEAAdTOZAzw5YTQuv3PSjJ7RgyWqTj9MPp6BDQ@mail.gmail.com","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-04-06T15:24:50Z","receivedAt":"2020-04-06T15:25:06Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"On Mon, Apr 06, 2020 at 06:40:07AM -0400, Sebastien Bruckert wrote:\n> What is your problem actually ? You want to edit a commit before where\n> you are in a rebase ?\n> \n> O --- A --- B --- C --- D\n> * You are in a middle of a rebase at commit C.\n> * You want to edit A without finishing all your actual rebase.\n> \n> Is that right ?\n> \n> Then, why making a whole new rebase for that operation ?\n\nActually, it's a *bit* more complicated.  I came across the need while \npreparing a large patch series for submission.  I was going through the \nseries, making sure the patches were in a logical order and didn't contain \njunk like an edit that should have been a fixup to an ealier patch.\n\n(Quite often, as I'm writing comments describing a new function,\nI tweak the comments later.)\n\nIf I only want to fix up an old patch, I can make a fixup patch and merge \nit in in a later pass.  If I want to edit the commit message again, I \ncan't make the change and have git remember it for me, but I can at least \nmake a a (possibly empty) squash commit with a note about the change.\n\nThe hairy part comes when I'm doing a lot of reordering, and I realize \nthat oh, damn it, commit C really should come before A in the patch \nseries.  (Or maybe C should be split and *part* of it should\ncome before A.)\n\nI don't want to abort the rebase and restart, because I've already put a \nlot of work into rebasing A and B.  (Which are each multiple patches, \nsimplified to one for this explanation.)  I've rearranged patches, \nchanged function names and prototypes, and resolved the \nresultant conflicts.\n\nJust finishing up the rebase and restarting is a PITA, because I'll have \nmore conflicts in D to resolve (again, D is not just a single commit), \nwhich will take some thinking, and by the time I\"ve done all that I've \nforgotten what I was doing with C.\n\nWhat I'd like to do is just back up a few steps in the current\nrebase, put C there, and then resume rebasing D.\n\nInstead, I end up writing myself a note and, at the conclusion of\nthe current rebase, starting a second one to apply the additional\nchanges.\n\n> In this example, you are finally editing A with some sort of new\n> nested operation. This operation should not do anything else than\n> this. Like something atomical, you edit the commit / add a commit /\n> remove one, and that's all. End of the story. Back to the original\n> rebase, and back to commit C. If that \"nested\" operation  made\n> conflict with B, we can move the actual rebase to B to clean the mess\n> you made with the \"nested\" operation. But you are still in only one\n> rebase. If you abort, everything gets cleaned up.\n> \n> I don't know if any of this is pertinent / understandable, but I hope\n> it gave a fresh view on that. You guys are maybe a bit too focused on\n> what to do in case of an abort of a nested rebase. However, we don't\n> actually know if a nested rebase is the best solution for this job.\n\nThis sounds a lot like my original (and still preferred) design: it's not \nreally a nested transaction in the database sense (which can be aborted \nindependent of the outer commit), it's just one rebase that I rewind.\n\nI think a full nested transaction is too much conceptual complexity. And \nmy primary use case is rearranging commits, so I want to move commits \nbetween the \"outer\" and \"inner\" rebase, which makes defining the boundary \nof the inner rebase problematic.\n\nBut Johannes Schindelin seems quite forcefully opposed to the lack of a \nnested abort, so we're hashing it out.\n\nI'm very interested in your opinion, but please note that we already have \nfixup commits for amending single commits in place.\n\nThe problem that currently has no good solution arises when I realize \nhalfway through a cleanup pass that things would be a lot simpler if I \nmoved A to after C. \"Hey, rather than adding A and then updating it to \ntake C into account, how about I just do commit C first, and then add the \nfinal code of A in one step?\"  That is, I want to change from O-A-B-C-D to \nO-B-C-A-D, but I didn't think of it until the rebase had reached O-A-B-C-.\n\nI think of it as \"quilt pop\" operation, taking patches off the\napplied list and putting them back on the todo.\n"},{"id":"394909","messageId":"CA+KXf2A7L1fRC3+rmDaME186CYf4yS+-dBgy_FkEFVh887N7MA@mail.gmail.com","threadId":"53043","inReplyTo":"20200406152450.GA9609@SDF.ORG","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Sebastien Bruckert","fromEmail":"sbruckert.dev@gmail.com","sentAt":"2020-04-07T09:16:50Z","receivedAt":"2020-04-07T08:23:22Z","isPatch":false,"sender":{"key":"sbruckert.dev@gmail.com","avatar":null},"body":"Thank you for the more detailed explanation.\n\n> I'm very interested in your opinion, but please note that we already have\n> fixup commits for amending single commits in place.\n\nYes sorry, I still don't know everything about git and the way it\nworks. But I'm working on it!\n\n> The problem that currently has no good solution arises when I realize\n> halfway through a cleanup pass that things would be a lot simpler if I\n> moved A to after C. \"Hey, rather than adding A and then updating it to\n> take C into account, how about I just do commit C first, and then add the\n> final code of A in one step?\"  That is, I want to change from O-A-B-C-D to\n> O-B-C-A-D, but I didn't think of it until the rebase had reached O-A-B-C-.\n>\n> I think of it as \"quilt pop\" operation, taking patches off the\n> applied list and putting them back on the todo.\n\nHmmm so you need some way to move C before your actual commit. To make\nit like a pseudo command, some kind of \"git rebase --reattach C\n--after A\"? This seems closer to your original idea.\n\nOr why not modify \"--edit-todo\" to get commits from before your actual\npoint? It could works like this:\n\nBefore:\n```\n#pick b2a96fe O\n#pick acb7459 A\n#pick 0dac4a4 B\nedit 1f54e51 C\nedit cda2a7e D\n```\n\nAfter:\n```\n#pick b2a96fe O\nedit 1f54e51 C\npick acb7459 A\npick 0dac4a4 B\nedit cda2a7e D\n```\n\nSo that you are still at C, but keeping the changes you made before on\nA and B, and going through them only if you have conflicts.\n\nIf I understand your problem correctly (I hope), the more I think\nabout it, the more this modified \"--edit-todo\" makes sense too me.\nMoreover, no problem for aborting, no big conceptual change, no change\nin the way rebase works. Only --edit-todo is enhanced.\n\nIt coincides with what you were saying at the beginning:\n\n> On Fri, Mar 20, 2020 at 03:51:20PM -0700, Junio C Hamano wrote:\n> > I thought that \"git rebase -i\" allows the todo file (i.e. list of\n> > steps still to be performed) to be edited before continuing; would>\n> your use case be supported by using that?\n>\n> Mostly, if I do it very carefully, which is why I thought it would\n> be easy to add.\n>\n> I think I could manually add the commits to the start of the todo file,\n> reset --hard to the old state, and rebase --continue.\n>\n> But cutting and pasting commit IDs from git log into the todo file,\n> and putting fixup commits in the right place is annoyingly fiddly.\n> That's exactly the sort of thing computers are good at.\n"},{"id":"394970","messageId":"7babcfdb-5b01-ca6d-2709-4fae582c50e1@gmail.com","threadId":"53043","inReplyTo":"60cd00c2-7aba-3d74-11fa-d4443f6cd83e@iee.email","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2020-04-07T15:54:35Z","receivedAt":"2020-04-07T15:54:41Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Philip\n\nOn 01/04/2020 17:43, Philip Oakley wrote:\n> Hi Phillip,\n> \n> On 31/03/2020 14:36, Phillip Wood wrote:\n>> Hi Philip, George and Johannes\n>>\n>> I really like the idea of being able to extend or rewind an existing\n>> rebase to reedit commits.\n>>\n>> On 31/03/2020 11:57, Philip Oakley wrote:\n>>> Hi george,\n>>>\n>>> On 31/03/2020 01:00, George Spelvin wrote:\n>>>> Thinking about Philip Oakley's suggestion, it dawned on me that\n>>>> we can *already* do a nested rebase manually, and having a less\n>>>> manual alias for the procedure would be reasonable.\n>>>>\n>>>> Suppose the last four commits are O-A-B-C, and whether they were\n>>>> created\n>>>> by this rebase or existed before is irrelevant.\n>>>>\n>>>> If I want to rebase --nested -i O, then I --edit-todo and\n>>>\n>>> Maybe `--rework` as a possible alternate option name, if the concept of\n>>> it being truly nested process does not work out?\n>>\n>> or `--rewind` ?\n> \n> A possibility, though it feels a bit narrow in suggesting the capabilities\n>>\n>>>> prepend the following four lines:\n>>>> reset O\n>>>> pick A\n>>>> pick B\n>>>> pick C\n>>>>\n>>>> If a nested rebase command does just that, I think it would cover my\n>>>> use case.  If it adds a comment saying \"nested rebase ends here\",\n>>>> it's easy to cancel the nested rebase if there was a mistake.\n>>>>\n>>>> A slightly fancier thing a nestrd rebase could do is see if any of the\n>>>> newly created picks are also used in merges that were already in the\n>>>> todo\n>>>> list.  In that case, follow the pick by a label command and update the\n>>>> later merge to refer to the label.\n>>\n>> If we're going to support rewinding a rebase that creates merges then\n>> this is a prerequisite otherwise it wont work properly. It will also\n>> need to update any existing labels that refer to a commits that get\n>> rewritten when rewinding.\n> \n> I would agree that the `label` instruction would need expanding to allow\n> arbitrary refs (e.g. specific oids and other branches) to be labelled\n> rather than just a presumed 'HEAD' ref. I did notice the man page\n> doesn't actually define the format of the extra instructions (there was\n> fun with awkward chars in label names on Windows).\n> \n> I'm of the opinion that we don't re-label/rename the previous labels -\n> they are what they are, but we do offer the ability to provide new\n> labels. Hence the extension to the label format to allow the labelling\n> of arbitrary refs, not just HEAD, along with showing existing progress,\n> so folks can _see_ the new oids etc.\n\nI'm not sure I understand how this would work. Say in the example below \nI decide I want to rework abc while editing fgh and run 'git rebase \n--rework abc^'. If we don't update the labels automatically how do I \nensure that the merge will pick up the reworked abc as it's parent.\n\n#pick abc\n#label topic\n#reset cde\nedit fgh\nmerge topic\n\n>>\n>> When cancelling the nested rebase we need to take care to restore any\n>> labels to their previous value if they have been updated by the nested\n>> rebase. We also need to restore the list or rewritten commits so that\n>> we don't report that we've rewritten the commits from the nested\n>> rebase that we're aborting. These two requirements unfortunately make\n>> it difficult to implement the nested rebase just by updating the todo\n>> list.\n> \n> I'm against the original conceptual idea of 'nesting' (or rewinding).\n> What's done is done, it's in the object store, as is all the old\n> original work, so we have a wider foundation to build from.  Clearly we\n> are not in a clean work-state, with the half complete jobs, so it's more\n> of a recovery activity than clean coding (from the user perspective).\n\nI don't like the idea of nesting either but I think it would be useful \nto be able to get back to a known state when the changes I make with \n'rebase --rework' turn out to be a bad idea so I don't throw away all \nthe work that I did before running 'rebase --rework'. I've been using a \nscript that rewinds and I've got myself into situations where a \nspeculative change made while rewinding turned out to be a bad idea and \nI want to get back to the state before the last rewind. When working on \na patch series I can rewind multiple times before completing the rebase \nas I jump back and forth modifying and rewording each patch.\n\nBest Wishes\n\nPhillip\n\n>> It needs to save the current labels (and reference the commits\n>> somewhere so they don't get gc'd) and the rewritten-list. `git rebase\n>> --abort` (or whatever we end up using to abort the nested part of the\n>> rebase) needs to restore the labels and rewritten-list. I think it\n>> should probably restore the todo list as well - if the original part\n>> of the todo list gets edited during the nested rebase should we drop\n>> those changes to the list or keep them when the nested rebase is aborted?\n> \n> If we haven't aborted, then we just have the actual sequence of work,\n> with some of the commits, ultimately, being left as unconnected stubs\n> (once their temporary tips have gone upon completion of the rebase -\n> could they be explicitly dropped?).  On completion, those abandoned\n> commits could be explicitly marked as having been removed in the various\n> book-keeping lists and logs (if it was useful and helpful). I think this\n> is a different conceptual view of the work of the rebase - resolve process.\n>>\n>> Best Wishes\n>>\n>> Phillip\n> --\n> Philip\n> \n"},{"id":"394996","messageId":"20200407190339.GA20902@SDF.ORG","threadId":"53043","inReplyTo":"CA+KXf2A7L1fRC3+rmDaME186CYf4yS+-dBgy_FkEFVh887N7MA@mail.gmail.com","subject":"Re: Feature request: rebase -i inside of rebase -i","fromName":"George Spelvin","fromEmail":"lkml@sdf.org","sentAt":"2020-04-07T19:03:39Z","receivedAt":"2020-04-07T19:03:53Z","isPatch":false,"sender":{"key":"lkml@sdf.org","avatar":null},"body":"On Tue, Apr 07, 2020 at 05:16:50AM -0400, Sebastien Bruckert wrote:\n> Hmmm so you need some way to move C before your actual commit. To make\n> it like a pseudo command, some kind of \"git rebase --reattach C\n> --after A\"? This seems closer to your original idea.\n\nThat seems too special-purpose and hard to remember.  The standard\nrebase -i operation (generate a todo list and drop me into an editor)\nis perfectly adequate and more familiar.  This is a very manual operation, \nafter all.  (\"-i\" for \"interactive\" means \"manual\".)\n\n> Or why not modify \"--edit-todo\" to get commits from before your actual\n> point? It could works like this:\n> \n> Before:\n> ```\n> #pick b2a96fe O\n> #pick acb7459 A\n> #pick 0dac4a4 B\n> edit 1f54e51 C\n> edit cda2a7e D\n> ```\n> \n> After:\n> ```\n> #pick b2a96fe O\n> edit 1f54e51 C\n> pick acb7459 A\n> pick 0dac4a4 B\n> edit cda2a7e D\n> ```\n> \n> So that you are still at C, but keeping the changes you made before on\n> A and B, and going through them only if you have conflicts.\n\nBecause the only reason this is interesting assumes that A and B have \nchanged!  If I didn't intend to modify A somehow, I wouldn't have included \nit in the rebase range.  They're now edited patches A' and B'.  So the\nstate I want to get to is:\n\n#pick b2a96fe O\n#pick acb7459 A\n#pick 0dac4a4 B\nreset b2a96fe O\nedit 1f54e51 C\npick 7f0bcab A'\npick fcd3c62 B'\nedit cda2a7e D\n\nwhere it will pick the versions of A and B that include the edits I've\nalready made.\n\nNow, having the original commits mentioned in comments is useful, in case \nI made a mess of the edit and want to revert it.  E.g. I can certainly see \nrealizing, three commits later in the rebase, that I recolved a conflict \nwrong and should re-do it.  Although this can probably be handled with a \nfixup.\n"}]}