diff --git a/sequencer.c b/sequencer.c index ad0ab75c8d4dd7..2baaf716a3cc89 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4349,6 +4349,7 @@ static int do_merge(struct repository *r, error(_("could not even attempt to merge '%.*s'"), merge_arg_len, arg); unlink(git_path_merge_msg(r)); + unlink(git_path_merge_head(r)); goto leave_merge; } /* @@ -5364,7 +5365,7 @@ static int commit_staged_changes(struct repository *r, flags |= AMEND_MSG; } - if (is_clean) { + if (is_clean && !file_exists(git_path_merge_head(r))) { if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") && refs_delete_ref(get_main_ref_store(r), "", diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 127216f7225aa4..f4b459fea16af2 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -111,6 +111,30 @@ test_expect_success 'rebase -r passes merge strategy options correctly' ' git rebase --continue ' +test_expect_success '--continue creates merge commit after empty resolution' ' + git reset --hard main && + git checkout -b rebase_i_merge && + test_commit unrelated && + git checkout -b rebase_i_merge_side && + test_commit side2 main.txt && + git checkout rebase_i_merge && + test_commit side1 main.txt && + PICK=$(git rev-parse --short rebase_i_merge) && + test_must_fail git merge rebase_i_merge_side && + echo side1 >main.txt && + git add main.txt && + test_tick && + git commit --no-edit && + FAKE_LINES="1 2 3 5 6 7 8 9 10 11" && + export FAKE_LINES && + test_must_fail git rebase -ir main && + echo side1 >main.txt && + git add main.txt && + git rebase --continue && + git log --merges >out && + test_grep "Merge branch '\''rebase_i_merge_side'\''" out +' + test_expect_success '--skip after failed fixup cleans commit message' ' test_when_finished "test_might_fail git rebase --abort" && git checkout -b with-conflicting-fixup && diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 802f8f704c62eb..b37e99625b4e65 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -183,6 +183,81 @@ EOF test_cmp expected actual ' +test_expect_success 'status during rebase -ir after conflicted merge (exec git merge)' ' + git reset --hard main && + git checkout -b rebase_i_merge && + test_commit unrelated && + git checkout -b rebase_i_merge_side && + test_commit side2 main.txt && + git checkout rebase_i_merge && + test_commit side1 main.txt && + PICK=$(git rev-parse --short rebase_i_merge) && + test_must_fail git merge rebase_i_merge_side && + echo side1 >main.txt && + git add main.txt && + test_tick && + git commit --no-edit && + MERGE=$(git rev-parse --short rebase_i_merge) && + ONTO=$(git rev-parse --short main) && + test_when_finished "git rebase --abort" && + FAKE_LINES="1 2 3 5 6 7 8 9 10 exec_git_merge_refs/rewritten/rebase-i-merge-side" && + export FAKE_LINES && + test_must_fail git rebase -ir main && + cat >expect <..." to mark resolution) + both modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF + git status --untracked-files=no >actual && + test_cmp expect actual +' + +test_expect_success 'status during rebase -ir after replaying conflicted merge (merge)' ' + PICK=$(git rev-parse --short :/side1) && + UNRELATED=$(git rev-parse --short :/unrelated) && + MERGE=$(git rev-parse --short rebase_i_merge) && + ONTO=$(git rev-parse --short main) && + test_when_finished "git rebase --abort" && + FAKE_LINES="1 2 3 5 6 7 8 9 10 11 4" && + export FAKE_LINES && + test_must_fail git rebase -ir main && + cat >expect <..." to mark resolution) + both modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF + git status --untracked-files=no >actual && + test_cmp expect actual +' + test_expect_success 'status when rebasing -i in edit mode' ' git reset --hard main && diff --git a/wt-status.c b/wt-status.c index 1da5732f57b115..f15495039e3eb1 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1342,9 +1342,11 @@ static int split_commit_in_progress(struct wt_status *s) /* * Turn - * "pick d6a2f0303e897ec257dd0e0a39a5ccb709bc2047 some message" + * "pick d6a2f0303e897ec257dd0e0a39a5ccb709bc2047 some message" and + * "merge -C d6a2f0303e897ec257dd0e0a39a5ccb709bc2047 some-branch" * into - * "pick d6a2f03 some message" + * "pick d6a2f03 some message" and + * "merge -C d6a2f03 some-branch" * * The function assumes that the line does not contain useless spaces * before or after the command. @@ -1360,20 +1362,31 @@ static void abbrev_oid_in_line(struct strbuf *line) starts_with(line->buf, "l ")) return; - split = strbuf_split_max(line, ' ', 3); + split = strbuf_split_max(line, ' ', 4); if (split[0] && split[1]) { struct object_id oid; - + struct strbuf *hash; + + if ((!strcmp(split[0]->buf, "merge ") || + !strcmp(split[0]->buf, "m " ) || + !strcmp(split[0]->buf, "fixup ") || + !strcmp(split[0]->buf, "f " )) && + (!strcmp(split[1]->buf, "-C ") || + !strcmp(split[1]->buf, "-c "))) { + hash = split[2]; + } else { + hash = split[1]; + } /* * strbuf_split_max left a space. Trim it and re-add * it after abbreviation. */ - strbuf_trim(split[1]); - if (!repo_get_oid(the_repository, split[1]->buf, &oid)) { - strbuf_reset(split[1]); - strbuf_add_unique_abbrev(split[1], &oid, + strbuf_trim(hash); + if (!repo_get_oid(the_repository, hash->buf, &oid)) { + strbuf_reset(hash); + strbuf_add_unique_abbrev(hash, &oid, DEFAULT_ABBREV); - strbuf_addch(split[1], ' '); + strbuf_addch(hash, ' '); strbuf_reset(line); for (i = 0; split[i]; i++) strbuf_addbuf(line, split[i]); @@ -1731,6 +1744,7 @@ int wt_status_check_rebase(const struct worktree *wt, struct wt_status_state *state) { struct stat st; + struct string_list have_done = STRING_LIST_INIT_DUP; if (!stat(worktree_git_path(the_repository, wt, "rebase-apply"), &st)) { if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/applying"), &st)) { @@ -1747,8 +1761,12 @@ int wt_status_check_rebase(const struct worktree *wt, state->rebase_interactive_in_progress = 1; else state->rebase_in_progress = 1; + read_rebase_todolist("rebase-merge/done", &have_done); + if (have_done.nr > 0 && starts_with(have_done.items[have_done.nr - 1].string, "merge")) + state->merge_during_rebase_in_progress = 1; state->branch = get_branch(wt, "rebase-merge/head-name"); state->onto = get_branch(wt, "rebase-merge/onto"); + string_list_clear(&have_done, 0); } else return 0; return 1; @@ -1842,10 +1860,15 @@ static void wt_longstatus_print_state(struct wt_status *s) if (state->merge_in_progress) { if (state->rebase_interactive_in_progress) { - show_rebase_information(s, state_color); - fputs("\n", s->fp); - } - show_merge_in_progress(s, state_color); + if (state->merge_during_rebase_in_progress) + show_rebase_in_progress(s, state_color); + else { + show_rebase_information(s, state_color); + fputs("\n", s->fp); + show_merge_in_progress(s, state_color); + } + } else + show_merge_in_progress(s, state_color); } else if (state->am_in_progress) show_am_in_progress(s, state_color); else if (state->rebase_in_progress || state->rebase_interactive_in_progress) diff --git a/wt-status.h b/wt-status.h index 4e377ce62b8b28..84bedfcd48f6cb 100644 --- a/wt-status.h +++ b/wt-status.h @@ -87,6 +87,7 @@ struct wt_status_state { int am_empty_patch; int rebase_in_progress; int rebase_interactive_in_progress; + int merge_during_rebase_in_progress; int cherry_pick_in_progress; int bisect_in_progress; int revert_in_progress;