rebase --apply: set ORIG_HEAD correctly

At the start of a rebase, ORIG_HEAD is updated to the tip of the
branch being rebased. Unfortunately reset_head() always uses the
current value of HEAD for this which is incorrect if the rebase is
started with "git rebase <upstream> <branch>" as in that case
ORIG_HEAD should be updated to <branch>. This only affects the "apply"
backend as the "merge" backend does not yet use reset_head() for the
initial checkout. Fix this by passing in orig_head when calling
reset_head() and add some regression tests.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Phillip Wood 2022-01-26 13:05:48 +00:00 committed by Junio C Hamano
parent 7700ab087b
commit cd1528ef8e
4 changed files with 34 additions and 1 deletions

View File

@ -1769,6 +1769,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
strbuf_addf(&msg, "%s: checkout %s", strbuf_addf(&msg, "%s: checkout %s",
getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name); getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
ropts.oid = &options.onto->object.oid; ropts.oid = &options.onto->object.oid;
ropts.orig_head = &options.orig_head,
ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD | ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD |
RESET_HEAD_RUN_POST_CHECKOUT_HOOK; RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
ropts.head_msg = msg.buf; ropts.head_msg = msg.buf;

View File

@ -15,6 +15,7 @@ static int update_refs(const struct reset_head_opts *opts,
unsigned detach_head = opts->flags & RESET_HEAD_DETACH; unsigned detach_head = opts->flags & RESET_HEAD_DETACH;
unsigned run_hook = opts->flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK; unsigned run_hook = opts->flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
unsigned update_orig_head = opts->flags & RESET_ORIG_HEAD; unsigned update_orig_head = opts->flags & RESET_ORIG_HEAD;
const struct object_id *orig_head = opts->orig_head;
const char *switch_to_branch = opts->branch; const char *switch_to_branch = opts->branch;
const char *reflog_branch = opts->branch_msg; const char *reflog_branch = opts->branch_msg;
const char *reflog_head = opts->head_msg; const char *reflog_head = opts->head_msg;
@ -43,7 +44,8 @@ static int update_refs(const struct reset_head_opts *opts,
strbuf_addstr(&msg, "updating ORIG_HEAD"); strbuf_addstr(&msg, "updating ORIG_HEAD");
reflog_orig_head = msg.buf; reflog_orig_head = msg.buf;
} }
update_ref(reflog_orig_head, "ORIG_HEAD", head, update_ref(reflog_orig_head, "ORIG_HEAD",
orig_head ? orig_head : head,
old_orig, 0, UPDATE_REFS_MSG_ON_ERR); old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig) } else if (old_orig)
delete_ref(NULL, "ORIG_HEAD", old_orig, 0); delete_ref(NULL, "ORIG_HEAD", old_orig, 0);

View File

@ -22,6 +22,10 @@ struct reset_head_opts {
* The commit to checkout/reset to. Defaults to HEAD. * The commit to checkout/reset to. Defaults to HEAD.
*/ */
const struct object_id *oid; const struct object_id *oid;
/*
* Optional value to set ORIG_HEAD. Defaults to HEAD.
*/
const struct object_id *orig_head;
/* /*
* Optional branch to switch to. * Optional branch to switch to.
*/ */

View File

@ -308,4 +308,30 @@ test_expect_success 'there is no --no-reschedule-failed-exec in an ongoing rebas
test_expect_code 129 git rebase --edit-todo --no-reschedule-failed-exec test_expect_code 129 git rebase --edit-todo --no-reschedule-failed-exec
' '
test_orig_head_helper () {
test_when_finished 'git rebase --abort &&
git checkout topic &&
git reset --hard commit-new-file-F2-on-topic-branch' &&
git update-ref -d ORIG_HEAD &&
test_must_fail git rebase "$@" &&
test_cmp_rev ORIG_HEAD commit-new-file-F2-on-topic-branch
}
test_orig_head () {
type=$1
test_expect_success "rebase $type sets ORIG_HEAD correctly" '
git checkout topic &&
git reset --hard commit-new-file-F2-on-topic-branch &&
test_orig_head_helper $type main
'
test_expect_success "rebase $type <upstream> <branch> sets ORIG_HEAD correctly" '
git checkout main &&
test_orig_head_helper $type main topic
'
}
test_orig_head --apply
test_orig_head --merge
test_done test_done