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