3 # Copyright (c) 2013 Ramkumar Ramachandra
6 test_description
='git rebase --autostash tests'
7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
=main
8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
10 TEST_PASSES_SANITIZE_LEAK
=true
13 test_expect_success setup
'
14 echo hello-world >file0 &&
17 git commit -m "initial commit" &&
18 git checkout -b feature-branch &&
19 echo another-hello >file1 &&
20 echo goodbye >file2 &&
23 git commit -m "second commit" &&
24 echo final-goodbye >file3 &&
27 git commit -m "third commit" &&
28 git checkout -b unrelated-onto-branch main &&
29 echo unrelated >file4 &&
32 git commit -m "unrelated commit" &&
33 git checkout -b related-onto-branch main &&
34 echo conflicting-change >file2 &&
37 git commit -m "related commit" &&
38 remove_progress_re="$(printf "s/.*\\r//")"
41 create_expected_success_apply
() {
43 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
44 First, rewinding head to replay your work on top of it...
45 Applying: second commit
46 Applying: third commit
51 create_expected_success_merge
() {
52 q_to_cr
>expected
<<-EOF
53 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
55 Successfully rebased and updated refs/heads/rebased-feature-branch.
59 create_expected_failure_apply
() {
61 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
62 First, rewinding head to replay your work on top of it...
63 Applying: second commit
64 Applying: third commit
65 Applying autostash resulted in conflicts.
66 Your changes are safe in the stash.
67 You can run "git stash pop" or "git stash drop" at any time.
71 create_expected_failure_merge
() {
73 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
74 Applying autostash resulted in conflicts.
75 Your changes are safe in the stash.
76 You can run "git stash pop" or "git stash drop" at any time.
77 Successfully rebased and updated refs/heads/rebased-feature-branch.
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 &&
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 &&
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
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
125 test_expect_success
"rebase$type: dirty worktree, --no-autostash" '
126 test_config rebase.autostash true &&
128 git checkout -b rebased-feature-branch feature-branch &&
129 test_when_finished git branch -D rebased-feature-branch &&
130 test_when_finished git checkout feature-branch &&
131 echo dirty >>file3 &&
132 test_must_fail git rebase$type --no-autostash unrelated-onto-branch
135 test_expect_success
"rebase$type: dirty worktree, non-conflicting rebase" '
136 test_config rebase.autostash true &&
138 git checkout -b rebased-feature-branch feature-branch &&
139 echo dirty >>file3 &&
140 git rebase$type unrelated-onto-branch >actual 2>&1 &&
141 grep unrelated file4 &&
143 git checkout feature-branch
146 test_expect_success
"rebase$type --autostash: check output" '
147 test_when_finished git branch -D rebased-feature-branch &&
148 suffix=${type#\ --} && suffix=${suffix:-apply} &&
149 if test ${suffix} = "interactive"; then
152 create_expected_success_$suffix &&
153 sed "$remove_progress_re" <actual >actual2 &&
154 test_cmp expected actual2
157 test_expect_success
"rebase$type: dirty index, non-conflicting rebase" '
158 test_config rebase.autostash true &&
160 git checkout -b rebased-feature-branch feature-branch &&
161 test_when_finished git branch -D rebased-feature-branch &&
162 echo dirty >>file3 &&
164 git rebase$type unrelated-onto-branch &&
165 grep unrelated file4 &&
167 git checkout feature-branch
170 test_expect_success
"rebase$type: conflicting rebase" '
171 test_config rebase.autostash true &&
173 git checkout -b rebased-feature-branch feature-branch &&
174 test_when_finished git branch -D rebased-feature-branch &&
175 echo dirty >>file3 &&
176 test_must_fail git rebase$type related-onto-branch &&
177 test_path_is_file $dotest/autostash &&
178 test_path_is_missing file3 &&
181 git checkout feature-branch
184 test_expect_success
"rebase$type: --continue" '
185 test_config rebase.autostash true &&
187 git checkout -b rebased-feature-branch feature-branch &&
188 test_when_finished git branch -D rebased-feature-branch &&
189 echo dirty >>file3 &&
190 test_must_fail git rebase$type related-onto-branch &&
191 test_path_is_file $dotest/autostash &&
192 test_path_is_missing file3 &&
193 echo "conflicting-plus-goodbye" >file2 &&
195 git rebase --continue &&
196 test_path_is_missing $dotest/autostash &&
198 git checkout feature-branch
201 test_expect_success
"rebase$type: --skip" '
202 test_config rebase.autostash true &&
204 git checkout -b rebased-feature-branch feature-branch &&
205 test_when_finished git branch -D rebased-feature-branch &&
206 echo dirty >>file3 &&
207 test_must_fail git rebase$type related-onto-branch &&
208 test_path_is_file $dotest/autostash &&
209 test_path_is_missing file3 &&
211 test_path_is_missing $dotest/autostash &&
213 git checkout feature-branch
216 test_expect_success
"rebase$type: --abort" '
217 test_config rebase.autostash true &&
219 git checkout -b rebased-feature-branch feature-branch &&
220 test_when_finished git branch -D rebased-feature-branch &&
221 echo dirty >>file3 &&
222 test_must_fail git rebase$type related-onto-branch &&
223 test_path_is_file $dotest/autostash &&
224 test_path_is_missing file3 &&
225 git rebase --abort &&
226 test_path_is_missing $dotest/autostash &&
228 git checkout feature-branch
231 test_expect_success
"rebase$type: --quit" '
232 test_config rebase.autostash true &&
234 git checkout -b rebased-feature-branch feature-branch &&
235 test_when_finished git branch -D rebased-feature-branch &&
236 echo dirty >>file3 &&
238 test_must_fail git rebase$type related-onto-branch &&
239 test_path_is_file $dotest/autostash &&
240 test_path_is_missing file3 &&
242 test_when_finished git stash drop &&
243 test_path_is_missing $dotest/autostash &&
244 ! grep dirty file3 &&
245 git stash show -p >actual &&
246 test_cmp expect actual &&
248 git checkout feature-branch
251 test_expect_success
"rebase$type: non-conflicting rebase, conflicting stash" '
252 test_config rebase.autostash true &&
254 git checkout -b rebased-feature-branch feature-branch &&
257 git rebase$type unrelated-onto-branch >actual 2>&1 &&
258 test_path_is_missing $dotest &&
260 grep unrelated file4 &&
261 ! grep dirty file4 &&
262 git checkout feature-branch &&
267 test_expect_success
"rebase$type: check output with conflicting stash" '
268 test_when_finished git branch -D rebased-feature-branch &&
269 suffix=${type#\ --} && suffix=${suffix:-apply} &&
270 if test ${suffix} = "interactive"; then
273 create_expected_failure_$suffix &&
274 sed "$remove_progress_re" <actual >actual2 &&
275 test_cmp expected actual2
279 test_expect_success
"rebase: fast-forward rebase" '
280 test_config rebase.autostash true &&
282 git checkout -b behind-feature-branch feature-branch~1 &&
283 test_when_finished git branch -D behind-feature-branch &&
284 echo dirty >>file1 &&
285 git rebase feature-branch &&
287 git checkout feature-branch
290 test_expect_success
"rebase: noop rebase" '
291 test_config rebase.autostash true &&
293 git checkout -b same-feature-branch feature-branch &&
294 test_when_finished git branch -D same-feature-branch &&
295 echo dirty >>file1 &&
296 git rebase feature-branch &&
298 git checkout feature-branch
301 testrebase
" --apply" .git
/rebase-apply
302 testrebase
" --merge" .git
/rebase-merge
303 testrebase
" --interactive" .git
/rebase-merge
305 test_expect_success
'abort rebase -i with --autostash' '
306 test_when_finished "git reset --hard" &&
307 echo uncommitted-content >file0 &&
309 write_script abort-editor.sh <<-\EOF &&
312 test_set_editor "$(pwd)/abort-editor.sh" &&
313 test_must_fail git rebase -i --autostash HEAD^ &&
314 rm -f abort-editor.sh
316 echo uncommitted-content >expected &&
317 test_cmp expected file0
320 test_expect_success
'restore autostash on editor failure' '
321 test_when_finished "git reset --hard" &&
322 echo uncommitted-content >file0 &&
324 test_set_editor "false" &&
325 test_must_fail git rebase -i --autostash HEAD^
327 echo uncommitted-content >expected &&
328 test_cmp expected file0
331 test_expect_success
'autostash is saved on editor failure with conflict' '
332 test_when_finished "git reset --hard" &&
333 echo uncommitted-content >file0 &&
335 write_script abort-editor.sh <<-\EOF &&
336 echo conflicting-content >file0
339 test_set_editor "$(pwd)/abort-editor.sh" &&
340 test_must_fail git rebase -i --autostash HEAD^ &&
341 rm -f abort-editor.sh
343 echo conflicting-content >expected &&
344 test_cmp expected file0 &&
345 git checkout file0 &&
347 echo uncommitted-content >expected &&
348 test_cmp expected file0
351 test_expect_success
'autostash with dirty submodules' '
352 test_when_finished "git reset --hard && git checkout main" &&
353 git checkout -b with-submodule &&
354 git -c protocol.file.allow=always submodule add ./ sub &&
356 git commit -m add-submodule &&
357 echo changed >sub/file0 &&
358 git rebase -i --autostash HEAD
361 test_expect_success
'branch is left alone when possible' '
362 git checkout -b unchanged-branch &&
363 echo changed >file0 &&
364 git rebase --autostash unchanged-branch &&
365 test changed = "$(cat file0)" &&
366 test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)"
369 test_expect_success
'never change active branch' '
370 git checkout -b not-the-feature-branch unrelated-onto-branch &&
371 test_when_finished "git reset --hard && git checkout main" &&
372 echo changed >file0 &&
373 git rebase --autostash not-the-feature-branch feature-branch &&
374 test_cmp_rev not-the-feature-branch unrelated-onto-branch
377 test_expect_success
'autostash commit is marked as reachable' '
378 echo changed >file0 &&
379 git rebase --autostash --exec "git prune --expire=now" \
380 feature-branch^ feature-branch &&
381 # git rebase succeeds if the stash cannot be applied so we need to check
382 # the contents of file0
383 echo changed >expect &&
384 test_cmp expect file0