[PATCH] sequencer: Skip copying notes for commits that disappear during rebase
- From
- Uwe Kleine-König <u.kleine-koenig@baylibre.com>
- Date
- Jun 16, 2026, 17:40 UTC
- Message-ID
- <20260616174012.601651-2-u.kleine-koenig@baylibre.com>
When a commit disappears during rebase because the patch content is already there (but not by the same patch in which case the commit would be skipped) the notes of that disappearing commit should not be copied to the unrelated commit that happens to be HEAD.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com> --- Hello,
after also my 2nd bug report[1] didn't motivate anyone to come up with a fix, I invested the time to work out one according to Phillip Wood's suggestion.
IMHO it's not pretty, but it works for me.
Note that Phillip also suggested to integrete the test into t3400-rebase.sh . IMHO it doesn't matter much if this is considered a rebase test or a notes test. I kept it where I have it because I'm lazy and failed to understand the git history created in that test.
Best regards Uwe
[1] https://lore.kernel.org/git/20260612143952.3281115-2-u.kleine-koenig@baylibre.com
sequencer.c | 20 ++++++++++---------- t/meson.build | 1 + t/t3322-notes-rebase.sh | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100755 t/t3322-notes-rebase.sh
diff --git a/sequencer.c b/sequencer.c index 57855b0066ac..da2185a37c5d 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2263,7 +2263,7 @@ static const char *reflog_message(struct replay_opts *opts, static int do_pick_commit(struct repository *r, struct todo_item *item, struct replay_opts *opts, - int final_fixup, int *check_todo) + int final_fixup, int *check_todo, int *dropped_commit) { struct replay_ctx *ctx = opts->ctx; unsigned int flags = should_edit(opts) ? EDIT_MSG : 0; @@ -2273,7 +2273,7 @@ static int do_pick_commit(struct repository *r, const char *base_label, *next_label, *reflog_action; char *author = NULL; struct commit_message msg = { NULL, NULL, NULL, NULL }; - int res, unborn = 0, reword = 0, allow, drop_commit; + int res, unborn = 0, reword = 0, allow; enum todo_command command = item->command; struct commit *commit = item->commit; @@ -2492,7 +2492,7 @@ static int do_pick_commit(struct repository *r, goto leave; } - drop_commit = 0; + *dropped_commit = 0; allow = allow_empty(r, opts, commit); if (allow < 0) { res = allow; @@ -2500,7 +2500,7 @@ static int do_pick_commit(struct repository *r, } else if (allow == 1) { flags |= ALLOW_EMPTY; } else if (allow == 2) { - drop_commit = 1; + *dropped_commit = 1; refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF); unlink(git_path_merge_msg(r)); @@ -2510,7 +2510,7 @@ static int do_pick_commit(struct repository *r, _("dropping %s %s -- patch contents already upstream\n"), oid_to_hex(&commit->object.oid), msg.subject); } /* else allow == 0 and there's nothing special to do */ - if (!opts->no_commit && !drop_commit) { + if (!opts->no_commit && !*dropped_commit) { if (author || command == TODO_REVERT || (flags & AMEND_MSG)) res = do_commit(r, msg_file, author, reflog_action, opts, flags, @@ -4943,12 +4943,12 @@ static int pick_one_commit(struct repository *r, struct replay_opts *opts, int *check_todo, int* reschedule) { - int res; + int res, dropped_commit; struct todo_item *item = todo_list->items + todo_list->current; const char *arg = todo_item_get_arg(todo_list, item); res = do_pick_commit(r, item, opts, is_final_fixup(todo_list), - check_todo); + check_todo, &dropped_commit); if (is_rebase_i(opts) && res < 0) { /* Reschedule */ *reschedule = 1; @@ -4965,7 +4965,7 @@ static int pick_one_commit(struct repository *r, return error_with_patch(r, commit, arg, item->arg_len, opts, res, !res); } - if (is_rebase_i(opts) && !res) + if (is_rebase_i(opts) && !res && !dropped_commit) record_in_rewritten(&item->commit->object.oid, peek_command(todo_list, 1)); if (res && is_fixup(item->command)) { @@ -5523,14 +5523,14 @@ static int single_pick(struct repository *r, struct commit *cmit, struct replay_opts *opts) { - int check_todo; + int check_todo, dummy; struct todo_item item; item.command = opts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT; item.commit = cmit; - return do_pick_commit(r, &item, opts, 0, &check_todo); + return do_pick_commit(r, &item, opts, 0, &check_todo, &dummy); } int sequencer_pick_revisions(struct repository *r, diff --git a/t/meson.build b/t/meson.build index c5832fee0535..6927bd9c794f 100644 --- a/t/meson.build +++ b/t/meson.build @@ -358,6 +358,7 @@ integration_tests = [ 't3311-notes-merge-fanout.sh', 't3320-notes-merge-worktrees.sh', 't3321-notes-stripspace.sh', + 't3322-notes-rebase.sh', 't3400-rebase.sh', 't3401-rebase-and-am-rename.sh', 't3402-rebase-merge.sh', diff --git a/t/t3322-notes-rebase.sh b/t/t3322-notes-rebase.sh new file mode 100755 index 000000000000..0eddde7f9961 --- /dev/null +++ b/t/t3322-notes-rebase.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +test_description='Test notes on rebase' + +. ./test-lib.sh + +test_expect_success setup ' + git init && + git config notes.rewriteRef refs/notes/commits && + git version > version && + echo A > A && + git add A && + git commit -m A && + git branch branch && + echo B > B && + git add B && + git commit -m B && + git notes add -m "This is B" @ && + echo C > C && + git add C && + git commit -m C && + git checkout branch && + echo B > B && + echo D > D && + git add B D && + git commit -m BD +' + +test_expect_success 'rebase B + C on top of BD' ' + git rebase @ master +' + +test_expect_success 'assert there is no note on BD' ' + if git notes list branch >/tmp/lalaa; then return 1; fi +' + +test_done base-commit: 3e65291872de10c3f0bf05ea8c24187e7a71ebf0
-- 2.47.3