From: Alex Henrie <alexhenrie24@gmail.com>
To: phillip.wood@dunelm.org.uk
Cc: git@vger.kernel.org, alban.gruin@gmail.com, gitster@pobox.com
Subject: Re: [PATCH] sequencer: finish parsing the todo list despite an invalid first line
Date: Thu, 20 Jul 2023 16:37:00 -0600 [thread overview]
Message-ID: <CAMMLpeSN_M1HW1D3HyuY+S+GwUrQ_4dP9qoSQ72hbQv3pwK5kg@mail.gmail.com> (raw)
In-Reply-To: <395274b4-37a9-8c95-203f-94178c99772a@gmail.com>
On Thu, Jul 20, 2023 at 3:42 AM Phillip Wood <phillip.wood123@gmail.com> wrote:
> On 19/07/2023 15:43, Alex Henrie wrote:
> > ddb81e5072 (rebase-interactive: use todo_list_write_to_file() in
> > edit_todo_list(), 2019-03-05) made edit_todo_list more efficient by
> > replacing transform_todo_file with todo_list_parse_insn_buffer.
> > Unfortunately, that innocuous change caused a regression because
> > todo_list_parse_insn_buffer would stop parsing after encountering an
> > invalid 'fixup' line. If the user accidentally made the first line a
> > 'fixup' and tried to recover from their mistake with `git rebase
> > --edit-todo`, all of the commands after the first would be lost.
>
> I found this description a little confusing as transform_todo_file()
> also called todo_list_parse_insn_buffer(). transform_todo_file() does
> not exist anymore but it looked like
>
> static int transform_todo_file(unsigned flags)
> {
> const char *todo_file = rebase_path_todo();
> struct todo_list todo_list = TODO_LIST_INIT;
> int res;
>
> if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
> return error_errno(_("could not read '%s'."), todo_file);
>
> if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,
> &todo_list)) {
> todo_list_release(&todo_list);
> return error(_("unusable todo list: '%s'"), todo_file);
> }
>
> res = todo_list_write_to_file(the_repository, &todo_list,
> todo_file,
> NULL, NULL, -1, flags);
> todo_list_release(&todo_list);
>
> if (res)
> return error_errno(_("could not write '%s'."), todo_file);
> return 0;
> }
>
> If it could not parse the todo list it did not try and write it to disc.
> After ddb81e5072 this changed as edit_todo_list() tries to shorten the
> OIDs in the todo list before it is edited even if it cannot be parsed.
> The fix below works around that by making sure we always try and parse
> the whole todo list even if the the first line is a fixup command. That
> is a worthwhile improvement because it means we notify the user of all
> the errors we find rather than just the first one and is in keeping with
> the way we handle other invalid lines. It does not however fix the root
> cause of this regression which is the change in behavior in
> edit_todo_list().
>
> After the user edits the todo file we do not try to transform the OIDs
> if it cannot be parsed or has missing commits. Therefore it still
> contains the shortened OIDs and editing hints and there is no need for
> edit_todo_list() to call write_todo_list() when "incorrect" is true.
When the user first runs `git rebase`, the commit template contains
the following message:
# However, if you remove everything, the rebase will be aborted.
When running `git rebase --edit-todo`, that message is replaced with:
# You are editing the todo file of an ongoing interactive rebase.
# To continue rebase after editing, run:
# git rebase --continue
The second message is indeed more accurate after the rebase has
started: Deleting all of the lines in `git rebase --edit-todo` drops
all of the commits; it does not abort the rebase.
It would be nice to preserve as much of the user's original input as
possible, but that's not a project that I'm going to tackle. As far as
a minimal fix for the regression, we can either leave the todo file
untouched and display inaccurate advice during `git rebase
--edit-todo`, or we can lose any long commit IDs that the user entered
and display equivalent short hex IDs instead. I would prefer the
latter.
> > +test_expect_success 'the first command cannot be a fixup' '
> > + # When using `git rebase --edit-todo` to recover from this error, ensure
> > + # that none of the original todo list is lost
> > + rebase_setup_and_clean fixup-first &&
> > + (
> > + set_fake_editor &&
> > + test_must_fail env FAKE_LINES="fixup 1 2 3 4 5" \
> > + git rebase -i --root 2>actual &&
>
> Thanks for taking the time to add a test. It is not worth a re-roll on
> its own, but there is no need to use "--root" here. It is confusing as
> it is not clear if we're refusing "fixup" as the first command because
> we're rewriting the root commit or if we always refuse to have "fixup"
> as the first command.
Good point. I used --root because I copied and pasted from the
preceding test, but HEAD~4 would make the intent of the test more
clear. That change and the grep change that Junio suggested are
probably worth a v2.
> > + test_i18ngrep "cannot .fixup. without a previous commit" \
> > + actual &&
> > + test_i18ngrep "You can fix this with .git rebase --edit-todo.." \
> > + actual &&
> > + grep -v "^#" .git/rebase-merge/git-rebase-todo >orig &&
> > + test_must_fail git rebase --edit-todo &&
> > + grep -v "^#" .git/rebase-merge/git-rebase-todo >actual &&
> > + test_cmp orig actual
>
> We check that the uncommitted lines after running "git rebase
> --edit-todo" match the uncommitted lines after the initial edit. That's
> fine to detect if the second edit truncates the file but it will still
> pass if the initial edit starts truncating the todo list as well. As we
> expect that git should not change an incorrect todo list we do not need
> to filter out the lines beginning with "#".
>
> To ensure we detect a regression where the first edit truncates the todo
> list we could do something like
>
> test_when_finished "git rebase --abort" &&
> cat >todo <<-EOF &&
> fixup $(git log -1 --format="%h %s" B)
> pick $(git log -1 --format="%h %s" C)
> EOF
>
> (
> set_replace_editor todo &&
> test_must_fail git rebase -i A 2>actual
> ) &&
> test_i18ngrep "cannot .fixup. without a previous commit" actual &&
> test_i18ngrep "You can fix this with .git rebase --edit-todo.." actual &&
> # check initial edit has not truncated todo list
> grep -v "^#" .git/rebase-merge/git-rebase-todo >actual &&
> test_cmp todo actual &&
> cat .git/rebase-merge/git-rebase-todo >expect &&
> test_must_fail git rebase --edit-todo &&
> # check the list is unchanged by --edit-todo
> test_cmp expect .git/rebase-merge/git-rebase-todo
To me it seems pretty far-fetched that a future bug would cause the
_initial_ commit template to be missing anything. But if you're
concerned about it, would you like to send a follow-up patch to revise
the test as you see fit?
> We could perhaps check the error message from "git rebase --edit-todo"
> as well.
That sounds like another good change for v2.
Thanks for the feedback,
-Alex
next prev parent reply other threads:[~2023-07-20 22:37 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-19 14:43 [PATCH] sequencer: finish parsing the todo list despite an invalid first line Alex Henrie
2023-07-19 21:32 ` Junio C Hamano
2023-07-20 9:42 ` Phillip Wood
2023-07-20 22:37 ` Alex Henrie [this message]
2023-07-21 9:31 ` Phillip Wood
2023-07-21 13:08 ` Phillip Wood
2023-07-21 15:21 ` Junio C Hamano
2023-07-21 5:38 ` [PATCH v2 0/1] " Alex Henrie
2023-07-21 5:38 ` [PATCH v2 1/1] " Alex Henrie
2023-07-21 5:58 ` [PATCH v3 0/1] " Alex Henrie
2023-07-21 5:58 ` [PATCH v3 1/1] " Alex Henrie
2023-07-21 6:07 ` [PATCH v4 0/1] " Alex Henrie
2023-07-21 6:07 ` [PATCH v4 1/1] " Alex Henrie
2023-07-21 13:13 ` [PATCH v4 0/1] " Phillip Wood
2023-07-22 21:28 ` [PATCH v5 " Alex Henrie
2023-07-22 21:28 ` [PATCH v5 1/1] " Alex Henrie
2023-07-24 10:02 ` Phillip Wood
2023-07-24 15:26 ` Alex Henrie
2023-07-24 16:00 ` Phillip Wood
2023-07-24 16:40 ` Junio C Hamano
2023-07-24 17:39 ` Alex Henrie
2023-07-24 18:30 ` Junio C Hamano
2023-07-24 20:08 ` Alex Henrie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAMMLpeSN_M1HW1D3HyuY+S+GwUrQ_4dP9qoSQ72hbQv3pwK5kg@mail.gmail.com \
--to=alexhenrie24@gmail.com \
--cc=alban.gruin@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=phillip.wood@dunelm.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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 NNTP newsgroup(s).