return 1;
}
-static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
- struct object_id *merge_base)
+static int can_fast_forward(struct commit *onto, struct commit *upstream,
+ struct object_id *head_oid, struct object_id *merge_base)
{
struct commit *head = lookup_commit(the_repository, head_oid);
- struct commit_list *merge_bases;
- int res;
+ struct commit_list *merge_bases = NULL;
+ int res = 0;
if (!head)
- return 0;
+ goto done;
merge_bases = get_merge_bases(onto, head);
- if (merge_bases && !merge_bases->next) {
- oidcpy(merge_base, &merge_bases->item->object.oid);
- res = oideq(merge_base, &onto->object.oid);
- } else {
+ if (!merge_bases || merge_bases->next) {
oidcpy(merge_base, &null_oid);
- res = 0;
+ goto done;
}
+
+ oidcpy(merge_base, &merge_bases->item->object.oid);
+ if (!oideq(merge_base, &onto->object.oid))
+ goto done;
+
+ if (!upstream)
+ goto done;
+
+ free_commit_list(merge_bases);
+ merge_bases = get_merge_bases(upstream, head);
+ if (!merge_bases || merge_bases->next)
+ goto done;
+
+ if (!oideq(&onto->object.oid, &merge_bases->item->object.oid))
+ goto done;
+
+ res = 1;
+
+done:
free_commit_list(merge_bases);
return res && is_linear_history(onto, head);
}
usage_with_options(builtin_rebase_usage,
builtin_rebase_options);
- prefix = setup_git_directory();
- trace_repo_setup(prefix);
- setup_work_tree();
-
options.allow_empty_message = 1;
git_config(rebase_config, &options);
/*
* Check if we are already based on onto with linear history,
- * but this should be done only when upstream and onto are the same
- * and if this is not an interactive rebase.
+ * in which case we could fast-forward without replacing the commits
+ * with new commits recreated by replaying their changes. This
+ * optimization must not be done if this is an interactive rebase.
*/
- if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
- !is_interactive(&options) && !options.restrict_revision &&
- options.upstream &&
- !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
+ if (can_fast_forward(options.onto, options.upstream, &options.orig_head,
+ &merge_base) &&
+ !is_interactive(&options) && !options.restrict_revision) {
int flag;
if (!(options.flags & REBASE_FORCE)) {
strbuf_addf(&msg, "%s: checkout %s",
getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
if (reset_head(&options.onto->object.oid, "checkout", NULL,
- RESET_HEAD_DETACH | RESET_ORIG_HEAD |
+ RESET_HEAD_DETACH | RESET_ORIG_HEAD |
RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
NULL, msg.buf))
die(_("Could not detach HEAD"));