To prevent mistakes when editing a branch, rebase features a knob, rebase.missingCommitsCheck, to warn the user if a commit was dropped. Unfortunately, this check is only effective for the initial edit, which means that if you edit the todo list at a later point of the rebase and dropped a commit, no warnings or errors would be issued. This adds the ability to check if commits were dropped when editing the todo list with `--edit-todo'. The first patch adds new tests demonstrating that the todo list is not checked with `--edit-todo'. The second patch implements the check. This series is pretty much a revamp of the first version. Some patches from the original series were rerolled separately and live now in ag/sequencer-todo-updates. This version is pretty much brand new, as you can see in the range diff below. Changes since v1 are about what the new todo list is compared to, and when. The original series compared the todo list against the original edit, so if a commit was added then deleted, it would go unnoticed. Now, it is compared against the previous version to avoid that. This is highlighted in the new tests. The original series checked the todo list after `--edit-todo', but also before continuing a rebase or after having executed a command. Now, it only checks it after `--edit-todo', as suggested by Phillip Wood. This is based on master (da72936f54, "Git 2.24"). The tip of this series is tagged as "edit-todo-drop-rfc-v2" at https://github.com/agrn/git. Alban Gruin (2): t3404: demonstrate that --edit-todo does not check for dropped commits rebase-interactive: warn if commit is dropped with --edit-todo rebase-interactive.c | 7 ++-- sequencer.c | 5 +-- t/t3404-rebase-interactive.sh | 75 +++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-) Diff-intervalle contre v1 : 1: b35f920318 ! 1: 6974b6c8f2 t3404: demonstrate that --edit-todo does not check for dropped commits @@ Commit message When set to "warn" or "error", `rebase.missingCommitCheck' would make rebase -i warn if the user removed commits from the todo list to prevent - mistakes. Unfortunately, rebase --edit-todo and rebase --continue don't - take it into account. + mistakes. Unfortunately, rebase --edit-todo don't take it into account. This adds three tests to t3404 to demonstrate this. The first one is not broken, as when `rebase.missingCommitsCheck' is not set, nothing in particular must be done towards dropped commits. The two others are broken, demonstrating the problem. + The tests for `rebase.missingCommitsCheck = warn' and + `rebase.missingCommitsCheck = error' have a similar structure. First, + we start a rebase with an incorrect command on the first line. Then, we + edit the todo list, removing the first and the last lines. This + demonstrates that `--edit-todo' notices dropped commits, but not when + the command is incorrect. Then, we restore the original todo list, and + edit it to remove the last line. This demonstrates that if we add a + commit after the initial edit, then remove it, `--edit-todo' will notice + that it has been dropped. Then, the actual rebase takes place. + Signed-off-by: Alban Gruin <alban.gruin@xxxxxxxxx> ## t/t3404-rebase-interactive.sh ## @@ t/t3404-rebase-interactive.sh: test_expect_success 'rebase -i respects rebase.mi + test_config rebase.missingCommitsCheck ignore && + rebase_setup_and_clean missing-commit && + set_fake_editor && -+ test_must_fail env FAKE_LINES="1 2 bad 3 4" \ -+ git rebase -i --root >/dev/null 2>stderr && -+ FAKE_LINES="1 2 4" git rebase --edit-todo && ++ FAKE_LINES="break 1 2 3 4 5" git rebase -i --root && ++ FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual && + git rebase --continue 2>actual && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_i18ngrep \ @@ t/t3404-rebase-interactive.sh: test_expect_success 'rebase -i respects rebase.mi + actual +' + -+cat >expect <<EOF -+error: invalid line 5: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 master) -+Warning: some commits may have been dropped accidentally. -+Dropped commits (newer to older): -+ - $(git rev-list --pretty=oneline --abbrev-commit -1 master) -+To avoid this message, use "drop" to explicitly remove a commit. -+ -+Use 'git config rebase.missingCommitsCheck' to change the level of warnings. -+The possible behaviours are: ignore, warn, error. -+ -+EOF -+ -+tail -n 8 <expect >expect.2 -+ +test_expect_failure 'rebase --edit-todo respects rebase.missingCommitsCheck = warn' ' ++ cat >expect <<-EOF && ++ error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 master~4) ++ Warning: some commits may have been dropped accidentally. ++ Dropped commits (newer to older): ++ - $(git rev-list --pretty=oneline --abbrev-commit -1 master) ++ To avoid this message, use "drop" to explicitly remove a commit. ++ EOF ++ tail -n4 expect >expect.2 && + test_config rebase.missingCommitsCheck warn && + rebase_setup_and_clean missing-commit && + set_fake_editor && -+ test_must_fail env FAKE_LINES="1 2 3 4 bad 5" \ -+ git rebase -i --root >/dev/null 2>stderr && -+ FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual && ++ test_must_fail env FAKE_LINES="bad 1 2 3 4 5" \ ++ git rebase -i --root && ++ cp .git/rebase-merge/git-rebase-todo.backup orig && ++ FAKE_LINES="2 3 4" git rebase --edit-todo 2>actual.2 && ++ head -n5 actual.2 >actual && + test_i18ncmp expect actual && -+ git rebase --continue 2>actual.2 && -+ head -n 8 <actual.2 >actual && ++ cp orig .git/rebase-merge/git-rebase-todo && ++ FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual.2 && ++ head -n4 actual.2 >actual && + test_i18ncmp expect.2 actual && ++ git rebase --continue 2>actual && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_i18ngrep \ + "Successfully rebased and updated refs/heads/missing-commit" \ -+ actual.2 ++ actual +' + -+cat >expect <<EOF -+error: invalid line 3: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 master~2) -+Warning: some commits may have been dropped accidentally. -+Dropped commits (newer to older): -+ - $(git rev-list --pretty=oneline --abbrev-commit -1 master) -+ - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2) -+To avoid this message, use "drop" to explicitly remove a commit. -+ -+Use 'git config rebase.missingCommitsCheck' to change the level of warnings. -+The possible behaviours are: ignore, warn, error. -+ -+EOF -+ -+tail -n 9 <expect >expect.2 -+ +test_expect_failure 'rebase --edit-todo respects rebase.missingCommitsCheck = error' ' ++ cat >expect <<-EOF && ++ error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 master~4) ++ Warning: some commits may have been dropped accidentally. ++ Dropped commits (newer to older): ++ - $(git rev-list --pretty=oneline --abbrev-commit -1 master) ++ To avoid this message, use "drop" to explicitly remove a commit. ++ EOF ++ tail -n4 expect >expect.2 && + test_config rebase.missingCommitsCheck error && + rebase_setup_and_clean missing-commit && + set_fake_editor && -+ test_must_fail env FAKE_LINES="1 2 bad 3 4" \ -+ git rebase -i --root >/dev/null 2>stderr && -+ test_must_fail env FAKE_LINES="1 2 4" \ -+ git rebase --edit-todo 2>actual && ++ test_must_fail env FAKE_LINES="bad 1 2 3 4 5" \ ++ git rebase -i --root && ++ cp .git/rebase-merge/git-rebase-todo.backup orig && ++ test_must_fail env FAKE_LINES="2 3 4" \ ++ git rebase --edit-todo 2>actual.2 && ++ head -n5 actual.2 >actual && + test_i18ncmp expect actual && -+ test_must_fail git rebase --continue 2>actual && ++ cp orig .git/rebase-merge/git-rebase-todo && ++ test_must_fail env FAKE_LINES="1 2 3 4" \ ++ git rebase --edit-todo 2>actual.2 && ++ head -n4 actual.2 >actual && + test_i18ncmp expect.2 actual && -+ cp .git/rebase-merge/git-rebase-todo.backup \ -+ .git/rebase-merge/git-rebase-todo && -+ FAKE_LINES="1 2 drop 3 4 drop 5" \ -+ git rebase --edit-todo && ++ cp orig .git/rebase-merge/git-rebase-todo && ++ FAKE_LINES="1 2 3 4 drop 5" git rebase --edit-todo && + git rebase --continue 2>actual && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_i18ngrep \ 2: 7410a1bc4b < -: ---------- t3429: demonstrate that rebase exec does not check for dropped commits 3: f9ef6d5569 < -: ---------- sequencer: update `total_nr' when adding an item to a todo list 4: 049a92dec0 < -: ---------- sequencer: update `done_nr' when skipping commands in a todo list 5: f7aae0c763 < -: ---------- sequencer: move the code writing total_nr on the disk to a new function 6: 0e41c4c85e < -: ---------- sequencer: add a parameter to sequencer_continue() to accept a todo list 7: e6f5589f18 < -: ---------- rebase-interactive: todo_list_check() also uses the done list 8: 69a562b0ab < -: ---------- rebase-interactive: warn if commit is dropped with --edit-todo 9: 4656ab11ae < -: ---------- sequencer: have read_populate_todo() check for dropped commits -: ---------- > 2: a4a700ce8b rebase-interactive: warn if commit is dropped with --edit-todo -- 2.24.0.2.ga4a700ce8b