Skip to content

Commit f21becd

Browse files
phillipwoodgitster
authored andcommitted
rebase: store orig_head as a commit
Using a struct commit rather than a struct oid to hold orig_head means that we error out straight away if the branch being rebased does not point to a commit. It also simplifies the code that handles finding the merge base and fork point as it no longer has to convert from an oid to a commit. To avoid changing the behavior of "git rebase <upstream> <branch>" we keep the existing call to read_ref() and use lookup_commit_object() on the oid returned by that rather than calling lookup_commit_reference_by_name() which applies the ref dwim rules to its argument. Helped-by: Junio C Hamano <[email protected]> Signed-off-by: Phillip Wood <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b8dbfd0 commit f21becd

File tree

1 file changed

+31
-35
lines changed

1 file changed

+31
-35
lines changed

builtin/rebase.c

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ struct rebase_options {
6868
const char *upstream_name;
6969
const char *upstream_arg;
7070
char *head_name;
71-
struct object_id orig_head;
71+
struct commit *orig_head;
7272
struct commit *onto;
7373
const char *onto_name;
7474
const char *revisions;
@@ -260,13 +260,13 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
260260
struct replay_opts replay = get_replay_opts(opts);
261261
struct string_list commands = STRING_LIST_INIT_DUP;
262262

263-
if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head,
263+
if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head->object.oid,
264264
&revisions, &shortrevisions))
265265
return -1;
266266

267267
if (init_basic_state(&replay,
268268
opts->head_name ? opts->head_name : "detached HEAD",
269-
opts->onto, &opts->orig_head)) {
269+
opts->onto, &opts->orig_head->object.oid)) {
270270
free(revisions);
271271
free(shortrevisions);
272272

@@ -297,8 +297,8 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
297297
split_exec_commands(opts->cmd, &commands);
298298
ret = complete_action(the_repository, &replay, flags,
299299
shortrevisions, opts->onto_name, opts->onto,
300-
&opts->orig_head, &commands, opts->autosquash,
301-
&todo_list);
300+
&opts->orig_head->object.oid, &commands,
301+
opts->autosquash, &todo_list);
302302
}
303303

304304
string_list_clear(&commands, 0);
@@ -446,7 +446,8 @@ static int read_basic_state(struct rebase_options *opts)
446446
} else if (!read_oneliner(&buf, state_dir_path("head", opts),
447447
READ_ONELINER_WARN_MISSING))
448448
return -1;
449-
if (get_oid_hex(buf.buf, &opts->orig_head))
449+
if (get_oid_hex(buf.buf, &oid) ||
450+
!(opts->orig_head = lookup_commit_object(the_repository, &oid)))
450451
return error(_("invalid orig-head: '%s'"), buf.buf);
451452

452453
if (file_exists(state_dir_path("quiet", opts)))
@@ -515,7 +516,7 @@ static int rebase_write_basic_state(struct rebase_options *opts)
515516
write_file(state_dir_path("onto", opts), "%s",
516517
opts->onto ? oid_to_hex(&opts->onto->object.oid) : "");
517518
write_file(state_dir_path("orig-head", opts), "%s",
518-
oid_to_hex(&opts->orig_head));
519+
oid_to_hex(&opts->orig_head->object.oid));
519520
if (!(opts->flags & REBASE_NO_QUIET))
520521
write_file(state_dir_path("quiet", opts), "%s", "");
521522
if (opts->flags & REBASE_VERBOSE)
@@ -644,7 +645,7 @@ static int run_am(struct rebase_options *opts)
644645
/* this is now equivalent to !opts->upstream */
645646
&opts->onto->object.oid :
646647
&opts->upstream->object.oid),
647-
oid_to_hex(&opts->orig_head));
648+
oid_to_hex(&opts->orig_head->object.oid));
648649

