Merge branch 'pw/rebase-of-a-tag-fix'

"git rebase <upstream> <tag>" failed when aborted in the middle, as
it mistakenly tried to write the tag object instead of peeling it
to HEAD.

* pw/rebase-of-a-tag-fix:
  rebase: dereference tags
  rebase: use lookup_commit_reference_by_name()
  rebase: use our standard error return value
  t3407: rework rebase --quit tests
  t3407: strengthen rebase --abort tests
  t3407: use test_path_is_missing
  t3407: rename a variable
  t3407: use test_cmp_rev
  t3407: use test_commit
  t3407: run tests in $TEST_DIRECTORY
This commit is contained in:
Junio C Hamano
2021-10-06 13:40:11 -07:00
2 changed files with 67 additions and 87 deletions

View File

@ -765,17 +765,6 @@ static int finish_rebase(struct rebase_options *opts)
return ret; return ret;
} }
static struct commit *peel_committish(const char *name)
{
struct object *obj;
struct object_id oid;
if (get_oid(name, &oid))
return NULL;
obj = parse_object(the_repository, &oid);
return (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
}
static void add_var(struct strbuf *buf, const char *name, const char *value) static void add_var(struct strbuf *buf, const char *name, const char *value)
{ {
if (!value) if (!value)
@ -1580,7 +1569,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("could not move back to %s"), die(_("could not move back to %s"),
oid_to_hex(&options.orig_head)); oid_to_hex(&options.orig_head));
remove_branch_state(the_repository, 0); remove_branch_state(the_repository, 0);
ret = !!finish_rebase(&options); ret = finish_rebase(&options);
goto cleanup; goto cleanup;
} }
case ACTION_QUIT: { case ACTION_QUIT: {
@ -1589,11 +1578,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct replay_opts replay = REPLAY_OPTS_INIT; struct replay_opts replay = REPLAY_OPTS_INIT;
replay.action = REPLAY_INTERACTIVE_REBASE; replay.action = REPLAY_INTERACTIVE_REBASE;
ret = !!sequencer_remove_state(&replay); ret = sequencer_remove_state(&replay);
} else { } else {
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addstr(&buf, options.state_dir); strbuf_addstr(&buf, options.state_dir);
ret = !!remove_dir_recursively(&buf, 0); ret = remove_dir_recursively(&buf, 0);
if (ret) if (ret)
error(_("could not remove '%s'"), error(_("could not remove '%s'"),
options.state_dir); options.state_dir);
@ -1851,7 +1840,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (!strcmp(options.upstream_name, "-")) if (!strcmp(options.upstream_name, "-"))
options.upstream_name = "@{-1}"; options.upstream_name = "@{-1}";
} }
options.upstream = peel_committish(options.upstream_name); options.upstream =
lookup_commit_reference_by_name(options.upstream_name);
if (!options.upstream) if (!options.upstream)
die(_("invalid upstream '%s'"), options.upstream_name); die(_("invalid upstream '%s'"), options.upstream_name);
options.upstream_arg = options.upstream_name; options.upstream_arg = options.upstream_name;
@ -1894,7 +1884,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.onto = lookup_commit_or_die(&merge_base, options.onto = lookup_commit_or_die(&merge_base,
options.onto_name); options.onto_name);
} else { } else {
options.onto = peel_committish(options.onto_name); options.onto =
lookup_commit_reference_by_name(options.onto_name);
if (!options.onto) if (!options.onto)
die(_("Does not point to a valid commit '%s'"), die(_("Does not point to a valid commit '%s'"),
options.onto_name); options.onto_name);
@ -1919,13 +1910,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die_if_checked_out(buf.buf, 1); die_if_checked_out(buf.buf, 1);
options.head_name = xstrdup(buf.buf); options.head_name = xstrdup(buf.buf);
/* If not is it a valid ref (branch or commit)? */ /* If not is it a valid ref (branch or commit)? */
} else if (!get_oid(branch_name, &options.orig_head) && } else {
lookup_commit_reference(the_repository, struct commit *commit =
&options.orig_head)) lookup_commit_reference_by_name(branch_name);
if (!commit)
die(_("no such branch/commit '%s'"),
branch_name);
oidcpy(&options.orig_head, &commit->object.oid);
options.head_name = NULL; options.head_name = NULL;
else }
die(_("no such branch/commit '%s'"),
branch_name);
} else if (argc == 0) { } else if (argc == 0) {
/* Do not need to switch branches, we are already on it. */ /* Do not need to switch branches, we are already on it. */
options.head_name = options.head_name =
@ -1965,7 +1958,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (require_clean_work_tree(the_repository, "rebase", if (require_clean_work_tree(the_repository, "rebase",
_("Please commit or stash them."), 1, 1)) { _("Please commit or stash them."), 1, 1)) {
ret = 1; ret = -1;
goto cleanup; goto cleanup;
} }
@ -2000,7 +1993,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
RESET_HEAD_RUN_POST_CHECKOUT_HOOK, RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
NULL, buf.buf, NULL, buf.buf,
DEFAULT_REFLOG_ACTION) < 0) { DEFAULT_REFLOG_ACTION) < 0) {
ret = !!error(_("could not switch to " ret = error(_("could not switch to "
"%s"), "%s"),
options.switch_to); options.switch_to);
goto cleanup; goto cleanup;
@ -2015,7 +2008,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
else else
printf(_("Current branch %s is up to date.\n"), printf(_("Current branch %s is up to date.\n"),
branch_name); branch_name);
ret = !!finish_rebase(&options); ret = finish_rebase(&options);
goto cleanup; goto cleanup;
} else if (!(options.flags & REBASE_NO_QUIET)) } else if (!(options.flags & REBASE_NO_QUIET))
; /* be quiet */ ; /* be quiet */
@ -2093,7 +2086,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
RESET_HEAD_REFS_ONLY, "HEAD", msg.buf, RESET_HEAD_REFS_ONLY, "HEAD", msg.buf,
DEFAULT_REFLOG_ACTION); DEFAULT_REFLOG_ACTION);
strbuf_release(&msg); strbuf_release(&msg);
ret = !!finish_rebase(&options); ret = finish_rebase(&options);
goto cleanup; goto cleanup;
} }
@ -2107,7 +2100,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.revisions = revisions.buf; options.revisions = revisions.buf;
run_rebase: run_rebase:
ret = !!run_specific_rebase(&options, action); ret = run_specific_rebase(&options, action);
cleanup: cleanup:
strbuf_release(&buf); strbuf_release(&buf);
@ -2118,5 +2111,5 @@ cleanup:
free(options.strategy); free(options.strategy);
strbuf_release(&options.git_format_patch_opt); strbuf_release(&options.git_format_patch_opt);
free(squash_onto_name); free(squash_onto_name);
return ret; return !!ret;
} }

