builtin rebase: support `--autostash` option

To support `--autostash` we introduce a function `apply_autostash()` just like in `git-legacy-rebase.sh`. Rather than refactoring and using the same function that exists in `sequencer.c`, we go a different route here, to avoid clashes with the sister GSoC project that turns the interactive rebase into a builtin. 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 6defce2b02909b8e0fcf1ffeecee743688b97b49
1 file changed +109 -8
builtin/rebase.c
+109 -8
@@ -63,12 +63,6 @@ static int use_builtin_rebase(void)
63 return ret;
64 }
65
66 -static int apply_autostash(void)
67 -{
68 - warning("TODO");
69 - return 0;
70 -}
71 -
66 struct rebase_options {
67 enum rebase_type type;
68 const char *state_dir;
@@ -98,6 +92,7 @@ struct rebase_options {
92 int keep_empty;
93 int autosquash;
94 char *gpg_sign_opt;
95 + int autostash;
96 };
97
98 static int is_interactive(struct rebase_options *opts)
@@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)
219 return 0;
220 }
221
222 +static int apply_autostash(struct rebase_options *opts)
223 +{
224 + const char *path = state_dir_path("autostash", opts);
225 + struct strbuf autostash = STRBUF_INIT;
226 + struct child_process stash_apply = CHILD_PROCESS_INIT;
227 +
228 + if (!file_exists(path))
229 + return 0;
230 +
231 + if (read_one(state_dir_path("autostash", opts), &autostash))
232 + return error(_("Could not read '%s'"), path);
233 + argv_array_pushl(&stash_apply.args,
234 + "stash", "apply", autostash.buf, NULL);
235 + stash_apply.git_cmd = 1;
236 + stash_apply.no_stderr = stash_apply.no_stdout =
237 + stash_apply.no_stdin = 1;
238 + if (!run_command(&stash_apply))
239 + printf(_("Applied autostash.\n"));
240 + else {
241 + struct argv_array args = ARGV_ARRAY_INIT;
242 + int res = 0;
243 +
244 + argv_array_pushl(&args,
245 + "stash", "store", "-m", "autostash", "-q",
246 + autostash.buf, NULL);
247 + if (run_command_v_opt(args.argv, RUN_GIT_CMD))
248 + res = error(_("Cannot store %s"), autostash.buf);
249 + argv_array_clear(&args);
250 + strbuf_release(&autostash);
251 + if (res)
252 + return res;
253 +
254 + fprintf(stderr,
255 + _("Applying autostash resulted in conflicts.\n"
256 + "Your changes are safe in the stash.\n"
257 + "You can run \"git stash pop\" or \"git stash drop\" "
258 + "at any time.\n"));
259 + }
260 +
261 + strbuf_release(&autostash);
262 + return 0;
263 +}
264 +
265 static int finish_rebase(struct rebase_options *opts)
266 {
267 struct strbuf dir = STRBUF_INIT;
268 const char *argv_gc_auto[] = { "gc", "--auto", NULL };
269
270 delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
233 - apply_autostash();
271 + apply_autostash(opts);
272 close_all_packs(the_repository->objects);
273 /*
274 * We ignore errors in 'gc --auto', since the
@@ -345,7 +383,7 @@ static int run_specific_rebase(struct rebase_options *opts)
383 } else if (status == 2) {
384 struct strbuf dir = STRBUF_INIT;
385
348 - apply_autostash();
386 + apply_autostash(opts);
387 strbuf_addstr(&dir, opts->state_dir);
388 remove_dir_recursively(&dir, 0);
389 strbuf_release(&dir);
@@ -480,6 +518,11 @@ static int rebase_config(const char *var, const char *value, void *data)
518 return 0;
519 }
520
521 + if (!strcmp(var, "rebase.autostash")) {
522 + opts->autostash = git_config_bool(var, value);
523 + return 0;
524 + }
525 +
526 return git_default_config(var, value, data);
527 }
528
@@ -647,6 +690,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
690 N_("whitespace"), N_("passed to 'git apply'")),
691 OPT_SET_INT('C', NULL, &opt_c, N_("passed to 'git apply'"),
692 REBASE_AM),
693 + OPT_BOOL(0, "autostash", &options.autostash,
694 + N_("automatically stash/stash pop before and after")),
695 OPT_END(),
696 };
697
@@ -976,6 +1021,62 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1021 if (read_index(the_repository->index) < 0)
1022 die(_("could not read index"));
1023
1024 + if (options.autostash) {
1025 + struct lock_file lock_file = LOCK_INIT;
1026 + int fd;
1027 +
1028 + fd = hold_locked_index(&lock_file, 0);
1029 + refresh_cache(REFRESH_QUIET);
1030 + if (0 <= fd)
1031 + update_index_if_able(&the_index, &lock_file);
1032 + rollback_lock_file(&lock_file);
1033 +
1034 + if (has_unstaged_changes(0) || has_uncommitted_changes(0)) {
1035 + const char *autostash =
1036 + state_dir_path("autostash", &options);
1037 + struct child_process stash = CHILD_PROCESS_INIT;
1038 + struct object_id oid;
1039 + struct commit *head =
1040 + lookup_commit_reference(the_repository,
1041 + &options.orig_head);
1042 +
1043 + argv_array_pushl(&stash.args,
1044 + "stash", "create", "autostash", NULL);
1045 + stash.git_cmd = 1;
1046 + stash.no_stdin = 1;
1047 + strbuf_reset(&buf);
1048 + if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
1049 + die(_("Cannot autostash"));
1050 + strbuf_trim_trailing_newline(&buf);
1051 + if (get_oid(buf.buf, &oid))
1052 + die(_("Unexpected stash response: '%s'"),
1053 + buf.buf);
1054 + strbuf_reset(&buf);
1055 + strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
1056 +
1057 + if (safe_create_leading_directories_const(autostash))
1058 + die(_("Could not create directory for '%s'"),
1059 + options.state_dir);
1060 + write_file(autostash, "%s", buf.buf);
1061 + printf(_("Created autostash: %s\n"), buf.buf);
1062 + if (reset_head(&head->object.oid, "reset --hard",
1063 + NULL, 0) < 0)
1064 + die(_("could not reset --hard"));
1065 + printf(_("HEAD is now at %s"),
1066 + find_unique_abbrev(&head->object.oid,
1067 + DEFAULT_ABBREV));
1068 + strbuf_reset(&buf);
1069 + pp_commit_easy(CMIT_FMT_ONELINE, head, &buf);
1070 + if (buf.len > 0)
1071 + printf(" %s", buf.buf);
1072 + putchar('\n');
1073 +
1074 + if (discard_index(the_repository->index) < 0 ||
1075 + read_index(the_repository->index) < 0)
1076 + die(_("could not read index"));
1077 + }
1078 + }
1079 +
1080 if (require_clean_work_tree("rebase",
1081 _("Please commit or stash them."), 1, 1)) {
1082 ret = 1;