diff --git a/sequencer.c b/sequencer.c index a46f3ad2e3..3ef77311cf 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3694,6 +3694,28 @@ static const char *reflog_message(struct replay_opts *opts, return buf.buf; } +static struct commit *lookup_label(struct repository *r, const char *label, + int len, struct strbuf *buf) +{ + struct commit *commit; + struct object_id oid; + + strbuf_reset(buf); + strbuf_addf(buf, "refs/rewritten/%.*s", len, label); + if (!read_ref(buf->buf, &oid)) { + commit = lookup_commit_object(r, &oid); + } else { + /* fall back to non-rewritten ref or commit */ + strbuf_splice(buf, 0, strlen("refs/rewritten/"), "", 0); + commit = lookup_commit_reference_by_name(buf->buf); + } + + if (!commit) + error(_("could not resolve '%s'"), buf->buf); + + return commit; +} + static int do_reset(struct repository *r, const char *name, int len, struct replay_opts *opts) @@ -3725,6 +3747,7 @@ static int do_reset(struct repository *r, oidcpy(&oid, &opts->squash_onto); } else { int i; + struct commit *commit; /* Determine the length of the label */ for (i = 0; i < len; i++) @@ -3732,12 +3755,12 @@ static int do_reset(struct repository *r, break; len = i; - strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name); - if (get_oid(ref_name.buf, &oid) && - get_oid(ref_name.buf + strlen("refs/rewritten/"), &oid)) { - ret = error(_("could not read '%s'"), ref_name.buf); + commit = lookup_label(r, name, len, &ref_name); + if (!commit) { + ret = -1; goto cleanup; } + oid = commit->object.oid; } setup_unpack_trees_porcelain(&unpack_tree_opts, "reset"); @@ -3785,26 +3808,6 @@ static int do_reset(struct repository *r, return ret; } -static struct commit *lookup_label(const char *label, int len, - struct strbuf *buf) -{ - struct commit *commit; - - strbuf_reset(buf); - strbuf_addf(buf, "refs/rewritten/%.*s", len, label); - commit = lookup_commit_reference_by_name(buf->buf); - if (!commit) { - /* fall back to non-rewritten ref or commit */ - strbuf_splice(buf, 0, strlen("refs/rewritten/"), "", 0); - commit = lookup_commit_reference_by_name(buf->buf); - } - - if (!commit) - error(_("could not resolve '%s'"), buf->buf); - - return commit; -} - static int do_merge(struct repository *r, struct commit *commit, const char *arg, int arg_len, @@ -3852,7 +3855,7 @@ static int do_merge(struct repository *r, k = strcspn(p, " \t\n"); if (!k) continue; - merge_commit = lookup_label(p, k, &ref_name); + merge_commit = lookup_label(r, p, k, &ref_name); if (!merge_commit) { ret = error(_("unable to parse '%.*s'"), k, p); goto leave_merge; diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index f351701fec..fa2a06c19f 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -138,6 +138,23 @@ test_expect_success '`reset` refuses to overwrite untracked files' ' git rebase --abort ' +test_expect_success '`reset` rejects trees' ' + test_when_finished "test_might_fail git rebase --abort" && + test_must_fail env GIT_SEQUENCE_EDITOR="echo reset A^{tree} >" \ + git rebase -i B C >out 2>err && + grep "object .* is a tree" err && + test_must_be_empty out +' + +test_expect_success '`reset` only looks for labels under refs/rewritten/' ' + test_when_finished "test_might_fail git rebase --abort" && + git branch refs/rewritten/my-label A && + test_must_fail env GIT_SEQUENCE_EDITOR="echo reset my-label >" \ + git rebase -i B C >out 2>err && + grep "could not resolve ${SQ}my-label${SQ}" err && + test_must_be_empty out +' + test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' ' test_when_finished "test_might_fail git rebase --abort" && git checkout -b conflicting-merge A &&