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