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