Merge branch 'nd/misc-cleanups' into maint
[git] / t / t3510-cherry-pick-sequence.sh
1 #!/bin/sh
2
3 test_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
16 pristine_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
23 test_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
29 test_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
42 test_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
51 test_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
75 test_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
81 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
82         pristine_detach initial &&
83         git cherry-pick --quit
84 '
85
86 test_expect_success '--abort requires cherry-pick in progress' '
87         pristine_detach initial &&
88         test_must_fail git cherry-pick --abort
89 '
90
91 test_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
98 test_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
119 test_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
129 test_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
139 test_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
149 test_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
157 test_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
167 test_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
176 test_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
192 test_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
216 test_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
226 test_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
235 test_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
240 test_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
246 test_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
273 test_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
291 test_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
309 test_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
320 test_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
331 test_done