builtin rebase: support --root

This option allows to rebase entire histories up to, and including, the root commit. The conversion from the shell script is straight-forward, apart from the fact that we do not have to write an empty tree in C. Signed-off-by: Pratik Karki <predatoramigo@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Pratik Karki committed Sep 4, 2018 at 15:00 UTC 9dba809a69a7cd2a60e73d1ccaea0812b72b2b79
1 file changed +29 -2
builtin/rebase.c
+29 -2
@@ -76,6 +76,7 @@ struct rebase_options {
76 const char *revisions;
77 const char *switch_to;
78 int root;
79 + struct object_id *squash_onto;
80 struct commit *restrict_revision;
81 int dont_finish_rebase;
82 enum {
@@ -375,6 +376,9 @@ static int run_specific_rebase(struct rebase_options *opts)
376 opts->rebase_cousins ? "t" : "");
377 add_var(&script_snippet, "strategy", opts->strategy);
378 add_var(&script_snippet, "strategy_opts", opts->strategy_opts);
379 + add_var(&script_snippet, "rebase_root", opts->root ? "t" : "");
380 + add_var(&script_snippet, "squash_onto",
381 + opts->squash_onto ? oid_to_hex(opts->squash_onto) : "");
382
383 switch (opts->type) {
384 case REBASE_AM:
@@ -653,6 +657,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
657 const char *rebase_merges = NULL;
658 int fork_point = -1;
659 struct string_list strategy_options = STRING_LIST_INIT_NODUP;
660 + struct object_id squash_onto;
661 + char *squash_onto_name = NULL;
662 struct option builtin_rebase_options[] = {
663 OPT_STRING(0, "onto", &options.onto_name,
664 N_("revision"),
@@ -744,6 +750,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
750 N_("option"),
751 N_("pass the argument through to the merge "
752 "strategy")),
753 + OPT_BOOL(0, "root", &options.root,
754 + N_("rebase all reachable commits up to the root(s)")),
755 OPT_END(),
756 };
757
@@ -1021,6 +1029,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1029 }
1030 }
1031
1032 + if (options.root && !options.onto_name)
1033 + imply_interactive(&options, "--root without --onto");
1034 +
1035 switch (options.type) {
1036 case REBASE_MERGE:
1037 case REBASE_INTERACTIVE:
@@ -1059,8 +1070,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1070 if (!options.upstream)
1071 die(_("invalid upstream '%s'"), options.upstream_name);
1072 options.upstream_arg = options.upstream_name;
1062 - } else
1063 - die("TODO: upstream for --root");
1073 + } else {
1074 + if (!options.onto_name) {
1075 + if (commit_tree("", 0, the_hash_algo->empty_tree, NULL,
1076 + &squash_onto, NULL, NULL) < 0)
1077 + die(_("Could not create new root commit"));
1078 + options.squash_onto = &squash_onto;
1079 + options.onto_name = squash_onto_name =
1080 + xstrdup(oid_to_hex(&squash_onto));
1081 + }
1082 + options.upstream_name = NULL;
1083 + options.upstream = NULL;
1084 + if (argc > 1)
1085 + usage_with_options(builtin_rebase_usage,
1086 + builtin_rebase_options);
1087 + options.upstream_arg = "--root";
1088 + }
1089
1090 /* Make sure the branch to rebase onto is valid. */
1091 if (!options.onto_name)
@@ -1208,6 +1233,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1233 */
1234 if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
1235 !is_interactive(&options) && !options.restrict_revision &&
1236 + options.upstream &&
1237 !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
1238 int flag;
1239
@@ -1312,5 +1338,6 @@ cleanup:
1338 free(options.head_name);
1339 free(options.gpg_sign_opt);
1340 free(options.cmd);
1341 + free(squash_onto_name);
1342 return ret;
1343 }