]> git.ipfire.org Git - thirdparty/git.git/commitdiff
sequencer: don't re-read todo for revert and cherry-pick
authorSZEDER Gábor <szeder.dev@gmail.com>
Sat, 23 Nov 2019 17:20:46 +0000 (18:20 +0100)
committerJunio C Hamano <gitster@pobox.com>
Sun, 24 Nov 2019 04:50:40 +0000 (13:50 +0900)
When 'git revert' or 'git cherry-pick --edit' is invoked with multiple
commits, then after editing the first commit message is finished both
these commands should continue with processing the second commit and
launch another editor for its commit message, assuming there are
no conflicts, of course.

Alas, this inadvertently changed with commit a47ba3c777 (rebase -i:
check for updated todo after squash and reword, 2019-08-19): after
editing the first commit message is finished, both 'git revert' and
'git cherry-pick --edit' exit with error, claiming that "nothing to
commit, working tree clean".

The reason for the changed behaviour is twofold:

  - Prior to a47ba3c777 the up-to-dateness of the todo list file was
    only checked after 'exec' instructions, and that commit moved
    those checks to the common code path.  The intention was that this
    check should be performed after instructions spawning an editor
    ('squash' and 'reword') as well, so the ongoing 'rebase -i'
    notices when the user runs a 'git rebase --edit-todo' while
    squashing/rewording a commit message.

    However, as it happened that check is now performed even after
    'revert' and 'pick' instructions when they involved editing the
    commit message.  And 'revert' by default while 'pick' optionally
    (with 'git cherry-pick --edit') involves editing the commit
    message.

  - When invoking 'git revert' or 'git cherry-pick --edit' with
    multiple commits they don't read a todo list file but assemble the
    todo list in memory, thus the associated stat data used to check
    whether the file has been updated is all zeroed out initially.

    Then the sequencer writes all instructions (including the very
    first) to the todo file, executes the first 'revert/pick'
    instruction, and after the user finished editing the commit
    message the changes of a47ba3c777 kick in, and it checks whether
    the todo file has been modified.  The initial all-zero stat data
    obviously differs from the todo file's current stat data, so the
    sequencer concludes that the file has been modified.  Technically
    it is not wrong, of course, because the file just has been written
    indeed by the sequencer itself, though the file's contents still
    match what the sequencer was invoked with in the beginning.
    Consequently, after re-reading the todo file the sequencer
    executes the same first instruction _again_, thus ending up in
    that "nothing to commit" situation.

The todo list was never meant to be edited during multi-commit 'git
revert' or 'cherry-pick' operations, so perform that "has the todo
file been modified" check only when the sequencer was invoked as part
of an interactive rebase.

Reported-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
sequencer.c
t/t3429-rebase-edit-todo.sh

index 2adcf5a639c3a7d0154f07cf07f420f5d4f54007..3b05d0277d0bd45b23a1d309e08874b5f0ba3d8a 100644 (file)
@@ -3791,7 +3791,7 @@ static int pick_commits(struct repository *r,
                                                        item->commit,
                                                        arg, item->arg_len,
                                                        opts, res, 0);
-               } else if (check_todo && !res) {
+               } else if (is_rebase_i(opts) && check_todo && !res) {
                        struct stat st;
 
                        if (stat(get_todo_path(opts), &st)) {
index 8739cb60a77a61f6a6a2e08ebb4ae64c92bafb67..1679f2563d3b62f7f28de8c007303c2bdb0b9e5e 100755 (executable)
@@ -52,4 +52,34 @@ test_expect_success 'todo is re-read after reword and squash' '
        test_cmp expected actual
 '
 
+test_expect_success 're-reading todo doesnt interfere with revert --edit' '
+       git reset --hard third &&
+
+       git revert --edit third second &&
+
+       cat >expect <<-\EOF &&
+       Revert "second"
+       Revert "third"
+       third
+       second
+       first
+       EOF
+       git log --format="%s" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 're-reading todo doesnt interfere with cherry-pick --edit' '
+       git reset --hard first &&
+
+       git cherry-pick --edit second third &&
+
+       cat >expect <<-\EOF &&
+       third
+       second
+       first
+       EOF
+       git log --format="%s" >actual &&
+       test_cmp expect actual
+'
+
 test_done