649650
rebased_patches = xstrdup(git_path("rebased-patches"));
650651
format_patch.out = open(rebased_patches,
@@ -678,7 +679,7 @@ static int run_am(struct rebase_options *opts)
678679
free(rebased_patches);
679680
strvec_clear(&am.args);
680681

681-
ropts.oid = &opts->orig_head;
682+
ropts.oid = &opts->orig_head->object.oid;
682683
ropts.branch = opts->head_name;
683684
ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
684685
reset_head(the_repository, &ropts);
@@ -826,7 +827,7 @@ static int checkout_up_to_date(struct rebase_options *options)
826827
strbuf_addf(&buf, "%s: checkout %s",
827828
getenv(GIT_REFLOG_ACTION_ENVIRONMENT),
828829
options->switch_to);
829-
ropts.oid = &options->orig_head;
830+
ropts.oid = &options->orig_head->object.oid;
830831
ropts.branch = options->head_name;
831832
ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
832833
if (!ropts.branch)
@@ -859,15 +860,11 @@ static int is_linear_history(struct commit *from, struct commit *to)
859860

860861
static int can_fast_forward(struct commit *onto, struct commit *upstream,
861862
struct commit *restrict_revision,
862-
struct object_id *head_oid, struct object_id *merge_base)
863+
struct commit *head, struct object_id *merge_base)
863864
{
864-
struct commit *head = lookup_commit(the_repository, head_oid);
865865
struct commit_list *merge_bases = NULL;
866866
int res = 0;
867867

868-
if (!head)
869-
goto done;
870-
871868
merge_bases = get_merge_bases(onto, head);
872869
if (!merge_bases || merge_bases->next) {
873870
oidcpy(merge_base, null_oid());
@@ -1302,13 +1299,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
13021299

13031300
if (read_basic_state(&options))
13041301
exit(1);
1305-
ropts.oid = &options.orig_head;
1302+
ropts.oid = &options.orig_head->object.oid;
13061303
ropts.branch = options.head_name;
13071304
ropts.flags = RESET_HEAD_HARD;
13081305
ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
13091306
if (reset_head(the_repository, &ropts) < 0)
13101307
die(_("could not move back to %s"),
1311-
oid_to_hex(&options.orig_head));
1308+
oid_to_hex(&options.orig_head->object.oid));
13121309
remove_branch_state(the_repository, 0);
13131310
ret = finish_rebase(&options);
13141311
goto cleanup;
@@ -1594,25 +1591,27 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
15941591
*/
15951592
if (argc == 1) {
15961593
/* Is it "rebase other branchname" or "rebase other commit"? */
1594+
struct object_id branch_oid;
15971595
branch_name = argv[0];
15981596
options.switch_to = argv[0];
15991597

16001598
/* Is it a local branch? */
16011599
strbuf_reset(&buf);
16021600
strbuf_addf(&buf, "refs/heads/%s", branch_name);
1603-
if (!read_ref(buf.buf, &options.orig_head)) {
1601+
if (!read_ref(buf.buf, &branch_oid)) {
16041602
die_if_checked_out(buf.buf, 1);
16051603
options.head_name = xstrdup(buf.buf);
1604+
options.orig_head =
1605+
lookup_commit_object(the_repository,
1606+
&branch_oid);
16061607
/* If not is it a valid ref (branch or commit)? */
16071608
} else {
1608-
struct commit *commit =
1609+
options.orig_head =
16091610
lookup_commit_reference_by_name(branch_name);
1610-
if (!commit)
1611-
die(_("no such branch/commit '%s'"),
1612-
branch_name);
1613-
oidcpy(&options.orig_head, &commit->object.oid);
16141611
options.head_name = NULL;
16151612
}
1613+
if (!options.orig_head)
1614+
die(_("no such branch/commit '%s'"), branch_name);
16161615
} else if (argc == 0) {
16171616
/* Do not need to switch branches, we are already on it. */
16181617
options.head_name =
@@ -1629,8 +1628,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
16291628
FREE_AND_NULL(options.head_name);
16301629
branch_name = "HEAD";
16311630
}
1632-
if (get_oid("HEAD", &options.orig_head))
1633-
die(_("Could not resolve HEAD to a revision"));
1631+
options.orig_head = lookup_commit_reference_by_name("HEAD");
1632+
if (!options.orig_head)
1633+
die(_("Could not resolve HEAD to a commit"));
16341634
} else
16351635
BUG("unexpected number of arguments left to parse");
16361636

@@ -1662,13 +1662,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
16621662
options.onto_name);
16631663
}
16641664

1665-
if (options.fork_point > 0) {
1666-
struct commit *head =
1667-
lookup_commit_reference(the_repository,
1668-
&options.orig_head);
1665+
if (options.fork_point > 0)
16691666
options.restrict_revision =
1670-
get_fork_point(options.upstream_name, head);
1671-
}
1667+
get_fork_point(options.upstream_name, options.orig_head);
16721668

16731669
if (repo_read_index(the_repository) < 0)
16741670
die(_("could not read index"));
@@ -1698,7 +1694,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
16981694
* call it before checking allow_preemptive_ff.
16991695
*/
17001696
if (can_fast_forward(options.onto, options.upstream, options.restrict_revision,
1701-
&options.orig_head, &merge_base) &&
1697+
options.orig_head, &merge_base) &&
17021698
allow_preemptive_ff) {
17031699
int flag;
17041700

@@ -1775,7 +1771,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
17751771
strbuf_addf(&msg, "%s: checkout %s",
17761772
getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
17771773
ropts.oid = &options.onto->object.oid;
1778-
ropts.orig_head = &options.orig_head,
1774+
ropts.orig_head = &options.orig_head->object.oid,
17791775
ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD |
17801776
RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
17811777
ropts.head_msg = msg.buf;
@@ -1789,7 +1785,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
17891785
* we just fast-forwarded.
17901786
*/
17911787
strbuf_reset(&msg);
1792-
if (oideq(&merge_base, &options.orig_head)) {
1788+
if (oideq(&merge_base, &options.orig_head->object.oid)) {
17931789
printf(_("Fast-forwarded %s to %s.\n"),
17941790
branch_name, options.onto_name);
17951791
strbuf_addf(&msg, "rebase finished: %s onto %s",
@@ -1810,7 +1806,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
18101806
(options.restrict_revision ?
18111807
oid_to_hex(&options.restrict_revision->object.oid) :
18121808
oid_to_hex(&options.upstream->object.oid)),
1813-
oid_to_hex(&options.orig_head));
1809+
oid_to_hex(&options.orig_head->object.oid));
18141810

18151811
options.revisions = revisions.buf;
18161812

0 commit comments

Comments
 (0)