Merge branch 'pw/rebase-abort-clean-rewritten' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 29 Jul 2019 19:38:20 +0000 (12:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 29 Jul 2019 19:38:20 +0000 (12:38 -0700)
"git rebase --abort" used to leave refs/rewritten/ when concluding
"git rebase -r", which has been corrected.

* pw/rebase-abort-clean-rewritten:
rebase --abort/--quit: cleanup refs/rewritten
sequencer: return errors from sequencer_remove_state()
rebase: warn if state directory cannot be removed
rebase: fix a memory leak

builtin/rebase.c
sequencer.c
t/t3430-rebase-merges.sh
index b6892bc77120b44fc33f9899b928ca4fbf84abe7..3d6219d0223e78218f400bd1f0504e62c2058070 100644 (file)
@@ -738,6 +738,7 @@ static int finish_rebase(struct rebase_options *opts)
 {
        struct strbuf dir = STRBUF_INIT;
        const char *argv_gc_auto[] = { "gc", "--auto", NULL };
+       int ret = 0;
 
        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
        apply_autostash(opts);
@@ -747,11 +748,20 @@ static int finish_rebase(struct rebase_options *opts)
         * user should see them.
         */
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
-       strbuf_addstr(&dir, opts->state_dir);
-       remove_dir_recursively(&dir, 0);
-       strbuf_release(&dir);
+       if (opts->type == REBASE_INTERACTIVE) {
+               struct replay_opts replay = REPLAY_OPTS_INIT;
 
-       return 0;
+               replay.action = REPLAY_INTERACTIVE_REBASE;
+               ret = sequencer_remove_state(&replay);
+       } else {
+               strbuf_addstr(&dir, opts->state_dir);
+               if (remove_dir_recursively(&dir, 0))
+                       ret = error(_("could not remove '%s'"),
+                                   opts->state_dir);
+               strbuf_release(&dir);
+       }
+
+       return ret;
 }
 
 static struct commit *peel_committish(const char *name)
@@ -1627,15 +1637,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        die(_("could not move back to %s"),
                            oid_to_hex(&options.orig_head));
                remove_branch_state(the_repository);
-               ret = finish_rebase(&options);
+               ret = !!finish_rebase(&options);
                goto cleanup;
        }
        case ACTION_QUIT: {
-               strbuf_reset(&buf);
-               strbuf_addstr(&buf, options.state_dir);
-               ret = !!remove_dir_recursively(&buf, 0);
-               if (ret)
-                       die(_("could not remove '%s'"), options.state_dir);
+               if (options.type == REBASE_INTERACTIVE) {
+                       struct replay_opts replay = REPLAY_OPTS_INIT;
+
+                       replay.action = REPLAY_INTERACTIVE_REBASE;
+                       ret = !!sequencer_remove_state(&replay);
+               } else {
+                       strbuf_reset(&buf);
+                       strbuf_addstr(&buf, options.state_dir);
+                       ret = !!remove_dir_recursively(&buf, 0);
+                       if (ret)
+                               error(_("could not remove '%s'"),
+                                      options.state_dir);
+               }
                goto cleanup;
        }
        case ACTION_EDIT_TODO:
@@ -2150,6 +2168,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        ret = !!run_specific_rebase(&options, action);
 
 cleanup:
+       strbuf_release(&buf);
        strbuf_release(&revisions);
        free(options.head_name);
        free(options.gpg_sign_opt);
index 63b09cfceb5d3d4c685bebad6dcc24fe1d72bc61..1d206fd22456cce12f7496321df8a47fcb94db9e 100644 (file)
@@ -279,7 +279,7 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
 int sequencer_remove_state(struct replay_opts *opts)
 {
        struct strbuf buf = STRBUF_INIT;
-       int i;
+       int i, ret = 0;
 
        if (is_rebase_i(opts) &&
            strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) {
@@ -288,8 +288,10 @@ int sequencer_remove_state(struct replay_opts *opts)
                        char *eol = strchr(p, '\n');
                        if (eol)
                                *eol = '\0';
-                       if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0)
+                       if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0) {
                                warning(_("could not delete '%s'"), p);
+                               ret = -1;
+                       }
                        if (!eol)
                                break;
                        p = eol + 1;
@@ -305,10 +307,11 @@ int sequencer_remove_state(struct replay_opts *opts)
 
        strbuf_reset(&buf);
        strbuf_addstr(&buf, get_dir(opts));
-       remove_dir_recursively(&buf, 0);
+       if (remove_dir_recursively(&buf, 0))
+               ret = error(_("could not remove '%s'"), buf.buf);
        strbuf_release(&buf);
 
-       return 0;
+       return ret;
 }
 
 static const char *action_name(const struct replay_opts *opts)
index 42ba5b9f0981b2b7ce98e1c5c55012ef61757bab..f0814d5280c6755ad1f9f8378a6a32d32ffaee1d 100755 (executable)
@@ -224,8 +224,24 @@ test_expect_success 'refs/rewritten/* is worktree-local' '
        test_cmp_rev HEAD "$(cat wt/b)"
 '
 
+test_expect_success '--abort cleans up refs/rewritten' '
+       git checkout -b abort-cleans-refs-rewritten H &&
+       GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ &&
+       git rev-parse --verify refs/rewritten/onto &&
+       git rebase --abort &&
+       test_must_fail git rev-parse --verify refs/rewritten/onto
+'
+
+test_expect_success '--quit cleans up refs/rewritten' '
+       git checkout -b quit-cleans-refs-rewritten H &&
+       GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ &&
+       git rev-parse --verify refs/rewritten/onto &&
+       git rebase --quit &&
+       test_must_fail git rev-parse --verify refs/rewritten/onto
+'
+
 test_expect_success 'post-rewrite hook and fixups work for merges' '
-       git checkout -b post-rewrite &&
+       git checkout -b post-rewrite &&
        test_commit same1 &&
        git reset --hard HEAD^ &&
        test_commit same2 &&