git-apply: try threeway first when "--3way" is used
[git] / t / t3507-cherry-pick-conflict.sh
1 #!/bin/sh
2
3 test_description='test cherry-pick and revert with conflicts
4
5   -
6   + picked: rewrites foo to c
7   + base: rewrites foo to b
8   + initial: writes foo as a, unrelated as unrelated
9
10 '
11
12 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
13 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
14
15 . ./test-lib.sh
16
17 pristine_detach () {
18         git checkout -f "$1^0" &&
19         git read-tree -u --reset HEAD &&
20         git clean -d -f -f -q -x
21 }
22
23 test_expect_success setup '
24
25         echo unrelated >unrelated &&
26         git add unrelated &&
27         test_commit initial foo a &&
28         test_commit base foo b &&
29         test_commit picked foo c &&
30         test_commit --signoff picked-signed foo d &&
31         git checkout -b topic initial &&
32         test_commit redundant-pick foo c redundant &&
33         git commit --allow-empty --allow-empty-message &&
34         git tag empty &&
35         git checkout main &&
36         git config advice.detachedhead false
37
38 '
39
40 test_expect_success 'failed cherry-pick does not advance HEAD' '
41         pristine_detach initial &&
42
43         head=$(git rev-parse HEAD) &&
44         test_must_fail git cherry-pick picked &&
45         newhead=$(git rev-parse HEAD) &&
46
47         test "$head" = "$newhead"
48 '
49
50 test_expect_success 'advice from failed cherry-pick' "
51         pristine_detach initial &&
52
53         picked=\$(git rev-parse --short picked) &&
54         cat <<-EOF >expected &&
55         error: could not apply \$picked... picked
56         hint: after resolving the conflicts, mark the corrected paths
57         hint: with 'git add <paths>' or 'git rm <paths>'
58         hint: and commit the result with 'git commit'
59         EOF
60         test_must_fail git cherry-pick picked 2>actual &&
61
62         test_cmp expected actual
63 "
64
65 test_expect_success 'advice from failed cherry-pick --no-commit' "
66         pristine_detach initial &&
67
68         picked=\$(git rev-parse --short picked) &&
69         cat <<-EOF >expected &&
70         error: could not apply \$picked... picked
71         hint: after resolving the conflicts, mark the corrected paths
72         hint: with 'git add <paths>' or 'git rm <paths>'
73         EOF
74         test_must_fail git cherry-pick --no-commit picked 2>actual &&
75
76         test_cmp expected actual
77 "
78
79 test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
80         pristine_detach initial &&
81         test_must_fail git cherry-pick picked &&
82         test_cmp_rev picked CHERRY_PICK_HEAD
83 '
84
85 test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '
86         pristine_detach initial &&
87         git cherry-pick base &&
88         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
89 '
90
91 test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
92         pristine_detach initial &&
93         git cherry-pick --no-commit base &&
94         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
95 '
96
97 test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
98         pristine_detach initial &&
99         echo foo >foo &&
100         test_must_fail git cherry-pick base &&
101         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
102 '
103
104 test_expect_success \
105         'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
106         pristine_detach initial &&
107         echo foo >foo &&
108         test_must_fail git cherry-pick --strategy=resolve base &&
109         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
110 '
111
112 test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '
113         pristine_detach initial &&
114         (
115                 GIT_CHERRY_PICK_HELP="and then do something else" &&
116                 export GIT_CHERRY_PICK_HELP &&
117                 test_must_fail git cherry-pick picked
118         ) &&
119         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
120 '
121
122 test_expect_success 'git reset clears CHERRY_PICK_HEAD' '
123         pristine_detach initial &&
124
125         test_must_fail git cherry-pick picked &&
126         git reset &&
127
128         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
129 '
130
131 test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '
132         pristine_detach initial &&
133
134         test_must_fail git cherry-pick picked &&
135         test_must_fail git commit &&
136
137         test_cmp_rev picked CHERRY_PICK_HEAD
138 '
139
140 test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '
141         pristine_detach initial &&
142
143         test_must_fail git cherry-pick picked &&
144         echo resolved >foo &&
145         git add foo &&
146         git update-index --refresh -q &&
147         test_must_fail git diff-index --exit-code HEAD &&
148         (
149                 GIT_EDITOR=false &&
150                 export GIT_EDITOR &&
151                 test_must_fail git commit
152         ) &&
153
154         test_cmp_rev picked CHERRY_PICK_HEAD
155 '
156
157 test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '
158         pristine_detach initial &&
159
160         test_must_fail git cherry-pick picked &&
161         echo resolved >foo &&
162         git add foo &&
163         git commit &&
164
165         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
166 '
167
168 test_expect_success 'partial commit of cherry-pick fails' '
169         pristine_detach initial &&
170
171         test_must_fail git cherry-pick picked &&
172         echo resolved >foo &&
173         git add foo &&
174         test_must_fail git commit foo 2>err &&
175
176         test_i18ngrep "cannot do a partial commit during a cherry-pick." err
177 '
178
179 test_expect_success 'commit --amend of cherry-pick fails' '
180         pristine_detach initial &&
181
182         test_must_fail git cherry-pick picked &&
183         echo resolved >foo &&
184         git add foo &&
185         test_must_fail git commit --amend 2>err &&
186
187         test_i18ngrep "in the middle of a cherry-pick -- cannot amend." err
188 '
189
190 test_expect_success 'successful final commit clears cherry-pick state' '
191         pristine_detach initial &&
192
193         test_must_fail git cherry-pick base picked-signed &&
194         echo resolved >foo &&
195         test_path_is_file .git/sequencer/todo &&
196         git commit -a &&
197         test_path_is_missing .git/sequencer
198 '
199
200 test_expect_success 'reset after final pick clears cherry-pick state' '
201         pristine_detach initial &&
202
203         test_must_fail git cherry-pick base picked-signed &&
204         echo resolved >foo &&
205         test_path_is_file .git/sequencer/todo &&
206         git reset &&
207         test_path_is_missing .git/sequencer
208 '
209
210 test_expect_success 'failed cherry-pick produces dirty index' '
211         pristine_detach initial &&
212
213         test_must_fail git cherry-pick picked &&
214
215         test_must_fail git update-index --refresh -q &&
216         test_must_fail git diff-index --exit-code HEAD
217 '
218
219 test_expect_success 'failed cherry-pick registers participants in index' '
220         pristine_detach initial &&
221         {
222                 git checkout base -- foo &&
223                 git ls-files --stage foo &&
224                 git checkout initial -- foo &&
225                 git ls-files --stage foo &&
226                 git checkout picked -- foo &&
227                 git ls-files --stage foo
228         } >stages &&
229         sed "
230                 1 s/ 0  / 1     /
231                 2 s/ 0  / 2     /
232                 3 s/ 0  / 3     /
233         " stages >expected &&
234         git read-tree -u --reset HEAD &&
235
236         test_must_fail git cherry-pick picked &&
237         git ls-files --stage --unmerged >actual &&
238
239         test_cmp expected actual
240 '
241
242 test_expect_success \
243         'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
244         pristine_detach initial &&
245         git config commit.cleanup scissors &&
246         cat <<-EOF >expected &&
247                 picked
248
249                 # ------------------------ >8 ------------------------
250                 # Do not modify or remove the line above.
251                 # Everything below it will be ignored.
252                 #
253                 # Conflicts:
254                 #       foo
255                 EOF
256
257         test_must_fail git cherry-pick picked &&
258
259         test_cmp expected .git/MERGE_MSG
260 '
261
262 test_expect_success \
263         'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
264         pristine_detach initial &&
265         git config --unset commit.cleanup &&
266         cat <<-EOF >expected &&
267                 picked
268
269                 # ------------------------ >8 ------------------------
270                 # Do not modify or remove the line above.
271                 # Everything below it will be ignored.
272                 #
273                 # Conflicts:
274                 #       foo
275                 EOF
276
277         test_must_fail git cherry-pick --cleanup=scissors picked &&
278
279         test_cmp expected .git/MERGE_MSG
280 '
281
282 test_expect_success 'failed cherry-pick describes conflict in work tree' '
283         pristine_detach initial &&
284         cat <<-EOF >expected &&
285         <<<<<<< HEAD
286         a
287         =======
288         c
289         >>>>>>> objid (picked)
290         EOF
291
292         test_must_fail git cherry-pick picked &&
293
294         sed "s/[a-f0-9]* (/objid (/" foo >actual &&
295         test_cmp expected actual
296 '
297
298 test_expect_success 'diff3 -m style' '
299         pristine_detach initial &&
300         git config merge.conflictstyle diff3 &&
301         cat <<-EOF >expected &&
302         <<<<<<< HEAD
303         a
304         ||||||| parent of objid (picked)
305         b
306         =======
307         c
308         >>>>>>> objid (picked)
309         EOF
310
311         test_must_fail git cherry-pick picked &&
312
313         sed "s/[a-f0-9]* (/objid (/" foo >actual &&
314         test_cmp expected actual
315 '
316
317 test_expect_success 'revert also handles conflicts sanely' '
318         git config --unset merge.conflictstyle &&
319         pristine_detach initial &&
320         cat <<-EOF >expected &&
321         <<<<<<< HEAD
322         a
323         =======
324         b
325         >>>>>>> parent of objid (picked)
326         EOF
327         {
328                 git checkout picked -- foo &&
329                 git ls-files --stage foo &&
330                 git checkout initial -- foo &&
331                 git ls-files --stage foo &&
332                 git checkout base -- foo &&
333                 git ls-files --stage foo
334         } >stages &&
335         sed "
336                 1 s/ 0  / 1     /
337                 2 s/ 0  / 2     /
338                 3 s/ 0  / 3     /
339         " stages >expected-stages &&
340         git read-tree -u --reset HEAD &&
341
342         head=$(git rev-parse HEAD) &&
343         test_must_fail git revert picked &&
344         newhead=$(git rev-parse HEAD) &&
345         git ls-files --stage --unmerged >actual-stages &&
346
347         test "$head" = "$newhead" &&
348         test_must_fail git update-index --refresh -q &&
349         test_must_fail git diff-index --exit-code HEAD &&
350         test_cmp expected-stages actual-stages &&
351         sed "s/[a-f0-9]* (/objid (/" foo >actual &&
352         test_cmp expected actual
353 '
354
355 test_expect_success 'failed revert sets REVERT_HEAD' '
356         pristine_detach initial &&
357         test_must_fail git revert picked &&
358         test_cmp_rev picked REVERT_HEAD
359 '
360
361 test_expect_success 'successful revert does not set REVERT_HEAD' '
362         pristine_detach base &&
363         git revert base &&
364         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
365         test_must_fail git rev-parse --verify REVERT_HEAD
366 '
367
368 test_expect_success 'revert --no-commit sets REVERT_HEAD' '
369         pristine_detach base &&
370         git revert --no-commit base &&
371         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
372         test_cmp_rev base REVERT_HEAD
373 '
374
375 test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
376         pristine_detach base &&
377         echo foo >foo &&
378         test_must_fail git revert base &&
379         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
380         test_must_fail git rev-parse --verify REVERT_HEAD
381 '
382
383 test_expect_success 'GIT_CHERRY_PICK_HELP does not suppress REVERT_HEAD' '
384         pristine_detach initial &&
385         (
386                 GIT_CHERRY_PICK_HELP="and then do something else" &&
387                 GIT_REVERT_HELP="and then do something else, again" &&
388                 export GIT_CHERRY_PICK_HELP GIT_REVERT_HELP &&
389                 test_must_fail git revert picked
390         ) &&
391         test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
392         test_cmp_rev picked REVERT_HEAD
393 '
394
395 test_expect_success 'git reset clears REVERT_HEAD' '
396         pristine_detach initial &&
397         test_must_fail git revert picked &&
398         git reset &&
399         test_must_fail git rev-parse --verify REVERT_HEAD
400 '
401
402 test_expect_success 'failed commit does not clear REVERT_HEAD' '
403         pristine_detach initial &&
404         test_must_fail git revert picked &&
405         test_must_fail git commit &&
406         test_cmp_rev picked REVERT_HEAD
407 '
408
409 test_expect_success 'successful final commit clears revert state' '
410         pristine_detach picked-signed &&
411
412         test_must_fail git revert picked-signed base &&
413         echo resolved >foo &&
414         test_path_is_file .git/sequencer/todo &&
415         git commit -a &&
416         test_path_is_missing .git/sequencer
417 '
418
419 test_expect_success 'reset after final pick clears revert state' '
420         pristine_detach picked-signed &&
421
422         test_must_fail git revert picked-signed base &&
423         echo resolved >foo &&
424         test_path_is_file .git/sequencer/todo &&
425         git reset &&
426         test_path_is_missing .git/sequencer
427 '
428
429 test_expect_success 'revert conflict, diff3 -m style' '
430         pristine_detach initial &&
431         git config merge.conflictstyle diff3 &&
432         cat <<-EOF >expected &&
433         <<<<<<< HEAD
434         a
435         ||||||| objid (picked)
436         c
437         =======
438         b
439         >>>>>>> parent of objid (picked)
440         EOF
441
442         test_must_fail git revert picked &&
443
444         sed "s/[a-f0-9]* (/objid (/" foo >actual &&
445         test_cmp expected actual
446 '
447
448 test_expect_success \
449         'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
450         pristine_detach initial &&
451         git config commit.cleanup scissors &&
452         cat >expected <<-EOF &&
453                 Revert "picked"
454
455                 This reverts commit OBJID.
456
457                 # ------------------------ >8 ------------------------
458                 # Do not modify or remove the line above.
459                 # Everything below it will be ignored.
460                 #
461                 # Conflicts:
462                 #       foo
463                 EOF
464
465         test_must_fail git revert picked &&
466
467         sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
468         test_cmp expected actual
469 '
470
471 test_expect_success \
472         'revert conflict, ensure cleanup=scissors places scissors line properly' '
473         pristine_detach initial &&
474         git config --unset commit.cleanup &&
475         cat >expected <<-EOF &&
476                 Revert "picked"
477
478                 This reverts commit OBJID.
479
480                 # ------------------------ >8 ------------------------
481                 # Do not modify or remove the line above.
482                 # Everything below it will be ignored.
483                 #
484                 # Conflicts:
485                 #       foo
486                 EOF
487
488         test_must_fail git revert --cleanup=scissors picked &&
489
490         sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
491         test_cmp expected actual
492 '
493
494 test_expect_success 'failed cherry-pick does not forget -s' '
495         pristine_detach initial &&
496         test_must_fail git cherry-pick -s picked &&
497         test_i18ngrep -e "Signed-off-by" .git/MERGE_MSG
498 '
499
500 test_expect_success 'commit after failed cherry-pick does not add duplicated -s' '
501         pristine_detach initial &&
502         test_must_fail git cherry-pick -s picked-signed &&
503         git commit -a -s &&
504         test $(git show -s >tmp && grep -c "Signed-off-by" tmp && rm tmp) = 1
505 '
506
507 test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
508         pristine_detach initial &&
509         test_must_fail git cherry-pick picked &&
510
511         git commit -a -s &&
512
513         # Do S-o-b and Conflicts appear in the right order?
514         cat <<-\EOF >expect &&
515         Signed-off-by: C O Mitter <committer@example.com>
516         # Conflicts:
517         EOF
518         grep -e "^# Conflicts:" -e "^Signed-off-by" .git/COMMIT_EDITMSG >actual &&
519         test_cmp expect actual &&
520
521         cat <<-\EOF >expected &&
522         picked
523
524         Signed-off-by: C O Mitter <committer@example.com>
525         EOF
526
527         git show -s --pretty=format:%B >actual &&
528         test_cmp expected actual
529 '
530
531 test_expect_success 'commit --amend -s places the sign-off at the right place' '
532         pristine_detach initial &&
533         test_must_fail git cherry-pick picked &&
534
535         # emulate old-style conflicts block
536         mv .git/MERGE_MSG .git/MERGE_MSG+ &&
537         sed -e "/^# Conflicts:/,\$s/^# *//" .git/MERGE_MSG+ >.git/MERGE_MSG &&
538
539         git commit -a &&
540         git commit --amend -s &&
541
542         # Do S-o-b and Conflicts appear in the right order?
543         cat <<-\EOF >expect &&
544         Signed-off-by: C O Mitter <committer@example.com>
545         Conflicts:
546         EOF
547         grep -e "^Conflicts:" -e "^Signed-off-by" .git/COMMIT_EDITMSG >actual &&
548         test_cmp expect actual
549 '
550
551 test_expect_success 'cherry-pick preserves sparse-checkout' '
552         pristine_detach initial &&
553         test_config core.sparseCheckout true &&
554         test_when_finished "
555                 echo \"/*\" >.git/info/sparse-checkout
556                 git read-tree --reset -u HEAD
557                 rm .git/info/sparse-checkout" &&
558         echo /unrelated >.git/info/sparse-checkout &&
559         git read-tree --reset -u HEAD &&
560         test_must_fail git cherry-pick -Xours picked>actual &&
561         test_i18ngrep ! "Changes not staged for commit:" actual
562 '
563
564 test_expect_success 'cherry-pick --continue remembers --keep-redundant-commits' '
565         test_when_finished "git cherry-pick --abort || :" &&
566         pristine_detach initial &&
567         test_must_fail git cherry-pick --keep-redundant-commits picked redundant &&
568         echo c >foo &&
569         git add foo &&
570         git cherry-pick --continue
571 '
572
573 test_expect_success 'cherry-pick --continue remembers --allow-empty and --allow-empty-message' '
574         test_when_finished "git cherry-pick --abort || :" &&
575         pristine_detach initial &&
576         test_must_fail git cherry-pick --allow-empty --allow-empty-message \
577                                        picked empty &&
578         echo c >foo &&
579         git add foo &&
580         git cherry-pick --continue
581 '
582
583 test_done