]> git.ipfire.org Git - thirdparty/git.git/blob - t/t3510-cherry-pick-sequence.sh
Merge branch 'nd/attr-pathspec-in-tree-walk'
[thirdparty/git.git] / t / t3510-cherry-pick-sequence.sh
1 #!/bin/sh
2
3 test_description='Test cherry-pick continuation features
4
5 + conflicting: rewrites unrelated to conflicting
6 + yetanotherpick: rewrites foo to e
7 + anotherpick: rewrites foo to d
8 + picked: rewrites foo to c
9 + unrelatedpick: rewrites unrelated to reallyunrelated
10 + base: rewrites foo to b
11 + initial: writes foo as a, unrelated as unrelated
12
13 '
14
15 . ./test-lib.sh
16
17 # Repeat first match 10 times
18 _r10='\1\1\1\1\1\1\1\1\1\1'
19
20 pristine_detach () {
21 git cherry-pick --quit &&
22 git checkout -f "$1^0" &&
23 git read-tree -u --reset HEAD &&
24 git clean -d -f -f -q -x
25 }
26
27 test_expect_success setup '
28 git config advice.detachedhead false &&
29 echo unrelated >unrelated &&
30 git add unrelated &&
31 test_commit initial foo a &&
32 test_commit base foo b &&
33 test_commit unrelatedpick unrelated reallyunrelated &&
34 test_commit picked foo c &&
35 test_commit anotherpick foo d &&
36 test_commit yetanotherpick foo e &&
37 pristine_detach initial &&
38 test_commit conflicting unrelated
39 '
40
41 test_expect_success 'cherry-pick persists data on failure' '
42 pristine_detach initial &&
43 test_expect_code 1 git cherry-pick -s base..anotherpick &&
44 test_path_is_dir .git/sequencer &&
45 test_path_is_file .git/sequencer/head &&
46 test_path_is_file .git/sequencer/todo &&
47 test_path_is_file .git/sequencer/opts
48 '
49
50 test_expect_success 'cherry-pick mid-cherry-pick-sequence' '
51 pristine_detach initial &&
52 test_must_fail git cherry-pick base..anotherpick &&
53 test_cmp_rev picked CHERRY_PICK_HEAD &&
54 # "oops, I forgot that these patches rely on the change from base"
55 git checkout HEAD foo &&
56 git cherry-pick base &&
57 git cherry-pick picked &&
58 git cherry-pick --continue &&
59 git diff --exit-code anotherpick
60 '
61
62 test_expect_success 'cherry-pick persists opts correctly' '
63 pristine_detach initial &&
64 test_expect_code 128 git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours initial..anotherpick &&
65 test_path_is_dir .git/sequencer &&
66 test_path_is_file .git/sequencer/head &&
67 test_path_is_file .git/sequencer/todo &&
68 test_path_is_file .git/sequencer/opts &&
69 echo "true" >expect &&
70 git config --file=.git/sequencer/opts --get-all options.signoff >actual &&
71 test_cmp expect actual &&
72 echo "1" >expect &&
73 git config --file=.git/sequencer/opts --get-all options.mainline >actual &&
74 test_cmp expect actual &&
75 echo "recursive" >expect &&
76 git config --file=.git/sequencer/opts --get-all options.strategy >actual &&
77 test_cmp expect actual &&
78 cat >expect <<-\EOF &&
79 patience
80 ours
81 EOF
82 git config --file=.git/sequencer/opts --get-all options.strategy-option >actual &&
83 test_cmp expect actual
84 '
85
86 test_expect_success 'cherry-pick cleans up sequencer state upon success' '
87 pristine_detach initial &&
88 git cherry-pick initial..picked &&
89 test_path_is_missing .git/sequencer
90 '
91
92 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
93 pristine_detach initial &&
94 git cherry-pick --quit
95 '
96
97 test_expect_success '--abort requires cherry-pick in progress' '
98 pristine_detach initial &&
99 test_must_fail git cherry-pick --abort
100 '
101
102 test_expect_success '--quit cleans up sequencer state' '
103 pristine_detach initial &&
104 test_expect_code 1 git cherry-pick base..picked &&
105 git cherry-pick --quit &&
106 test_path_is_missing .git/sequencer &&
107 test_path_is_missing .git/CHERRY_PICK_HEAD
108 '
109
110 test_expect_success '--quit keeps HEAD and conflicted index intact' '
111 pristine_detach initial &&
112 cat >expect <<-\EOF &&
113 OBJID
114 :100644 100644 OBJID OBJID M unrelated
115 OBJID
116 :000000 100644 OBJID OBJID A foo
117 :000000 100644 OBJID OBJID A unrelated
118 EOF
119 test_expect_code 1 git cherry-pick base..picked &&
120 git cherry-pick --quit &&
121 test_path_is_missing .git/sequencer &&
122 test_must_fail git update-index --refresh &&
123 {
124 git rev-list HEAD |
125 git diff-tree --root --stdin |
126 sed "s/$OID_REGEX/OBJID/g"
127 } >actual &&
128 test_cmp expect actual
129 '
130
131 test_expect_success '--abort to cancel multiple cherry-pick' '
132 pristine_detach initial &&
133 test_expect_code 1 git cherry-pick base..anotherpick &&
134 git cherry-pick --abort &&
135 test_path_is_missing .git/sequencer &&
136 test_path_is_missing .git/CHERRY_PICK_HEAD &&
137 test_cmp_rev initial HEAD &&
138 git update-index --refresh &&
139 git diff-index --exit-code HEAD
140 '
141
142 test_expect_success '--abort to cancel single cherry-pick' '
143 pristine_detach initial &&
144 test_expect_code 1 git cherry-pick picked &&
145 git cherry-pick --abort &&
146 test_path_is_missing .git/sequencer &&
147 test_path_is_missing .git/CHERRY_PICK_HEAD &&
148 test_cmp_rev initial HEAD &&
149 git update-index --refresh &&
150 git diff-index --exit-code HEAD
151 '
152
153 test_expect_success '--abort does not unsafely change HEAD' '
154 pristine_detach initial &&
155 test_must_fail git cherry-pick picked anotherpick &&
156 git reset --hard base &&
157 test_must_fail git cherry-pick picked anotherpick &&
158 git cherry-pick --abort 2>actual &&
159 test_i18ngrep "You seem to have moved HEAD" actual &&
160 test_cmp_rev base HEAD
161 '
162
163 test_expect_success 'cherry-pick --abort to cancel multiple revert' '
164 pristine_detach anotherpick &&
165 test_expect_code 1 git revert base..picked &&
166 git cherry-pick --abort &&
167 test_path_is_missing .git/sequencer &&
168 test_path_is_missing .git/CHERRY_PICK_HEAD &&
169 test_cmp_rev anotherpick HEAD &&
170 git update-index --refresh &&
171 git diff-index --exit-code HEAD
172 '
173
174 test_expect_success 'revert --abort works, too' '
175 pristine_detach anotherpick &&
176 test_expect_code 1 git revert base..picked &&
177 git revert --abort &&
178 test_path_is_missing .git/sequencer &&
179 test_cmp_rev anotherpick HEAD
180 '
181
182 test_expect_success '--abort to cancel single revert' '
183 pristine_detach anotherpick &&
184 test_expect_code 1 git revert picked &&
185 git revert --abort &&
186 test_path_is_missing .git/sequencer &&
187 test_cmp_rev anotherpick HEAD &&
188 git update-index --refresh &&
189 git diff-index --exit-code HEAD
190 '
191
192 test_expect_success '--abort keeps unrelated change, easy case' '
193 pristine_detach unrelatedpick &&
194 echo changed >expect &&
195 test_expect_code 1 git cherry-pick picked..yetanotherpick &&
196 echo changed >unrelated &&
197 git cherry-pick --abort &&
198 test_cmp expect unrelated
199 '
200
201 test_expect_success '--abort refuses to clobber unrelated change, harder case' '
202 pristine_detach initial &&
203 echo changed >expect &&
204 test_expect_code 1 git cherry-pick base..anotherpick &&
205 echo changed >unrelated &&
206 test_must_fail git cherry-pick --abort &&
207 test_cmp expect unrelated &&
208 git rev-list HEAD >log &&
209 test_line_count = 2 log &&
210 test_must_fail git update-index --refresh &&
211
212 git checkout unrelated &&
213 git cherry-pick --abort &&
214 test_cmp_rev initial HEAD
215 '
216
217 test_expect_success 'cherry-pick still writes sequencer state when one commit is left' '
218 pristine_detach initial &&
219 test_expect_code 1 git cherry-pick base..picked &&
220 test_path_is_dir .git/sequencer &&
221 echo "resolved" >foo &&
222 git add foo &&
223 git commit &&
224 {
225 git rev-list HEAD |
226 git diff-tree --root --stdin |
227 sed "s/$OID_REGEX/OBJID/g"
228 } >actual &&
229 cat >expect <<-\EOF &&
230 OBJID
231 :100644 100644 OBJID OBJID M foo
232 OBJID
233 :100644 100644 OBJID OBJID M unrelated
234 OBJID
235 :000000 100644 OBJID OBJID A foo
236 :000000 100644 OBJID OBJID A unrelated
237 EOF
238 test_cmp expect actual
239 '
240
241 test_expect_success '--abort after last commit in sequence' '
242 pristine_detach initial &&
243 test_expect_code 1 git cherry-pick base..picked &&
244 git cherry-pick --abort &&
245 test_path_is_missing .git/sequencer &&
246 test_path_is_missing .git/CHERRY_PICK_HEAD &&
247 test_cmp_rev initial HEAD &&
248 git update-index --refresh &&
249 git diff-index --exit-code HEAD
250 '
251
252 test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
253 pristine_detach initial &&
254 test_expect_code 1 git cherry-pick base..anotherpick &&
255 test-tool chmtime --get .git/sequencer >expect &&
256 test_expect_code 128 git cherry-pick unrelatedpick &&
257 test-tool chmtime --get .git/sequencer >actual &&
258 test_cmp expect actual
259 '
260
261 test_expect_success '--continue complains when no cherry-pick is in progress' '
262 pristine_detach initial &&
263 test_expect_code 128 git cherry-pick --continue
264 '
265
266 test_expect_success '--continue complains when there are unresolved conflicts' '
267 pristine_detach initial &&
268 test_expect_code 1 git cherry-pick base..anotherpick &&
269 test_expect_code 128 git cherry-pick --continue
270 '
271
272 test_expect_success '--continue of single cherry-pick' '
273 pristine_detach initial &&
274 echo c >expect &&
275 test_must_fail git cherry-pick picked &&
276 echo c >foo &&
277 git add foo &&
278 git cherry-pick --continue &&
279
280 test_cmp expect foo &&
281 test_cmp_rev initial HEAD^ &&
282 git diff --exit-code HEAD &&
283 test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
284 '
285
286 test_expect_success '--continue of single revert' '
287 pristine_detach initial &&
288 echo resolved >expect &&
289 echo "Revert \"picked\"" >expect.msg &&
290 test_must_fail git revert picked &&
291 echo resolved >foo &&
292 git add foo &&
293 git cherry-pick --continue &&
294
295 git diff --exit-code HEAD &&
296 test_cmp expect foo &&
297 test_cmp_rev initial HEAD^ &&
298 git diff-tree -s --pretty=tformat:%s HEAD >msg &&
299 test_cmp expect.msg msg &&
300 test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
301 test_must_fail git rev-parse --verify REVERT_HEAD
302 '
303
304 test_expect_success '--continue after resolving conflicts' '
305 pristine_detach initial &&
306 echo d >expect &&
307 cat >expect.log <<-\EOF &&
308 OBJID
309 :100644 100644 OBJID OBJID M foo
310 OBJID
311 :100644 100644 OBJID OBJID M foo
312 OBJID
313 :100644 100644 OBJID OBJID M unrelated
314 OBJID
315 :000000 100644 OBJID OBJID A foo
316 :000000 100644 OBJID OBJID A unrelated
317 EOF
318 test_must_fail git cherry-pick base..anotherpick &&
319 echo c >foo &&
320 git add foo &&
321 git cherry-pick --continue &&
322 {
323 git rev-list HEAD |
324 git diff-tree --root --stdin |
325 sed "s/$OID_REGEX/OBJID/g"
326 } >actual.log &&
327 test_cmp expect foo &&
328 test_cmp expect.log actual.log
329 '
330
331 test_expect_success '--continue after resolving conflicts and committing' '
332 pristine_detach initial &&
333 test_expect_code 1 git cherry-pick base..anotherpick &&
334 echo "c" >foo &&
335 git add foo &&
336 git commit &&
337 git cherry-pick --continue &&
338 test_path_is_missing .git/sequencer &&
339 {
340 git rev-list HEAD |
341 git diff-tree --root --stdin |
342 sed "s/$OID_REGEX/OBJID/g"
343 } >actual &&
344 cat >expect <<-\EOF &&
345 OBJID
346 :100644 100644 OBJID OBJID M foo
347 OBJID
348 :100644 100644 OBJID OBJID M foo
349 OBJID
350 :100644 100644 OBJID OBJID M unrelated
351 OBJID
352 :000000 100644 OBJID OBJID A foo
353 :000000 100644 OBJID OBJID A unrelated
354 EOF
355 test_cmp expect actual
356 '
357
358 test_expect_success '--continue asks for help after resolving patch to nil' '
359 pristine_detach conflicting &&
360 test_must_fail git cherry-pick initial..picked &&
361
362 test_cmp_rev unrelatedpick CHERRY_PICK_HEAD &&
363 git checkout HEAD -- unrelated &&
364 test_must_fail git cherry-pick --continue 2>msg &&
365 test_i18ngrep "The previous cherry-pick is now empty" msg
366 '
367
368 test_expect_success 'follow advice and skip nil patch' '
369 pristine_detach conflicting &&
370 test_must_fail git cherry-pick initial..picked &&
371
372 git checkout HEAD -- unrelated &&
373 test_must_fail git cherry-pick --continue &&
374 git reset &&
375 git cherry-pick --continue &&
376
377 git rev-list initial..HEAD >commits &&
378 test_line_count = 3 commits
379 '
380
381 test_expect_success '--continue respects opts' '
382 pristine_detach initial &&
383 test_expect_code 1 git cherry-pick -x base..anotherpick &&
384 echo "c" >foo &&
385 git add foo &&
386 git commit &&
387 git cherry-pick --continue &&
388 test_path_is_missing .git/sequencer &&
389 git cat-file commit HEAD >anotherpick_msg &&
390 git cat-file commit HEAD~1 >picked_msg &&
391 git cat-file commit HEAD~2 >unrelatedpick_msg &&
392 git cat-file commit HEAD~3 >initial_msg &&
393 ! grep "cherry picked from" initial_msg &&
394 grep "cherry picked from" unrelatedpick_msg &&
395 grep "cherry picked from" picked_msg &&
396 grep "cherry picked from" anotherpick_msg
397 '
398
399 test_expect_success '--continue of single-pick respects -x' '
400 pristine_detach initial &&
401 test_must_fail git cherry-pick -x picked &&
402 echo c >foo &&
403 git add foo &&
404 git cherry-pick --continue &&
405 test_path_is_missing .git/sequencer &&
406 git cat-file commit HEAD >msg &&
407 grep "cherry picked from" msg
408 '
409
410 test_expect_success '--continue respects -x in first commit in multi-pick' '
411 pristine_detach initial &&
412 test_must_fail git cherry-pick -x picked anotherpick &&
413 echo c >foo &&
414 git add foo &&
415 git cherry-pick --continue &&
416 test_path_is_missing .git/sequencer &&
417 git cat-file commit HEAD^ >msg &&
418 picked=$(git rev-parse --verify picked) &&
419 grep "cherry picked from.*$picked" msg
420 '
421
422 test_expect_failure '--signoff is automatically propagated to resolved conflict' '
423 pristine_detach initial &&
424 test_expect_code 1 git cherry-pick --signoff base..anotherpick &&
425 echo "c" >foo &&
426 git add foo &&
427 git commit &&
428 git cherry-pick --continue &&
429 test_path_is_missing .git/sequencer &&
430 git cat-file commit HEAD >anotherpick_msg &&
431 git cat-file commit HEAD~1 >picked_msg &&
432 git cat-file commit HEAD~2 >unrelatedpick_msg &&
433 git cat-file commit HEAD~3 >initial_msg &&
434 ! grep "Signed-off-by:" initial_msg &&
435 grep "Signed-off-by:" unrelatedpick_msg &&
436 ! grep "Signed-off-by:" picked_msg &&
437 grep "Signed-off-by:" anotherpick_msg
438 '
439
440 test_expect_failure '--signoff dropped for implicit commit of resolution, multi-pick case' '
441 pristine_detach initial &&
442 test_must_fail git cherry-pick -s picked anotherpick &&
443 echo c >foo &&
444 git add foo &&
445 git cherry-pick --continue &&
446
447 git diff --exit-code HEAD &&
448 test_cmp_rev initial HEAD^^ &&
449 git cat-file commit HEAD^ >msg &&
450 ! grep Signed-off-by: msg
451 '
452
453 test_expect_failure 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
454 pristine_detach initial &&
455 test_must_fail git cherry-pick -s picked &&
456 echo c >foo &&
457 git add foo &&
458 git cherry-pick --continue &&
459
460 git diff --exit-code HEAD &&
461 test_cmp_rev initial HEAD^ &&
462 git cat-file commit HEAD >msg &&
463 ! grep Signed-off-by: msg
464 '
465
466 test_expect_success 'malformed instruction sheet 1' '
467 pristine_detach initial &&
468 test_expect_code 1 git cherry-pick base..anotherpick &&
469 echo "resolved" >foo &&
470 git add foo &&
471 git commit &&
472 sed "s/pick /pick/" .git/sequencer/todo >new_sheet &&
473 cp new_sheet .git/sequencer/todo &&
474 test_expect_code 128 git cherry-pick --continue
475 '
476
477 test_expect_success 'malformed instruction sheet 2' '
478 pristine_detach initial &&
479 test_expect_code 1 git cherry-pick base..anotherpick &&
480 echo "resolved" >foo &&
481 git add foo &&
482 git commit &&
483 sed "s/pick/revert/" .git/sequencer/todo >new_sheet &&
484 cp new_sheet .git/sequencer/todo &&
485 test_expect_code 128 git cherry-pick --continue
486 '
487
488 test_expect_success 'empty commit set (no commits to walk)' '
489 pristine_detach initial &&
490 test_expect_code 128 git cherry-pick base..base
491 '
492
493 test_expect_success 'empty commit set (culled during walk)' '
494 pristine_detach initial &&
495 test_expect_code 128 git cherry-pick -2 --author=no.such.author base
496 '
497
498 test_expect_success 'malformed instruction sheet 3' '
499 pristine_detach initial &&
500 test_expect_code 1 git cherry-pick base..anotherpick &&
501 echo "resolved" >foo &&
502 git add foo &&
503 git commit &&
504 sed "s/pick \([0-9a-f]*\)/pick $_r10/" .git/sequencer/todo >new_sheet &&
505 cp new_sheet .git/sequencer/todo &&
506 test_expect_code 128 git cherry-pick --continue
507 '
508
509 test_expect_success 'instruction sheet, fat-fingers version' '
510 pristine_detach initial &&
511 test_expect_code 1 git cherry-pick base..anotherpick &&
512 echo "c" >foo &&
513 git add foo &&
514 git commit &&
515 sed "s/pick \([0-9a-f]*\)/pick \1 /" .git/sequencer/todo >new_sheet &&
516 cp new_sheet .git/sequencer/todo &&
517 git cherry-pick --continue
518 '
519
520 test_expect_success 'commit descriptions in insn sheet are optional' '
521 pristine_detach initial &&
522 test_expect_code 1 git cherry-pick base..anotherpick &&
523 echo "c" >foo &&
524 git add foo &&
525 git commit &&
526 cut -d" " -f1,2 .git/sequencer/todo >new_sheet &&
527 cp new_sheet .git/sequencer/todo &&
528 git cherry-pick --continue &&
529 test_path_is_missing .git/sequencer &&
530 git rev-list HEAD >commits &&
531 test_line_count = 4 commits
532 '
533
534 test_done