1#!/bin/sh
2
3test_description='Test cherry-pick continuation features
4
5 + yetanotherpick: rewrites foo to e
6 + anotherpick: rewrites foo to d
7 + picked: rewrites foo to c
8 + unrelatedpick: rewrites unrelated to reallyunrelated
9 + base: rewrites foo to b
10 + initial: writes foo as a, unrelated as unrelated
11
12'
13
14. ./test-lib.sh
15
16pristine_detach () {
17 git cherry-pick --quit &&
18 git checkout -f "$1^0" &&
19 git read-tree -u --reset HEAD &&
20 git clean -d -f -f -q -x
21}
22
23test_cmp_rev () {
24 git rev-parse --verify "$1" >expect.rev &&
25 git rev-parse --verify "$2" >actual.rev &&
26 test_cmp expect.rev actual.rev
27}
28
29test_expect_success setup '
30 echo unrelated >unrelated &&
31 git add unrelated &&
32 test_commit initial foo a &&
33 test_commit base foo b &&
34 test_commit unrelatedpick unrelated reallyunrelated &&
35 test_commit picked foo c &&
36 test_commit anotherpick foo d &&
37 test_commit yetanotherpick foo e &&
38 git config advice.detachedhead false
39
40'
41
42test_expect_success 'cherry-pick persists data on failure' '
43 pristine_detach initial &&
44 test_must_fail git cherry-pick -s base..anotherpick &&
45 test_path_is_dir .git/sequencer &&
46 test_path_is_file .git/sequencer/head &&
47 test_path_is_file .git/sequencer/todo &&
48 test_path_is_file .git/sequencer/opts
49'
50
51test_expect_success 'cherry-pick persists opts correctly' '
52 pristine_detach initial &&
53 test_must_fail git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours base..anotherpick &&
54 test_path_is_dir .git/sequencer &&
55 test_path_is_file .git/sequencer/head &&
56 test_path_is_file .git/sequencer/todo &&
57 test_path_is_file .git/sequencer/opts &&
58 echo "true" >expect &&
59 git config --file=.git/sequencer/opts --get-all options.signoff >actual &&
60 test_cmp expect actual &&
61 echo "1" >expect &&
62 git config --file=.git/sequencer/opts --get-all options.mainline >actual &&
63 test_cmp expect actual &&
64 echo "recursive" >expect &&
65 git config --file=.git/sequencer/opts --get-all options.strategy >actual &&
66 test_cmp expect actual &&
67 cat >expect <<-\EOF &&
68 patience
69 ours
70 EOF
71 git config --file=.git/sequencer/opts --get-all options.strategy-option >actual &&
72 test_cmp expect actual
73'
74
75test_expect_success 'cherry-pick cleans up sequencer state upon success' '
76 pristine_detach initial &&
77 git cherry-pick initial..picked &&
78 test_path_is_missing .git/sequencer
79'
80
81test_expect_success '--quit does not complain when no cherry-pick is in progress' '
82 pristine_detach initial &&
83 git cherry-pick --quit
84'
85
86test_expect_success '--abort requires cherry-pick in progress' '
87 pristine_detach initial &&
88 test_must_fail git cherry-pick --abort
89'
90
91test_expect_success '--quit cleans up sequencer state' '
92 pristine_detach initial &&
93 test_must_fail git cherry-pick base..picked &&
94 git cherry-pick --quit &&
95 test_path_is_missing .git/sequencer
96'
97
98test_expect_success '--quit keeps HEAD and conflicted index intact' '
99 pristine_detach initial &&
100 cat >expect <<-\EOF &&
101 OBJID
102 :100644 100644 OBJID OBJID M unrelated
103 OBJID
104 :000000 100644 OBJID OBJID A foo
105 :000000 100644 OBJID OBJID A unrelated
106 EOF
107 test_must_fail git cherry-pick base..picked &&
108 git cherry-pick --quit &&
109 test_path_is_missing .git/sequencer &&
110 test_must_fail git update-index --refresh &&
111 {
112 git rev-list HEAD |
113 git diff-tree --root --stdin |
114 sed "s/$_x40/OBJID/g"
115 } >actual &&
116 test_cmp expect actual
117'
118
119test_expect_success '--abort to cancel multiple cherry-pick' '
120 pristine_detach initial &&
121 test_must_fail git cherry-pick base..anotherpick &&
122 git cherry-pick --abort &&
123 test_path_is_missing .git/sequencer &&
124 test_cmp_rev initial HEAD &&
125 git update-index --refresh &&
126 git diff-index --exit-code HEAD
127'
128
129test_expect_success '--abort to cancel single cherry-pick' '
130 pristine_detach initial &&
131 test_must_fail git cherry-pick picked &&
132 git cherry-pick --abort &&
133 test_path_is_missing .git/sequencer &&
134 test_cmp_rev initial HEAD &&
135 git update-index --refresh &&
136 git diff-index --exit-code HEAD
137'
138
139test_expect_success 'cherry-pick --abort to cancel multiple revert' '
140 pristine_detach anotherpick &&
141 test_must_fail git revert base..picked &&
142 git cherry-pick --abort &&
143 test_path_is_missing .git/sequencer &&
144 test_cmp_rev anotherpick HEAD &&
145 git update-index --refresh &&
146 git diff-index --exit-code HEAD
147'
148
149test_expect_success 'revert --abort works, too' '
150 pristine_detach anotherpick &&
151 test_must_fail git revert base..picked &&
152 git revert --abort &&
153 test_path_is_missing .git/sequencer &&
154 test_cmp_rev anotherpick HEAD
155'
156
157test_expect_success '--abort to cancel single revert' '
158 pristine_detach anotherpick &&
159 test_must_fail git revert picked &&
160 git revert --abort &&
161 test_path_is_missing .git/sequencer &&
162 test_cmp_rev anotherpick HEAD &&
163 git update-index --refresh &&
164 git diff-index --exit-code HEAD
165'
166
167test_expect_success '--abort keeps unrelated change, easy case' '
168 pristine_detach unrelatedpick &&
169 echo changed >expect &&
170 test_must_fail git cherry-pick picked..yetanotherpick &&
171 echo changed >unrelated &&
172 git cherry-pick --abort &&
173 test_cmp expect unrelated
174'
175
176test_expect_success '--abort refuses to clobber unrelated change, harder case' '
177 pristine_detach initial &&
178 echo changed >expect &&
179 test_must_fail git cherry-pick base..anotherpick &&
180 echo changed >unrelated &&
181 test_must_fail git cherry-pick --abort &&
182 test_cmp expect unrelated &&
183 git rev-list HEAD >log &&
184 test_line_count = 2 log &&
185 test_must_fail git update-index --refresh &&
186
187 git checkout unrelated &&
188 git cherry-pick --abort &&
189 test_cmp_rev initial HEAD
190'
191
192test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '
193 pristine_detach initial &&
194 test_must_fail git cherry-pick base..picked &&
195 test_path_is_missing .git/sequencer &&
196 echo "resolved" >foo &&
197 git add foo &&
198 git commit &&
199 {
200 git rev-list HEAD |
201 git diff-tree --root --stdin |
202 sed "s/$_x40/OBJID/g"
203 } >actual &&
204 cat >expect <<-\EOF &&
205 OBJID
206 :100644 100644 OBJID OBJID M foo
207 OBJID
208 :100644 100644 OBJID OBJID M unrelated
209 OBJID
210 :000000 100644 OBJID OBJID A foo
211 :000000 100644 OBJID OBJID A unrelated
212 EOF
213 test_cmp expect actual
214'
215
216test_expect_failure '--abort after last commit in sequence' '
217 pristine_detach initial &&
218 test_must_fail git cherry-pick base..picked &&
219 git cherry-pick --abort &&
220 test_path_is_missing .git/sequencer &&
221 test_cmp_rev initial HEAD &&
222 git update-index --refresh &&
223 git diff-index --exit-code HEAD
224'
225
226test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
227 pristine_detach initial &&
228 test_must_fail git cherry-pick base..anotherpick &&
229 test-chmtime -v +0 .git/sequencer >expect &&
230 test_must_fail git cherry-pick unrelatedpick &&
231 test-chmtime -v +0 .git/sequencer >actual &&
232 test_cmp expect actual
233'
234
235test_expect_success '--continue complains when no cherry-pick is in progress' '
236 pristine_detach initial &&
237 test_must_fail git cherry-pick --continue
238'
239
240test_expect_success '--continue complains when there are unresolved conflicts' '
241 pristine_detach initial &&
242 test_must_fail git cherry-pick base..anotherpick &&
243 test_must_fail git cherry-pick --continue
244'
245
246test_expect_success '--continue continues after conflicts are resolved' '
247 pristine_detach initial &&
248 test_must_fail git cherry-pick base..anotherpick &&
249 echo "c" >foo &&
250 git add foo &&
251 git commit &&
252 git cherry-pick --continue &&
253 test_path_is_missing .git/sequencer &&
254 {
255 git rev-list HEAD |
256 git diff-tree --root --stdin |
257 sed "s/$_x40/OBJID/g"
258 } >actual &&
259 cat >expect <<-\EOF &&
260 OBJID
261 :100644 100644 OBJID OBJID M foo
262 OBJID
263 :100644 100644 OBJID OBJID M foo
264 OBJID
265 :100644 100644 OBJID OBJID M unrelated
266 OBJID
267 :000000 100644 OBJID OBJID A foo
268 :000000 100644 OBJID OBJID A unrelated
269 EOF
270 test_cmp expect actual
271'
272
273test_expect_success '--continue respects opts' '
274 pristine_detach initial &&
275 test_must_fail git cherry-pick -x base..anotherpick &&
276 echo "c" >foo &&
277 git add foo &&
278 git commit &&
279 git cherry-pick --continue &&
280 test_path_is_missing .git/sequencer &&
281 git cat-file commit HEAD >anotherpick_msg &&
282 git cat-file commit HEAD~1 >picked_msg &&
283 git cat-file commit HEAD~2 >unrelatedpick_msg &&
284 git cat-file commit HEAD~3 >initial_msg &&
285 test_must_fail grep "cherry picked from" initial_msg &&
286 grep "cherry picked from" unrelatedpick_msg &&
287 grep "cherry picked from" picked_msg &&
288 grep "cherry picked from" anotherpick_msg
289'
290
291test_expect_success '--signoff is not automatically propagated to resolved conflict' '
292 pristine_detach initial &&
293 test_must_fail git cherry-pick --signoff base..anotherpick &&
294 echo "c" >foo &&
295 git add foo &&
296 git commit &&
297 git cherry-pick --continue &&
298 test_path_is_missing .git/sequencer &&
299 git cat-file commit HEAD >anotherpick_msg &&
300 git cat-file commit HEAD~1 >picked_msg &&
301 git cat-file commit HEAD~2 >unrelatedpick_msg &&
302 git cat-file commit HEAD~3 >initial_msg &&
303 test_must_fail grep "Signed-off-by:" initial_msg &&
304 grep "Signed-off-by:" unrelatedpick_msg &&
305 test_must_fail grep "Signed-off-by:" picked_msg &&
306 grep "Signed-off-by:" anotherpick_msg
307'
308
309test_expect_success 'malformed instruction sheet 1' '
310 pristine_detach initial &&
311 test_must_fail git cherry-pick base..anotherpick &&
312 echo "resolved" >foo &&
313 git add foo &&
314 git commit &&
315 sed "s/pick /pick/" .git/sequencer/todo >new_sheet &&
316 cp new_sheet .git/sequencer/todo &&
317 test_must_fail git cherry-pick --continue
318'
319
320test_expect_success 'malformed instruction sheet 2' '
321 pristine_detach initial &&
322 test_must_fail git cherry-pick base..anotherpick &&
323 echo "resolved" >foo &&
324 git add foo &&
325 git commit &&
326 sed "s/pick/revert/" .git/sequencer/todo >new_sheet &&
327 cp new_sheet .git/sequencer/todo &&
328 test_must_fail git cherry-pick --continue
329'
330
331test_done