Skip to content

Commit 7740ac6

Browse files
phillipwoodgitster
authored andcommitted
rebase: dereference tags
A rebase started with 'git rebase <A> <B>' is conceptually to first checkout <B> and run 'git rebase <A>' starting from that state. 'git rebase --abort' in the middle of such a rebase should take us back to the state we checked out <B>. This used to work, even when <B> is a tag that points at a commit, until Git 2.20.0 when the command was reimplemented in C. The command now complains that the tag object itself cannot be checked out, which may be technically correct but is not what the user asked to do. Fix this old regression by using lookup_commit_reference_by_name() when parsing <B>. The scripted version did not need to peel the tag because the commands it passed the tag to (e.g 'git reset') peeled the tag themselves. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 1d18826 commit 7740ac6

File tree

2 files changed

+22
-10
lines changed

2 files changed

+22
-10
lines changed

builtin/rebase.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,13 +1905,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
19051905
die_if_checked_out(buf.buf, 1);
19061906
options.head_name = xstrdup(buf.buf);
19071907
/* If not is it a valid ref (branch or commit)? */
1908-
} else if (!get_oid(branch_name, &options.orig_head) &&
1909-
lookup_commit_reference(the_repository,
1910-
&options.orig_head))
1908+
} else {
1909+
struct commit *commit =
1910+
lookup_commit_reference_by_name(branch_name);
1911+
if (!commit)
1912+
die(_("no such branch/commit '%s'"),
1913+
branch_name);
1914+
oidcpy(&options.orig_head, &commit->object.oid);
19111915
options.head_name = NULL;
1912-
else
1913-
die(_("no such branch/commit '%s'"),
1914-
branch_name);
1916+
}
19151917
} else if (argc == 0) {
19161918
/* Do not need to switch branches, we are already on it. */
19171919
options.head_name =

t/t3407-rebase-abort.sh

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ test_expect_success setup '
1111
test_commit a a a &&
1212
git branch to-rebase &&
1313
14-
test_commit b a b &&
15-
test_commit c a c &&
14+
test_commit --annotate b a b &&
15+
test_commit --annotate c a c &&
1616
1717
git checkout to-rebase &&
1818
test_commit "merge should fail on this" a d d &&
19-
test_commit "merge should fail on this, too" a e pre-rebase
19+
test_commit --annotate "merge should fail on this, too" a e pre-rebase
2020
'
2121

2222
# Check that HEAD is equal to "pre-rebase" and the current branch is
2323
# "to-rebase"
2424
check_head() {
25-
test_cmp_rev HEAD pre-rebase &&
25+
test_cmp_rev HEAD pre-rebase^{commit} &&
2626
test "$(git symbolic-ref HEAD)" = refs/heads/to-rebase
2727
}
2828

@@ -67,6 +67,16 @@ testrebase() {
6767
test_path_is_missing "$state_dir"
6868
'
6969

70+
test_expect_success "rebase$type --abort when checking out a tag" '
71+
test_when_finished "git symbolic-ref HEAD refs/heads/to-rebase" &&
72+
git reset --hard a -- &&
73+
test_must_fail git rebase$type --onto b c pre-rebase &&
74+
test_cmp_rev HEAD b^{commit} &&
75+
git rebase --abort &&
76+
test_cmp_rev HEAD pre-rebase^{commit} &&
77+
! git symbolic-ref HEAD
78+
'
79+
7080
test_expect_success "rebase$type --abort does not update reflog" '
7181
# Clean up the state from the previous one
7282
git reset --hard pre-rebase &&

0 commit comments

Comments
 (0)