Skip to content

Commit 2b800ec

Browse files
committed
Merge branch 'pw/rebase-autostash-fix'
"git rebase --autostash" failed to resurrect the autostashed changes when the command gets aborted after giving back control asking for hlep in conflict resolution. * pw/rebase-autostash-fix: rebase: apply and cleanup autostash when rebase fails to start
2 parents 6531f31 + bf6ab08 commit 2b800ec

File tree

4 files changed

+81
-10
lines changed

4 files changed

+81
-10
lines changed

builtin/rebase.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,23 @@ static int rebase_write_basic_state(struct rebase_options *opts)
527527
return 0;
528528
}
529529

530+
static int cleanup_autostash(struct rebase_options *opts)
531+
{
532+
int ret;
533+
struct strbuf dir = STRBUF_INIT;
534+
const char *path = state_dir_path("autostash", opts);
535+
536+
if (!file_exists(path))
537+
return 0;
538+
ret = apply_autostash(path);
539+
strbuf_addstr(&dir, opts->state_dir);
540+
if (remove_dir_recursively(&dir, 0))
541+
ret = error_errno(_("could not remove '%s'"), opts->state_dir);
542+
strbuf_release(&dir);
543+
544+
return ret;
545+
}
546+
530547
static int finish_rebase(struct rebase_options *opts)
531548
{
532549
struct strbuf dir = STRBUF_INIT;
@@ -1727,7 +1744,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
17271744
if (require_clean_work_tree(the_repository, "rebase",
17281745
_("Please commit or stash them."), 1, 1)) {
17291746
ret = -1;
1730-
goto cleanup;
1747+
goto cleanup_autostash;
17311748
}
17321749

17331750
/*
@@ -1750,7 +1767,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
17501767
if (options.switch_to) {
17511768
ret = checkout_up_to_date(&options);
17521769
if (ret)
1753-
goto cleanup;
1770+
goto cleanup_autostash;
17541771
}
17551772

17561773
if (!(options.flags & REBASE_NO_QUIET))
@@ -1776,8 +1793,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
17761793
/* If a hook exists, give it a chance to interrupt*/
17771794
if (!ok_to_skip_pre_rebase &&
17781795
run_hooks_l(the_repository, "pre-rebase", options.upstream_arg,
1779-
argc ? argv[0] : NULL, NULL))
1780-
die(_("The pre-rebase hook refused to rebase."));
1796+
argc ? argv[0] : NULL, NULL)) {
1797+
ret = error(_("The pre-rebase hook refused to rebase."));
1798+
goto cleanup_autostash;
1799+
}
17811800

17821801
if (options.flags & REBASE_DIFFSTAT) {
17831802
struct diff_options opts;
@@ -1822,9 +1841,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
18221841
RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
18231842
ropts.head_msg = msg.buf;
18241843
ropts.default_reflog_action = options.reflog_action;
1825-
if (reset_head(the_repository, &ropts))
1826-
die(_("Could not detach HEAD"));
1827-
strbuf_release(&msg);
1844+
if (reset_head(the_repository, &ropts)) {
1845+
ret = error(_("Could not detach HEAD"));
1846+
goto cleanup_autostash;
1847+
}
18281848

18291849
/*
18301850
* If the onto is a proper descendant of the tip of the branch, then
@@ -1852,9 +1872,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
18521872

18531873
cleanup:
18541874
strbuf_release(&buf);
1875+
strbuf_release(&msg);
18551876
strbuf_release(&revisions);
18561877
rebase_options_release(&options);
18571878
free(squash_onto_name);
18581879
free(keep_base_onto_name);
18591880
return !!ret;
1881+
1882+
cleanup_autostash:
1883+
ret |= !!cleanup_autostash(&options);
1884+
goto cleanup;
18601885
}

t/t3400-rebase.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ test_expect_success 'Show verbose error when HEAD could not be detached' '
145145
test_when_finished "rm -f B" &&
146146
test_must_fail git rebase topic 2>output.err >output.out &&
147147
test_grep "The following untracked working tree files would be overwritten by checkout:" output.err &&
148-
test_grep B output.err
148+
test_grep B output.err &&
149+
test_must_fail git rebase --quit 2>err &&
150+
test_grep "no rebase in progress" err
149151
'
150152

151153
test_expect_success 'fail when upstream arg is missing and not on branch' '
@@ -428,7 +430,9 @@ test_expect_success 'refuse to switch to branch checked out elsewhere' '
428430
git checkout main &&
429431
git worktree add wt &&
430432
test_must_fail git -C wt rebase main main 2>err &&
431-
test_grep "already used by worktree at" err
433+
test_grep "already used by worktree at" err &&
434+
test_must_fail git -C wt rebase --quit 2>err &&
435+
test_grep "no rebase in progress" err
432436
'
433437

434438
test_expect_success 'rebase when inside worktree subdirectory' '

t/t3413-rebase-hook.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ test_expect_success 'pre-rebase hook stops rebase (1)' '
110110
git reset --hard side &&
111111
test_must_fail git rebase main &&
112112
test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
113-
test 0 = $(git rev-list HEAD...side | wc -l)
113+
test 0 = $(git rev-list HEAD...side | wc -l) &&
114+
test_must_fail git rebase --quit 2>err &&
115+
test_grep "no rebase in progress" err
114116
'
115117

116118
test_expect_success 'pre-rebase hook stops rebase (2)' '

t/t3420-rebase-autostash.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,46 @@ testrebase () {
8282
type=$1
8383
dotest=$2
8484

85+
test_expect_success "rebase$type: restore autostash when pre-rebase hook fails" '
86+
git checkout -f feature-branch &&
87+
test_hook pre-rebase <<-\EOF &&
88+
exit 1
89+
EOF
90+
91+
echo changed >file0 &&
92+
test_must_fail git rebase $type --autostash -f HEAD^ &&
93+
test_must_fail git rebase --quit 2>err &&
94+
test_grep "no rebase in progress" err &&
95+
echo changed >expect &&
96+
test_cmp expect file0
97+
'
98+
99+
test_expect_success "rebase$type: restore autostash when checkout onto fails" '
100+
git checkout -f --detach feature-branch &&
101+
echo uncommitted-content >file0 &&
102+
echo untracked >file4 &&
103+
test_when_finished "rm file4" &&
104+
test_must_fail git rebase $type --autostash \
105+
unrelated-onto-branch &&
106+
test_must_fail git rebase --quit 2>err &&
107+
test_grep "no rebase in progress" err &&
108+
echo uncommitted-content >expect &&
109+
test_cmp expect file0
110+
'
111+
112+
test_expect_success "rebase$type: restore autostash when branch checkout fails" '
113+
git checkout -f unrelated-onto-branch^ &&
114+
echo uncommitted-content >file0 &&
115+
echo untracked >file4 &&
116+
test_when_finished "rm file4" &&
117+
test_must_fail git rebase $type --autostash HEAD \
118+
unrelated-onto-branch &&
119+
test_must_fail git rebase --quit 2>err &&
120+
test_grep "no rebase in progress" err &&
121+
echo uncommitted-content >expect &&
122+
test_cmp expect file0
123+
'
124+
85125
test_expect_success "rebase$type: dirty worktree, --no-autostash" '
86126
test_config rebase.autostash true &&
87127
git reset --hard &&

0 commit comments

Comments
 (0)