2023-04-11 15:41:56 +08:00
|
|
|
#include "git-compat-util.h"
|
2018-08-11 00:51:29 +08:00
|
|
|
#include "commit.h"
|
2023-04-11 15:41:57 +08:00
|
|
|
#include "editor.h"
|
2023-03-21 14:26:03 +08:00
|
|
|
#include "environment.h"
|
2023-03-21 14:25:54 +08:00
|
|
|
#include "gettext.h"
|
2018-08-11 00:51:29 +08:00
|
|
|
#include "sequencer.h"
|
2019-01-29 23:01:49 +08:00
|
|
|
#include "rebase-interactive.h"
|
2023-04-23 04:17:20 +08:00
|
|
|
#include "repository.h"
|
2018-08-11 00:51:29 +08:00
|
|
|
#include "strbuf.h"
|
2019-01-29 23:01:49 +08:00
|
|
|
#include "commit-slab.h"
|
|
|
|
#include "config.h"
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
#include "dir.h"
|
2023-04-11 15:41:49 +08:00
|
|
|
#include "object-name.h"
|
2023-03-21 14:26:01 +08:00
|
|
|
#include "wrapper.h"
|
2019-01-29 23:01:49 +08:00
|
|
|
|
2020-01-29 05:12:45 +08:00
|
|
|
static const char edit_todo_list_advice[] =
|
|
|
|
N_("You can fix this with 'git rebase --edit-todo' "
|
|
|
|
"and then run 'git rebase --continue'.\n"
|
|
|
|
"Or you can abort the rebase with 'git rebase"
|
|
|
|
" --abort'.\n");
|
|
|
|
|
2019-01-29 23:01:49 +08:00
|
|
|
enum missing_commit_check_level {
|
|
|
|
MISSING_COMMIT_CHECK_IGNORE = 0,
|
|
|
|
MISSING_COMMIT_CHECK_WARN,
|
|
|
|
MISSING_COMMIT_CHECK_ERROR
|
|
|
|
};
|
|
|
|
|
|
|
|
static enum missing_commit_check_level get_missing_commit_check_level(void)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
if (git_config_get_value("rebase.missingcommitscheck", &value) ||
|
|
|
|
!strcasecmp("ignore", value))
|
|
|
|
return MISSING_COMMIT_CHECK_IGNORE;
|
|
|
|
if (!strcasecmp("warn", value))
|
|
|
|
return MISSING_COMMIT_CHECK_WARN;
|
|
|
|
if (!strcasecmp("error", value))
|
|
|
|
return MISSING_COMMIT_CHECK_ERROR;
|
|
|
|
warning(_("unrecognized setting %s for option "
|
|
|
|
"rebase.missingCommitsCheck. Ignoring."), value);
|
|
|
|
return MISSING_COMMIT_CHECK_IGNORE;
|
|
|
|
}
|
2018-08-11 00:51:29 +08:00
|
|
|
|
rebase (interactive-backend): make --keep-empty the default
Different rebase backends have different treatment for commits which
start empty (i.e. have no changes relative to their parent), and the
--keep-empty option was added at some point to allow adjusting behavior.
The handling of commits which start empty is actually quite similar to
commit b00bf1c9a8dd (git-rebase: make --allow-empty-message the default,
2018-06-27), which pointed out that the behavior for various backends is
often more happenstance than design. The specific change made in that
commit is actually quite relevant as well and much of the logic there
directly applies here.
It makes a lot of sense in 'git commit' to error out on the creation of
empty commits, unless an override flag is provided. However, once
someone determines that there is a rare case that merits using the
manual override to create such a commit, it is somewhere between
annoying and harmful to have to take extra steps to keep such
intentional commits around. Granted, empty commits are quite rare,
which is why handling of them doesn't get considered much and folks tend
to defer to existing (accidental) behavior and assume there was a reason
for it, leading them to just add flags (--keep-empty in this case) that
allow them to override the bad defaults. Fix the interactive backend so
that --keep-empty is the default, much like we did with
--allow-empty-message. The am backend should also be fixed to have
--keep-empty semantics for commits that start empty, but that is not
included in this patch other than a testcase documenting the failure.
Note that there was one test in t3421 which appears to have been written
expecting --keep-empty to not be the default as correct behavior. This
test was introduced in commit 00b8be5a4d38 ("add tests for rebasing of
empty commits", 2013-06-06), which was part of a series focusing on
rebase topology and which had an interesting original cover letter at
https://lore.kernel.org/git/1347949878-12578-1-git-send-email-martinvonz@gmail.com/
which noted
Your input especially appreciated on whether you agree with the
intent of the test cases.
and then went into a long example about how one of the many tests added
had several questions about whether it was correct. As such, I believe
most the tests in that series were about testing rebase topology with as
many different flags as possible and were not trying to state in general
how those flags should behave otherwise.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-16 05:36:24 +08:00
|
|
|
void append_todo_help(int command_count,
|
2019-03-06 03:18:02 +08:00
|
|
|
const char *shortrevisions, const char *shortonto,
|
2018-08-11 00:51:35 +08:00
|
|
|
struct strbuf *buf)
|
2018-08-11 00:51:29 +08:00
|
|
|
{
|
|
|
|
const char *msg = _("\nCommands:\n"
|
|
|
|
"p, pick <commit> = use commit\n"
|
|
|
|
"r, reword <commit> = use commit, but edit the commit message\n"
|
|
|
|
"e, edit <commit> = use commit, but stop for amending\n"
|
|
|
|
"s, squash <commit> = use commit, but meld into previous commit\n"
|
2021-02-10 19:36:43 +08:00
|
|
|
"f, fixup [-C | -c] <commit> = like \"squash\" but keep only the previous\n"
|
|
|
|
" commit's log message, unless -C is used, in which case\n"
|
|
|
|
" keep only this commit's message; -c is same as -C but\n"
|
|
|
|
" opens the editor\n"
|
2018-08-11 00:51:29 +08:00
|
|
|
"x, exec <command> = run command (the rest of the line) using shell\n"
|
2018-10-12 21:14:26 +08:00
|
|
|
"b, break = stop here (continue rebase later with 'git rebase --continue')\n"
|
2018-08-11 00:51:29 +08:00
|
|
|
"d, drop <commit> = remove commit\n"
|
|
|
|
"l, label <label> = label current HEAD with a name\n"
|
|
|
|
"t, reset <label> = reset HEAD to a label\n"
|
|
|
|
"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
|
2022-07-20 02:33:36 +08:00
|
|
|
" create a merge commit using the original merge commit's\n"
|
|
|
|
" message (or the oneline, if no original merge commit was\n"
|
|
|
|
" specified); use -c <commit> to reword the commit message\n"
|
2022-07-20 02:33:38 +08:00
|
|
|
"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
|
|
|
|
" to this position in the new commits. The <ref> is\n"
|
|
|
|
" updated at the end of the rebase\n"
|
2018-08-11 00:51:29 +08:00
|
|
|
"\n"
|
|
|
|
"These lines can be re-ordered; they are executed from top to bottom.\n");
|
2019-03-06 03:18:02 +08:00
|
|
|
unsigned edit_todo = !(shortrevisions && shortonto);
|
|
|
|
|
|
|
|
if (!edit_todo) {
|
|
|
|
strbuf_addch(buf, '\n');
|
|
|
|
strbuf_commented_addf(buf, Q_("Rebase %s onto %s (%d command)",
|
|
|
|
"Rebase %s onto %s (%d commands)",
|
|
|
|
command_count),
|
|
|
|
shortrevisions, shortonto, command_count);
|
|
|
|
}
|
2018-08-11 00:51:29 +08:00
|
|
|
|
2018-08-11 00:51:35 +08:00
|
|
|
strbuf_add_commented_lines(buf, msg, strlen(msg));
|
2018-08-11 00:51:29 +08:00
|
|
|
|
|
|
|
if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)
|
|
|
|
msg = _("\nDo not remove any line. Use 'drop' "
|
|
|
|
"explicitly to remove a commit.\n");
|
|
|
|
else
|
|
|
|
msg = _("\nIf you remove a line here "
|
|
|
|
"THAT COMMIT WILL BE LOST.\n");
|
|
|
|
|
2018-08-11 00:51:35 +08:00
|
|
|
strbuf_add_commented_lines(buf, msg, strlen(msg));
|
2018-08-11 00:51:29 +08:00
|
|
|
|
|
|
|
if (edit_todo)
|
|
|
|
msg = _("\nYou are editing the todo file "
|
|
|
|
"of an ongoing interactive rebase.\n"
|
|
|
|
"To continue rebase after editing, run:\n"
|
|
|
|
" git rebase --continue\n\n");
|
|
|
|
else
|
|
|
|
msg = _("\nHowever, if you remove everything, "
|
|
|
|
"the rebase will be aborted.\n\n");
|
|
|
|
|
2018-08-11 00:51:35 +08:00
|
|
|
strbuf_add_commented_lines(buf, msg, strlen(msg));
|
|
|
|
}
|
|
|
|
|
2019-03-06 03:18:03 +08:00
|
|
|
int edit_todo_list(struct repository *r, struct todo_list *todo_list,
|
|
|
|
struct todo_list *new_todo, const char *shortrevisions,
|
|
|
|
const char *shortonto, unsigned flags)
|
2018-08-11 00:51:31 +08:00
|
|
|
{
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
const char *todo_file = rebase_path_todo(),
|
|
|
|
*todo_backup = rebase_path_todo_backup();
|
2019-03-06 03:18:03 +08:00
|
|
|
unsigned initial = shortrevisions && shortonto;
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
int incorrect = 0;
|
2018-08-11 00:51:31 +08:00
|
|
|
|
2019-03-06 03:18:03 +08:00
|
|
|
/* If the user is editing the todo list, we first try to parse
|
|
|
|
* it. If there is an error, we do not return, because the user
|
|
|
|
* might want to fix it in the first place. */
|
|
|
|
if (!initial)
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
incorrect = todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list) |
|
|
|
|
file_exists(rebase_path_dropped());
|
2019-03-06 03:18:03 +08:00
|
|
|
|
|
|
|
if (todo_list_write_to_file(r, todo_list, todo_file, shortrevisions, shortonto,
|
|
|
|
-1, flags | TODO_LIST_SHORTEN_IDS | TODO_LIST_APPEND_TODO_HELP))
|
|
|
|
return error_errno(_("could not write '%s'"), todo_file);
|
|
|
|
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
if (!incorrect &&
|
|
|
|
todo_list_write_to_file(r, todo_list, todo_backup,
|
2020-01-23 20:28:19 +08:00
|
|
|
shortrevisions, shortonto, -1,
|
|
|
|
(flags | TODO_LIST_APPEND_TODO_HELP) & ~TODO_LIST_SHORTEN_IDS) < 0)
|
|
|
|
return error(_("could not write '%s'."), rebase_path_todo_backup());
|
2019-03-06 03:18:03 +08:00
|
|
|
|
|
|
|
if (launch_sequence_editor(todo_file, &new_todo->buf, NULL))
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
strbuf_stripspace(&new_todo->buf, 1);
|
|
|
|
if (initial && new_todo->buf.len == 0)
|
|
|
|
return -3;
|
2018-08-11 00:51:35 +08:00
|
|
|
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
if (todo_list_parse_insn_buffer(r, new_todo->buf.buf, new_todo)) {
|
|
|
|
fprintf(stderr, _(edit_todo_list_advice));
|
|
|
|
return -4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (incorrect) {
|
|
|
|
if (todo_list_check_against_backup(r, new_todo)) {
|
2020-02-28 04:25:30 +08:00
|
|
|
write_file(rebase_path_dropped(), "%s", "");
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
return -4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (incorrect > 0)
|
|
|
|
unlink(rebase_path_dropped());
|
|
|
|
} else if (todo_list_check(todo_list, new_todo)) {
|
2020-02-28 04:25:30 +08:00
|
|
|
write_file(rebase_path_dropped(), "%s", "");
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
return -4;
|
|
|
|
}
|
2018-08-11 00:51:31 +08:00
|
|
|
|
2022-07-20 02:33:41 +08:00
|
|
|
/*
|
|
|
|
* See if branches need to be added or removed from the update-refs
|
|
|
|
* file based on the new todo list.
|
|
|
|
*/
|
|
|
|
todo_list_filter_update_refs(r, new_todo);
|
|
|
|
|
2019-03-06 03:18:03 +08:00
|
|
|
return 0;
|
2018-08-11 00:51:31 +08:00
|
|
|
}
|
2019-01-29 23:01:49 +08:00
|
|
|
|
|
|
|
define_commit_slab(commit_seen, unsigned char);
|
|
|
|
/*
|
|
|
|
* Check if the user dropped some commits by mistake
|
|
|
|
* Behaviour determined by rebase.missingCommitsCheck.
|
|
|
|
* Check if there is an unrecognized command or a
|
|
|
|
* bad SHA-1 in a command.
|
|
|
|
*/
|
|
|
|
int todo_list_check(struct todo_list *old_todo, struct todo_list *new_todo)
|
|
|
|
{
|
|
|
|
enum missing_commit_check_level check_level = get_missing_commit_check_level();
|
|
|
|
struct strbuf missing = STRBUF_INIT;
|
|
|
|
int res = 0, i;
|
|
|
|
struct commit_seen commit_seen;
|
|
|
|
|
|
|
|
init_commit_seen(&commit_seen);
|
|
|
|
|
|
|
|
if (check_level == MISSING_COMMIT_CHECK_IGNORE)
|
|
|
|
goto leave_check;
|
|
|
|
|
|
|
|
/* Mark the commits in git-rebase-todo as seen */
|
|
|
|
for (i = 0; i < new_todo->nr; i++) {
|
|
|
|
struct commit *commit = new_todo->items[i].commit;
|
|
|
|
if (commit)
|
|
|
|
*commit_seen_at(&commit_seen, commit) = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find commits in git-rebase-todo.backup yet unseen */
|
|
|
|
for (i = old_todo->nr - 1; i >= 0; i--) {
|
|
|
|
struct todo_item *item = old_todo->items + i;
|
|
|
|
struct commit *commit = item->commit;
|
|
|
|
if (commit && !*commit_seen_at(&commit_seen, commit)) {
|
|
|
|
strbuf_addf(&missing, " - %s %.*s\n",
|
2023-03-28 21:58:46 +08:00
|
|
|
repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
|
2019-01-29 23:01:49 +08:00
|
|
|
item->arg_len,
|
|
|
|
todo_item_get_arg(old_todo, item));
|
|
|
|
*commit_seen_at(&commit_seen, commit) = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Warn about missing commits */
|
|
|
|
if (!missing.len)
|
|
|
|
goto leave_check;
|
|
|
|
|
|
|
|
if (check_level == MISSING_COMMIT_CHECK_ERROR)
|
|
|
|
res = 1;
|
|
|
|
|
|
|
|
fprintf(stderr,
|
|
|
|
_("Warning: some commits may have been dropped accidentally.\n"
|
|
|
|
"Dropped commits (newer to older):\n"));
|
|
|
|
|
|
|
|
/* Make the list user-friendly and display */
|
|
|
|
fputs(missing.buf, stderr);
|
|
|
|
strbuf_release(&missing);
|
|
|
|
|
|
|
|
fprintf(stderr, _("To avoid this message, use \"drop\" to "
|
|
|
|
"explicitly remove a commit.\n\n"
|
|
|
|
"Use 'git config rebase.missingCommitsCheck' to change "
|
|
|
|
"the level of warnings.\n"
|
|
|
|
"The possible behaviours are: ignore, warn, error.\n\n"));
|
|
|
|
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
fprintf(stderr, _(edit_todo_list_advice));
|
|
|
|
|
2019-01-29 23:01:49 +08:00
|
|
|
leave_check:
|
|
|
|
clear_commit_seen(&commit_seen);
|
|
|
|
return res;
|
|
|
|
}
|
2020-01-29 05:12:45 +08:00
|
|
|
|
rebase-interactive: warn if commit is dropped with `rebase --edit-todo'
When set to "warn" or "error", `rebase.missingCommitsCheck' 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.
This adds the ability for `rebase --edit-todo' and `rebase --continue'
to check if commits were dropped by the user. As both edit_todo_list()
and complete_action() parse the todo list and check for dropped commits,
the code doing so in the latter is removed to reduce duplication.
`edit_todo_list_advice' is removed from sequencer.c as it is no longer
used there.
This changes when a backup of the todo list is made. Until now, it was
saved only once, before the initial edit. Now, it is also made if the
original todo list has no errors or no dropped commits. Thus, the
backup should be error-free. Without this, sequencer_continue()
(`rebase --continue') could only compare the current todo list against
the original, unedited list. Before this change, this file was only
used by edit_todo_list() and `rebase -p' to create the backup before
the initial edit, and check_todo_list_from_file(), only used by
`rebase -p' to check for dropped commits after its own initial edit.
If the edited list has an error, a file, `dropped', is created to
report the issue. Otherwise, it is deleted. Usually, the edited list
is compared against the list before editing, but if this file exists,
it will be compared to the backup. Also, if the file exists,
sequencer_continue() checks the list for dropped commits. If the
check was performed every time, it would fail when resuming a rebase
after resolving a conflict, as the backup will contain commits that
were picked, but they will not be in the new list. It's safe to
ignore this check if `dropped' does not exist, because that means that
no errors were found at the last edition, so any missing commits here
have already been picked.
Five tests are added to t3404. 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. In the third
test, it is also checked that `--continue' will refuse to resume the
rebase if commits were dropped. The fourth test checks that no errors
are raised when resuming a rebase after resolving a conflict, the fifth
checks that no errors are raised when editing the todo list after
pausing the rebase.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-29 05:12:46 +08:00
|
|
|
int todo_list_check_against_backup(struct repository *r, struct todo_list *todo_list)
|
|
|
|
{
|
|
|
|
struct todo_list backup = TODO_LIST_INIT;
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
if (strbuf_read_file(&backup.buf, rebase_path_todo_backup(), 0) > 0) {
|
|
|
|
todo_list_parse_insn_buffer(r, backup.buf.buf, &backup);
|
|
|
|
res = todo_list_check(&backup, todo_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
todo_list_release(&backup);
|
|
|
|
return res;
|
|
|
|
}
|