rebase: introduce a dedicated backend for --preserve-merges
[gitweb.git] / sequencer.c
index 8eddda681d14a102ee95f33c60c38aa42f16264c..01e561bc20ec39587c6b4852c3deff9beb20a3f4 100644 (file)
@@ -2747,18 +2747,34 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)
        if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
                return -1;
 
-       /* Determine the length of the label */
-       for (i = 0; i < len; i++)
-               if (isspace(name[i]))
-                       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)) {
-               error(_("could not read '%s'"), ref_name.buf);
-               rollback_lock_file(&lock);
-               strbuf_release(&ref_name);
-               return -1;
+       if (len == 10 && !strncmp("[new root]", name, len)) {
+               if (!opts->have_squash_onto) {
+                       const char *hex;
+                       if (commit_tree("", 0, the_hash_algo->empty_tree,
+                                       NULL, &opts->squash_onto,
+                                       NULL, NULL))
+                               return error(_("writing fake root commit"));
+                       opts->have_squash_onto = 1;
+                       hex = oid_to_hex(&opts->squash_onto);
+                       if (write_message(hex, strlen(hex),
+                                         rebase_path_squash_onto(), 0))
+                               return error(_("writing squash-onto"));
+               }
+               oidcpy(&oid, &opts->squash_onto);
+       } else {
+               /* Determine the length of the label */
+               for (i = 0; i < len; i++)
+                       if (isspace(name[i]))
+                               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)) {
+                       error(_("could not read '%s'"), ref_name.buf);
+                       rollback_lock_file(&lock);
+                       strbuf_release(&ref_name);
+                       return -1;
+               }
        }
 
        memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
@@ -2854,6 +2870,18 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
                goto leave_merge;
        }
 
+       if (opts->have_squash_onto &&
+           !oidcmp(&head_commit->object.oid, &opts->squash_onto)) {
+               /*
+                * When the user tells us to "merge" something into a
+                * "[new root]", let's simply fast-forward to the merge head.
+                */
+               rollback_lock_file(&lock);
+               ret = fast_forward_to(&merge_commit->object.oid,
+                                      &head_commit->object.oid, 0, opts);
+               goto leave_merge;
+       }
+
        if (commit) {
                const char *message = get_commit_buffer(commit, NULL);
                const char *body;
@@ -3875,7 +3903,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                }
 
                if (!commit)
-                       fprintf(out, "%s onto\n", cmd_reset);
+                       fprintf(out, "%s %s\n", cmd_reset,
+                               rebase_cousins ? "onto" : "[new root]");
                else {
                        const char *to = NULL;