Git fork
1#!/bin/sh
2
3test_description='git apply --3way'
4
5GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8. ./test-lib.sh
9
10print_sanitized_conflicted_diff () {
11 git diff HEAD >diff.raw &&
12 sed -e '
13 /^index /d
14 s/^\(+[<>|][<>|][<>|][<>|]*\) .*/\1/
15 ' diff.raw
16}
17
18test_expect_success setup '
19 test_tick &&
20 test_write_lines 1 2 3 4 5 6 7 >one &&
21 cat one >two &&
22 git add one two &&
23 git commit -m initial &&
24
25 git branch side &&
26
27 test_tick &&
28 test_write_lines 1 two 3 4 5 six 7 >one &&
29 test_write_lines 1 two 3 4 5 6 7 >two &&
30 git commit -a -m main &&
31
32 git checkout side &&
33 test_write_lines 1 2 3 4 five 6 7 >one &&
34 test_write_lines 1 2 3 4 five 6 7 >two &&
35 git commit -a -m side &&
36
37 git checkout main
38'
39
40test_expect_success 'apply without --3way' '
41 git diff side^ side >P.diff &&
42
43 # should fail to apply
44 git reset --hard &&
45 git checkout main^0 &&
46 test_must_fail git apply --index P.diff &&
47 # should leave things intact
48 git diff-files --exit-code &&
49 git diff-index --exit-code --cached HEAD
50'
51
52test_apply_with_3way () {
53 # Merging side should be similar to applying this patch
54 git diff ...side >P.diff &&
55
56 # The corresponding conflicted merge
57 git reset --hard &&
58 git checkout main^0 &&
59 test_must_fail git merge --no-commit side &&
60 git ls-files -s >expect.ls &&
61 print_sanitized_conflicted_diff >expect.diff &&
62
63 # should fail to apply
64 git reset --hard &&
65 git checkout main^0 &&
66 test_must_fail git apply --index --3way P.diff &&
67 git ls-files -s >actual.ls &&
68 print_sanitized_conflicted_diff >actual.diff &&
69
70 # The result should resemble the corresponding merge
71 test_cmp expect.ls actual.ls &&
72 test_cmp expect.diff actual.diff
73}
74
75test_expect_success 'apply with --3way' '
76 test_apply_with_3way
77'
78
79test_expect_success 'apply with --3way with merge.conflictStyle = diff3' '
80 test_config merge.conflictStyle diff3 &&
81 test_apply_with_3way
82'
83
84test_apply_with_3way_favoritism () {
85 apply_arg=$1
86 merge_arg=$2
87
88 # Merging side should be similar to applying this patch
89 git diff ...side >P.diff &&
90
91 # The corresponding conflicted merge
92 git reset --hard &&
93 git checkout main^0 &&
94 git merge --no-commit $merge_arg side &&
95 git ls-files -s >expect.ls &&
96 print_sanitized_conflicted_diff >expect.diff &&
97
98 # should apply successfully
99 git reset --hard &&
100 git checkout main^0 &&
101 git apply --index --3way $apply_arg P.diff &&
102 git ls-files -s >actual.ls &&
103 print_sanitized_conflicted_diff >actual.diff &&
104
105 # The result should resemble the corresponding merge
106 test_cmp expect.ls actual.ls &&
107 test_cmp expect.diff actual.diff
108}
109
110test_expect_success 'apply with --3way --ours' '
111 test_apply_with_3way_favoritism --ours -Xours
112'
113
114test_expect_success 'apply with --3way --theirs' '
115 test_apply_with_3way_favoritism --theirs -Xtheirs
116'
117
118test_expect_success 'apply with --3way --union' '
119 echo "* merge=union" >.gitattributes &&
120 test_apply_with_3way_favoritism --union &&
121 rm .gitattributes
122'
123
124test_expect_success 'apply with --3way with rerere enabled' '
125 test_config rerere.enabled true &&
126
127 # Merging side should be similar to applying this patch
128 git diff ...side >P.diff &&
129
130 # The corresponding conflicted merge
131 git reset --hard &&
132 git checkout main^0 &&
133 test_must_fail git merge --no-commit side &&
134
135 # Manually resolve and record the resolution
136 test_write_lines 1 two 3 4 five six 7 >one &&
137 git rerere &&
138 cat one >expect &&
139
140 # should fail to apply
141 git reset --hard &&
142 git checkout main^0 &&
143 test_must_fail git apply --index --3way P.diff &&
144
145 # but rerere should have replayed the recorded resolution
146 test_cmp expect one
147'
148
149test_expect_success 'apply -3 with add/add conflict setup' '
150 git reset --hard &&
151
152 git checkout -b adder &&
153 test_write_lines 1 2 3 4 5 6 7 >three &&
154 test_write_lines 1 2 3 4 5 6 7 >four &&
155 git add three four &&
156 git commit -m "add three and four" &&
157
158 git checkout -b another adder^ &&
159 test_write_lines 1 2 3 4 5 6 7 >three &&
160 test_write_lines 1 2 3 four 5 6 7 >four &&
161 git add three four &&
162 git commit -m "add three and four" &&
163
164 # Merging another should be similar to applying this patch
165 git diff adder...another >P.diff &&
166
167 git checkout adder^0 &&
168 test_must_fail git merge --no-commit another &&
169 git ls-files -s >expect.ls &&
170 print_sanitized_conflicted_diff >expect.diff
171'
172
173test_expect_success 'apply -3 with add/add conflict' '
174 # should fail to apply ...
175 git reset --hard &&
176 git checkout adder^0 &&
177 test_must_fail git apply --index --3way P.diff &&
178 # ... and leave conflicts in the index and in the working tree
179 git ls-files -s >actual.ls &&
180 print_sanitized_conflicted_diff >actual.diff &&
181
182 # The result should resemble the corresponding merge
183 test_cmp expect.ls actual.ls &&
184 test_cmp expect.diff actual.diff
185'
186
187test_expect_success 'apply -3 with add/add conflict (dirty working tree)' '
188 # should fail to apply ...
189 git reset --hard &&
190 git checkout adder^0 &&
191 echo >>four &&
192 cat four >four.save &&
193 cat three >three.save &&
194 git ls-files -s >expect.ls &&
195 test_must_fail git apply --index --3way P.diff &&
196 # ... and should not touch anything
197 git ls-files -s >actual.ls &&
198 test_cmp expect.ls actual.ls &&
199 test_cmp four.save four &&
200 test_cmp three.save three
201'
202
203test_expect_success 'apply -3 with ambiguous repeating file' '
204 git reset --hard &&
205 test_write_lines 1 2 1 2 1 2 1 2 1 2 1 >one_two_repeat &&
206 git add one_two_repeat &&
207 git commit -m "init one" &&
208 test_write_lines 1 2 1 2 1 2 1 2 one 2 1 >one_two_repeat &&
209 git commit -a -m "change one" &&
210
211 git diff HEAD~ >Repeat.diff &&
212 git reset --hard HEAD~ &&
213
214 test_write_lines 1 2 1 2 1 2 one 2 1 2 one >one_two_repeat &&
215 git commit -a -m "change surrounding one" &&
216
217 git apply --index --3way Repeat.diff &&
218 test_write_lines 1 2 1 2 1 2 one 2 one 2 one >expect &&
219
220 test_cmp expect one_two_repeat
221'
222
223test_expect_success 'apply with --3way --cached clean apply' '
224 # Merging side should be similar to applying this patch
225 git diff ...side >P.diff &&
226
227 # The corresponding cleanly applied merge
228 git reset --hard &&
229 git checkout main~ &&
230 git merge --no-commit side &&
231 git ls-files -s >expect.ls &&
232
233 # should succeed
234 git reset --hard &&
235 git checkout main~ &&
236 git apply --cached --3way P.diff &&
237 git ls-files -s >actual.ls &&
238 print_sanitized_conflicted_diff >actual.diff &&
239
240 # The cache should resemble the corresponding merge
241 # (both files at stage #0)
242 test_cmp expect.ls actual.ls &&
243 # However the working directory should not change
244 >expect.diff &&
245 test_cmp expect.diff actual.diff
246'
247
248test_expect_success 'apply with --3way --cached and conflicts' '
249 # Merging side should be similar to applying this patch
250 git diff ...side >P.diff &&
251
252 # The corresponding conflicted merge
253 git reset --hard &&
254 git checkout main^0 &&
255 test_must_fail git merge --no-commit side &&
256 git ls-files -s >expect.ls &&
257
258 # should fail to apply
259 git reset --hard &&
260 git checkout main^0 &&
261 test_must_fail git apply --cached --3way P.diff &&
262 git ls-files -s >actual.ls &&
263 print_sanitized_conflicted_diff >actual.diff &&
264
265 # The cache should resemble the corresponding merge
266 # (one file at stage #0, one file at stages #1 #2 #3)
267 test_cmp expect.ls actual.ls &&
268 # However the working directory should not change
269 >expect.diff &&
270 test_cmp expect.diff actual.diff
271'
272
273test_expect_success 'apply binary file patch' '
274 git reset --hard main &&
275 cp "$TEST_DIRECTORY/test-binary-1.png" bin.png &&
276 git add bin.png &&
277 git commit -m "add binary file" &&
278
279 cp "$TEST_DIRECTORY/test-binary-2.png" bin.png &&
280
281 git diff --binary >bin.diff &&
282 git reset --hard &&
283
284 # Apply must succeed.
285 git apply bin.diff
286'
287
288test_expect_success 'apply binary file patch with 3way' '
289 git reset --hard main &&
290 cp "$TEST_DIRECTORY/test-binary-1.png" bin.png &&
291 git add bin.png &&
292 git commit -m "add binary file" &&
293
294 cp "$TEST_DIRECTORY/test-binary-2.png" bin.png &&
295
296 git diff --binary >bin.diff &&
297 git reset --hard &&
298
299 # Apply must succeed.
300 git apply --3way --index bin.diff
301'
302
303test_expect_success 'apply full-index patch with 3way' '
304 git reset --hard main &&
305 cp "$TEST_DIRECTORY/test-binary-1.png" bin.png &&
306 git add bin.png &&
307 git commit -m "add binary file" &&
308
309 cp "$TEST_DIRECTORY/test-binary-2.png" bin.png &&
310
311 git diff --full-index >bin.diff &&
312 git reset --hard &&
313
314 # Apply must succeed.
315 git apply --3way --index bin.diff
316'
317
318test_expect_success 'apply delete then new patch with 3way' '
319 git reset --hard main &&
320 test_write_lines 2 > delnew &&
321 git add delnew &&
322 git diff --cached >> new.patch &&
323 git reset --hard &&
324 test_write_lines 1 > delnew &&
325 git add delnew &&
326 git commit -m "delnew" &&
327 rm delnew &&
328 git diff >> delete-then-new.patch &&
329 cat new.patch >> delete-then-new.patch &&
330
331 git checkout -- . &&
332 # Apply must succeed.
333 git apply --3way delete-then-new.patch
334'
335
336test_done