Raw
1 #!/bin/sh
2 #
3 # Copyright (c) 2013 Ramkumar Ramachandra
4 #
5
6 test_description='git rebase --autostash tests'
7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
9
10 . ./test-lib.sh
11
12 test_expect_success setup '
13 echo hello-world >file0 &&
14 git add . &&
15 test_tick &&
16 git commit -m "initial commit" &&
17 git checkout -b feature-branch &&
18 echo another-hello >file1 &&
19 echo goodbye >file2 &&
20 git add . &&
21 test_tick &&
22 git commit -m "second commit" &&
23 echo final-goodbye >file3 &&
24 git add . &&
25 test_tick &&
26 git commit -m "third commit" &&
27 git checkout -b unrelated-onto-branch main &&
28 echo unrelated >file4 &&
29 git add . &&
30 test_tick &&
31 git commit -m "unrelated commit" &&
32 git checkout -b related-onto-branch main &&
33 echo conflicting-change >file2 &&
34 git add . &&
35 test_tick &&
36 git commit -m "related commit" &&
37 remove_progress_re="$(printf "s/.*\\r//")"
38 '
39
40 create_expected_success_apply () {
41 cat >expected <<-EOF
42 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
43 First, rewinding head to replay your work on top of it...
44 Applying: second commit
45 Applying: third commit
46 Applied autostash.
47 EOF
48 }
49
50 create_expected_success_merge () {
51 q_to_cr >expected <<-EOF
52 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
53 Applied autostash.
54 Successfully rebased and updated refs/heads/rebased-feature-branch.
55 EOF
56 }
57
58 create_expected_failure_apply () {
59 cat >expected <<-EOF
60 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
61 First, rewinding head to replay your work on top of it...
62 Applying: second commit
63 Applying: third commit
64 Your local changes are stashed, however applying them
65 resulted in conflicts. You can either resolve the conflicts
66 and then discard the stash with "git stash drop", or, if you
67 do not want to resolve them now, run "git reset --hard" and
68 apply the local changes later by running "git stash pop".
69 EOF
70 }
71
72 create_expected_failure_merge () {
73 cat >expected <<-EOF
74 $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
75 Your local changes are stashed, however applying them
76 resulted in conflicts. You can either resolve the conflicts
77 and then discard the stash with "git stash drop", or, if you
78 do not want to resolve them now, run "git reset --hard" and
79 apply the local changes later by running "git stash pop".
80 Successfully rebased and updated refs/heads/rebased-feature-branch.
81 EOF
82 }
83
84 testrebase () {
85 type=$1
86 dotest=$2
87
88 test_expect_success "rebase$type: restore autostash when pre-rebase hook fails" '
89 git checkout -f feature-branch &&
90 test_hook pre-rebase <<-\EOF &&
91 exit 1
92 EOF
93
94 echo changed >file0 &&
95 test_must_fail git rebase $type --autostash -f HEAD^ &&
96 test_must_fail git rebase --quit 2>err &&
97 test_grep "no rebase in progress" err &&
98 echo changed >expect &&
99 test_cmp expect file0
100 '
101
102 test_expect_success "rebase$type: restore autostash when checkout onto fails" '
103 git checkout -f --detach feature-branch &&
104 echo uncommitted-content >file0 &&
105 echo untracked >file4 &&
106 test_when_finished "rm file4" &&
107 test_must_fail git rebase $type --autostash \
108 unrelated-onto-branch &&
109 test_must_fail git rebase --quit 2>err &&
110 test_grep "no rebase in progress" err &&
111 echo uncommitted-content >expect &&
112 test_cmp expect file0
113 '
114
115 test_expect_success "rebase$type: restore autostash when branch checkout fails" '
116 git checkout -f unrelated-onto-branch^ &&
117 echo uncommitted-content >file0 &&
118 echo untracked >file4 &&
119 test_when_finished "rm file4" &&
120 test_must_fail git rebase $type --autostash HEAD \
121 unrelated-onto-branch &&
122 test_must_fail git rebase --quit 2>err &&
123 test_grep "no rebase in progress" err &&
124 echo uncommitted-content >expect &&
125 test_cmp expect file0
126 '
127
128 test_expect_success "rebase$type: dirty worktree, --no-autostash" '
129 test_config rebase.autostash true &&
130 git reset --hard &&
131 git checkout -b rebased-feature-branch feature-branch &&
132 test_when_finished git branch -D rebased-feature-branch &&
133 test_when_finished git checkout feature-branch &&
134 echo dirty >>file3 &&
135 test_must_fail git rebase$type --no-autostash unrelated-onto-branch
136 '
137
138 test_expect_success "rebase$type: dirty worktree, non-conflicting rebase" '
139 test_config rebase.autostash true &&
140 git reset --hard &&
141 git checkout -b rebased-feature-branch feature-branch &&
142 echo dirty >>file3 &&
143 git rebase$type unrelated-onto-branch >actual 2>&1 &&
144 grep unrelated file4 &&
145 grep dirty file3 &&
146 git checkout feature-branch
147 '
148
149 test_expect_success "rebase$type --autostash: check output" '
150 test_when_finished git branch -D rebased-feature-branch &&
151 suffix=${type#\ --} && suffix=${suffix:-apply} &&
152 if test ${suffix} = "interactive"; then
153 suffix=merge
154 fi &&
155 create_expected_success_$suffix &&
156 sed "$remove_progress_re" <actual >actual2 &&
157 test_cmp expected actual2
158 '
159
160 test_expect_success "rebase$type: dirty index, non-conflicting rebase" '
161 test_config rebase.autostash true &&
162 git reset --hard &&
163 git checkout -b rebased-feature-branch feature-branch &&
164 test_when_finished git branch -D rebased-feature-branch &&
165 echo dirty >>file3 &&
166 git add file3 &&
167 git rebase$type unrelated-onto-branch &&
168 grep unrelated file4 &&
169 grep dirty file3 &&
170 git checkout feature-branch
171 '
172
173 test_expect_success "rebase$type: conflicting rebase" '
174 test_config rebase.autostash true &&
175 git reset --hard &&
176 git checkout -b rebased-feature-branch feature-branch &&
177 test_when_finished git branch -D rebased-feature-branch &&
178 echo dirty >>file3 &&
179 test_must_fail git rebase$type related-onto-branch &&
180 test_path_is_file $dotest/autostash &&
181 test_path_is_missing file3 &&
182 rm -rf $dotest &&
183 git reset --hard &&
184 git checkout feature-branch
185 '
186
187 test_expect_success "rebase$type: --continue" '
188 test_config rebase.autostash true &&
189 git reset --hard &&
190 git checkout -b rebased-feature-branch feature-branch &&
191 test_when_finished git branch -D rebased-feature-branch &&
192 echo dirty >>file3 &&
193 test_must_fail git rebase$type related-onto-branch &&
194 test_path_is_file $dotest/autostash &&
195 test_path_is_missing file3 &&
196 echo "conflicting-plus-goodbye" >file2 &&
197 git add file2 &&
198 git rebase --continue &&
199 test_path_is_missing $dotest/autostash &&
200 grep dirty file3 &&
201 git checkout feature-branch
202 '
203
204 test_expect_success "rebase$type: --skip" '
205 test_config rebase.autostash true &&
206 git reset --hard &&
207 git checkout -b rebased-feature-branch feature-branch &&
208 test_when_finished git branch -D rebased-feature-branch &&
209 echo dirty >>file3 &&
210 test_must_fail git rebase$type related-onto-branch &&
211 test_path_is_file $dotest/autostash &&
212 test_path_is_missing file3 &&
213 git rebase --skip &&
214 test_path_is_missing $dotest/autostash &&
215 grep dirty file3 &&
216 git checkout feature-branch
217 '
218
219 test_expect_success "rebase$type: --abort" '
220 test_config rebase.autostash true &&
221 git reset --hard &&
222 git checkout -b rebased-feature-branch feature-branch &&
223 test_when_finished git branch -D rebased-feature-branch &&
224 echo dirty >>file3 &&
225 test_must_fail git rebase$type related-onto-branch &&
226 test_path_is_file $dotest/autostash &&
227 test_path_is_missing file3 &&
228 git rebase --abort &&
229 test_path_is_missing $dotest/autostash &&
230 grep dirty file3 &&
231 git checkout feature-branch
232 '
233
234 test_expect_success "rebase$type: --quit" '
235 test_config rebase.autostash true &&
236 git reset --hard &&
237 git checkout -b rebased-feature-branch feature-branch &&
238 test_when_finished git branch -D rebased-feature-branch &&
239 echo dirty >>file3 &&
240 git diff >expect &&
241 test_must_fail git rebase$type related-onto-branch &&
242 test_path_is_file $dotest/autostash &&
243 test_path_is_missing file3 &&
244 git rebase --quit &&
245 test_when_finished git stash drop &&
246 test_path_is_missing $dotest/autostash &&
247 ! grep dirty file3 &&
248 git stash show -p >actual &&
249 test_cmp expect actual &&
250 git reset --hard &&
251 git checkout feature-branch
252 '
253
254 test_expect_success "rebase$type: non-conflicting rebase, conflicting stash" '
255 test_config rebase.autostash true &&
256 git reset --hard &&
257 git checkout -b rebased-feature-branch feature-branch &&
258 echo dirty >file4 &&
259 git add file4 &&
260 git rebase$type unrelated-onto-branch >actual 2>&1 &&
261 test_path_is_missing $dotest &&
262 git reset --hard &&
263 grep unrelated file4 &&
264 ! grep dirty file4 &&
265 git checkout feature-branch &&
266 git stash pop &&
267 grep dirty file4
268 '
269
270 test_expect_success "rebase$type: check output with conflicting stash" '
271 test_when_finished git branch -D rebased-feature-branch &&
272 suffix=${type#\ --} && suffix=${suffix:-apply} &&
273 if test ${suffix} = "interactive"; then
274 suffix=merge
275 fi &&
276 create_expected_failure_$suffix &&
277 sed "$remove_progress_re" <actual >actual2 &&
278 test_cmp expected actual2
279 '
280 }
281
282 test_expect_success "rebase: fast-forward rebase" '
283 test_config rebase.autostash true &&
284 git reset --hard &&
285 git checkout -b behind-feature-branch feature-branch~1 &&
286 test_when_finished git branch -D behind-feature-branch &&
287 echo dirty >>file1 &&
288 git rebase feature-branch &&
289 grep dirty file1 &&
290 git checkout feature-branch
291 '
292
293 test_expect_success "rebase: noop rebase" '
294 test_config rebase.autostash true &&
295 git reset --hard &&
296 git checkout -b same-feature-branch feature-branch &&
297 test_when_finished git branch -D same-feature-branch &&
298 echo dirty >>file1 &&
299 git rebase feature-branch &&
300 grep dirty file1 &&
301 git checkout feature-branch
302 '
303
304 testrebase " --apply" .git/rebase-apply
305 testrebase " --merge" .git/rebase-merge
306 testrebase " --interactive" .git/rebase-merge
307
308 test_expect_success 'abort rebase -i with --autostash' '
309 test_when_finished "git reset --hard" &&
310 echo uncommitted-content >file0 &&
311 (
312 write_script abort-editor.sh <<-\EOF &&
313 echo >"$1"
314 EOF
315 test_set_editor "$(pwd)/abort-editor.sh" &&
316 test_must_fail git rebase -i --autostash HEAD^ &&
317 rm -f abort-editor.sh
318 ) &&
319 echo uncommitted-content >expected &&
320 test_cmp expected file0
321 '
322
323 test_expect_success 'restore autostash on editor failure' '
324 test_when_finished "git reset --hard" &&
325 echo uncommitted-content >file0 &&
326 (
327 test_set_editor "false" &&
328 test_must_fail git rebase -i --autostash HEAD^
329 ) &&
330 echo uncommitted-content >expected &&
331 test_cmp expected file0
332 '
333
334 test_expect_success 'autostash is saved on editor failure with conflict' '
335 test_when_finished "git reset --hard" &&
336 echo uncommitted-content >file0 &&
337 (
338 write_script abort-editor.sh <<-\EOF &&
339 echo conflicting-content >file0
340 exit 1
341 EOF
342 test_set_editor "$(pwd)/abort-editor.sh" &&
343 test_must_fail git rebase -i --autostash HEAD^ &&
344 rm -f abort-editor.sh
345 ) &&
346 echo conflicting-content >expected &&
347 test_cmp expected file0 &&
348 git checkout file0 &&
349 git stash pop &&
350 echo uncommitted-content >expected &&
351 test_cmp expected file0
352 '
353
354 test_expect_success 'autostash with dirty submodules' '
355 test_when_finished "git reset --hard && git checkout main" &&
356 git checkout -b with-submodule &&
357 git -c protocol.file.allow=always submodule add ./ sub &&
358 test_tick &&
359 git commit -m add-submodule &&
360 echo changed >sub/file0 &&
361 git rebase -i --autostash HEAD
362 '
363
364 test_expect_success 'branch is left alone when possible' '
365 git checkout -b unchanged-branch &&
366 echo changed >file0 &&
367 git rebase --autostash unchanged-branch &&
368 test changed = "$(cat file0)" &&
369 test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)"
370 '
371
372 test_expect_success 'never change active branch' '
373 git checkout -b not-the-feature-branch unrelated-onto-branch &&
374 test_when_finished "git reset --hard && git checkout main" &&
375 echo changed >file0 &&
376 git rebase --autostash not-the-feature-branch feature-branch &&
377 test_cmp_rev not-the-feature-branch unrelated-onto-branch
378 '
379
380 test_expect_success 'autostash commit is marked as reachable' '
381 echo changed >file0 &&
382 git rebase --autostash --exec "git prune --expire=now" \
383 feature-branch^ feature-branch &&
384 # git rebase succeeds if the stash cannot be applied so we need to check
385 # the contents of file0
386 echo changed >expect &&
387 test_cmp expect file0
388 '
389
390 test_done