View File

@ -7,77 +7,77 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh . ./test-lib.sh
### Test that we handle space characters properly
work_dir="$(pwd)/test dir"
test_expect_success setup ' test_expect_success setup '
mkdir -p "$work_dir" && test_commit a a a &&
cd "$work_dir" &&
git init &&
echo a > a &&
git add a &&
git commit -m a &&
git branch to-rebase && git branch to-rebase &&
echo b > a && test_commit --annotate b a b &&
git commit -a -m b && test_commit --annotate c a c &&
echo c > a &&
git commit -a -m c &&
git checkout to-rebase && git checkout to-rebase &&
echo d > a && test_commit "merge should fail on this" a d d &&
git commit -a -m "merge should fail on this" && test_commit --annotate "merge should fail on this, too" a e pre-rebase
echo e > a &&
git commit -a -m "merge should fail on this, too" &&
git branch pre-rebase
' '
# Check that HEAD is equal to "pre-rebase" and the current branch is
# "to-rebase"
check_head() {
test_cmp_rev HEAD pre-rebase^{commit} &&
test "$(git symbolic-ref HEAD)" = refs/heads/to-rebase
}
testrebase() { testrebase() {
type=$1 type=$1
dotest=$2 state_dir=$2
test_expect_success "rebase$type --abort" ' test_expect_success "rebase$type --abort" '
cd "$work_dir" &&
# Clean up the state from the previous one # Clean up the state from the previous one
git reset --hard pre-rebase && git reset --hard pre-rebase &&
test_must_fail git rebase$type main && test_must_fail git rebase$type main &&
test_path_is_dir "$dotest" && test_path_is_dir "$state_dir" &&
git rebase --abort && git rebase --abort &&
test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && check_head &&
test ! -d "$dotest" test_path_is_missing "$state_dir"
' '
test_expect_success "rebase$type --abort after --skip" ' test_expect_success "rebase$type --abort after --skip" '
cd "$work_dir" &&
# Clean up the state from the previous one # Clean up the state from the previous one
git reset --hard pre-rebase && git reset --hard pre-rebase &&
test_must_fail git rebase$type main && test_must_fail git rebase$type main &&
test_path_is_dir "$dotest" && test_path_is_dir "$state_dir" &&
test_must_fail git rebase --skip && test_must_fail git rebase --skip &&
test $(git rev-parse HEAD) = $(git rev-parse main) && test_cmp_rev HEAD main &&
git rebase --abort && git rebase --abort &&
test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && check_head &&
test ! -d "$dotest" test_path_is_missing "$state_dir"
' '
test_expect_success "rebase$type --abort after --continue" ' test_expect_success "rebase$type --abort after --continue" '
cd "$work_dir" &&
# Clean up the state from the previous one # Clean up the state from the previous one
git reset --hard pre-rebase && git reset --hard pre-rebase &&
test_must_fail git rebase$type main && test_must_fail git rebase$type main &&
test_path_is_dir "$dotest" && test_path_is_dir "$state_dir" &&
echo c > a && echo c > a &&
echo d >> a && echo d >> a &&
git add a && git add a &&
test_must_fail git rebase --continue && test_must_fail git rebase --continue &&
test $(git rev-parse HEAD) != $(git rev-parse main) && test_cmp_rev ! HEAD main &&
git rebase --abort && git rebase --abort &&
test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && check_head &&
test ! -d "$dotest" test_path_is_missing "$state_dir"
'
test_expect_success "rebase$type --abort when checking out a tag" '
test_when_finished "git symbolic-ref HEAD refs/heads/to-rebase" &&
git reset --hard a -- &&
test_must_fail git rebase$type --onto b c pre-rebase &&
test_cmp_rev HEAD b^{commit} &&
git rebase --abort &&
test_cmp_rev HEAD pre-rebase^{commit} &&
! git symbolic-ref HEAD
' '
test_expect_success "rebase$type --abort does not update reflog" ' test_expect_success "rebase$type --abort does not update reflog" '
cd "$work_dir" &&
# Clean up the state from the previous one # Clean up the state from the previous one
git reset --hard pre-rebase && git reset --hard pre-rebase &&
git reflog show to-rebase > reflog_before && git reflog show to-rebase > reflog_before &&
@ -89,7 +89,6 @@ testrebase() {
' '
test_expect_success 'rebase --abort can not be used with other options' ' test_expect_success 'rebase --abort can not be used with other options' '
cd "$work_dir" &&
# Clean up the state from the previous one # Clean up the state from the previous one
git reset --hard pre-rebase && git reset --hard pre-rebase &&
test_must_fail git rebase$type main && test_must_fail git rebase$type main &&
@ -97,33 +96,21 @@ testrebase() {
test_must_fail git rebase --abort -v && test_must_fail git rebase --abort -v &&
git rebase --abort git rebase --abort
' '
test_expect_success "rebase$type --quit" '
test_when_finished "git symbolic-ref HEAD refs/heads/to-rebase" &&
# Clean up the state from the previous one
git reset --hard pre-rebase &&
test_must_fail git rebase$type main &&
test_path_is_dir $state_dir &&
head_before=$(git rev-parse HEAD) &&
git rebase --quit &&
test_cmp_rev HEAD $head_before &&
test_path_is_missing .git/rebase-apply
'
} }
testrebase " --apply" .git/rebase-apply testrebase " --apply" .git/rebase-apply
testrebase " --merge" .git/rebase-merge testrebase " --merge" .git/rebase-merge
test_expect_success 'rebase --apply --quit' '
cd "$work_dir" &&
# Clean up the state from the previous one
git reset --hard pre-rebase &&
test_must_fail git rebase --apply main &&
test_path_is_dir .git/rebase-apply &&
head_before=$(git rev-parse HEAD) &&
git rebase --quit &&
test $(git rev-parse HEAD) = $head_before &&
test ! -d .git/rebase-apply
'
test_expect_success 'rebase --merge --quit' '
cd "$work_dir" &&
# Clean up the state from the previous one
git reset --hard pre-rebase &&
test_must_fail git rebase --merge main &&
test_path_is_dir .git/rebase-merge &&
head_before=$(git rev-parse HEAD) &&
git rebase --quit &&
test $(git rev-parse HEAD) = $head_before &&
test ! -d .git/rebase-merge
'
test_done test_done