git-compat-util.h: add FLOSS headers for HPE NonStop
[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