1#!/bin/sh
2#
3# Copyright (c) 2005 Junio C Hamano
4#
5
6test_description='Two way merge with read-tree -m $H $M
7
8This test tries two-way merge (aka fast-forward with carry forward).
9
10There is the head (called H) and another commit (called M), which is
11simply ahead of H. The index and the work tree contains a state that
12is derived from H, but may also have local changes. This test checks
13all the combinations described in the two-tree merge "carry forward"
14rules, found in <Documentation/git read-tree.txt>.
15
16In the test, these paths are used:
17 bozbar - in H, stays in M, modified from bozbar to gnusto
18 frotz - not in H added in M
19 nitfol - in H, stays in M unmodified
20 rezrov - in H, deleted in M
21 yomin - not in H nor M
22'
23. ./test-lib.sh
24. "$TEST_DIRECTORY"/lib-read-tree.sh
25
26read_tree_twoway () {
27 git read-tree -m "$1" "$2" && git ls-files --stage
28}
29
30compare_change () {
31 sed -n >current \
32 -e '/^--- /d; /^+++ /d; /^@@ /d;' \
33 -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /p' \
34 "$1"
35 test_cmp expected current
36}
37
38check_cache_at () {
39 clean_if_empty=$(git diff-files -- "$1")
40 case "$clean_if_empty" in
41 '') echo "$1: clean" ;;
42 ?*) echo "$1: dirty" ;;
43 esac
44 case "$2,$clean_if_empty" in
45 clean,) : ;;
46 clean,?*) false ;;
47 dirty,) false ;;
48 dirty,?*) : ;;
49 esac
50}
51
52cat >bozbar-old <<\EOF
53This is a sample file used in two-way fast-forward merge
54tests. Its second line ends with a magic word bozbar
55which will be modified by the merged head to gnusto.
56It has some extra lines so that external tools can
57successfully merge independent changes made to later
58lines (such as this one), avoiding line conflicts.
59EOF
60
61sed -e 's/bozbar/gnusto (earlier bozbar)/' bozbar-old >bozbar-new
62
63test_expect_success \
64 setup \
65 'echo frotz >frotz &&
66 echo nitfol >nitfol &&
67 cat bozbar-old >bozbar &&
68 echo rezrov >rezrov &&
69 echo yomin >yomin &&
70 git update-index --add nitfol bozbar rezrov &&
71 treeH=$(git write-tree) &&
72 echo treeH $treeH &&
73 git ls-tree $treeH &&
74
75 cat bozbar-new >bozbar &&
76 git update-index --add frotz bozbar --force-remove rezrov &&
77 git ls-files --stage >M.out &&
78 treeM=$(git write-tree) &&
79 echo treeM $treeM &&
80 git ls-tree $treeM &&
81 git diff-tree $treeH $treeM'
82
83test_expect_success \
84 '1, 2, 3 - no carry forward' \
85 'rm -f .git/index &&
86 read_tree_twoway $treeH $treeM &&
87 git ls-files --stage >1-3.out &&
88 test_cmp M.out 1-3.out &&
89 check_cache_at bozbar dirty &&
90 check_cache_at frotz dirty &&
91 check_cache_at nitfol dirty'
92
93echo '+100644 X 0 yomin' >expected
94
95test_expect_success \
96 '4 - carry forward local addition.' \
97 'rm -f .git/index &&
98 read_tree_must_succeed $treeH &&
99 git checkout-index -u -f -q -a &&
100 git update-index --add yomin &&
101 read_tree_twoway $treeH $treeM &&
102 git ls-files --stage >4.out &&
103 test_must_fail git diff --no-index M.out 4.out >4diff.out &&
104 compare_change 4diff.out expected &&
105 check_cache_at yomin clean'
106
107test_expect_success \
108 '5 - carry forward local addition.' \
109 'rm -f .git/index &&
110 read_tree_must_succeed $treeH &&
111 git checkout-index -u -f -q -a &&
112 echo yomin >yomin &&
113 git update-index --add yomin &&
114 echo yomin yomin >yomin &&
115 read_tree_twoway $treeH $treeM &&
116 git ls-files --stage >5.out &&
117 test_must_fail git diff --no-index M.out 5.out >5diff.out &&
118 compare_change 5diff.out expected &&
119 check_cache_at yomin dirty'
120
121test_expect_success \
122 '6 - local addition already has the same.' \
123 'rm -f .git/index &&
124 read_tree_must_succeed $treeH &&
125 git checkout-index -u -f -q -a &&
126 git update-index --add frotz &&
127 read_tree_twoway $treeH $treeM &&
128 git ls-files --stage >6.out &&
129 test_cmp M.out 6.out &&
130 check_cache_at frotz clean'
131
132test_expect_success \
133 '7 - local addition already has the same.' \
134 'rm -f .git/index &&
135 read_tree_must_succeed $treeH &&
136 git checkout-index -u -f -q -a &&
137 echo frotz >frotz &&
138 git update-index --add frotz &&
139 echo frotz frotz >frotz &&
140 read_tree_twoway $treeH $treeM &&
141 git ls-files --stage >7.out &&
142 test_cmp M.out 7.out &&
143 check_cache_at frotz dirty'
144
145test_expect_success \
146 '8 - conflicting addition.' \
147 'rm -f .git/index &&
148 read_tree_must_succeed $treeH &&
149 git checkout-index -u -f -q -a &&
150 echo frotz frotz >frotz &&
151 git update-index --add frotz &&
152 if read_tree_twoway $treeH $treeM; then false; else :; fi'
153
154test_expect_success \
155 '9 - conflicting addition.' \
156 'rm -f .git/index &&
157 read_tree_must_succeed $treeH &&
158 git checkout-index -u -f -q -a &&
159 echo frotz frotz >frotz &&
160 git update-index --add frotz &&
161 echo frotz >frotz &&
162 if read_tree_twoway $treeH $treeM; then false; else :; fi'
163
164test_expect_success \
165 '10 - path removed.' \
166 'rm -f .git/index &&
167 read_tree_must_succeed $treeH &&
168 git checkout-index -u -f -q -a &&
169 echo rezrov >rezrov &&
170 git update-index --add rezrov &&
171 read_tree_twoway $treeH $treeM &&
172 git ls-files --stage >10.out &&
173 test_cmp M.out 10.out'
174
175test_expect_success \
176 '11 - dirty path removed.' \
177 'rm -f .git/index &&
178 read_tree_must_succeed $treeH &&
179 git checkout-index -u -f -q -a &&
180 echo rezrov >rezrov &&
181 git update-index --add rezrov &&
182 echo rezrov rezrov >rezrov &&
183 if read_tree_twoway $treeH $treeM; then false; else :; fi'
184
185test_expect_success \
186 '12 - unmatching local changes being removed.' \
187 'rm -f .git/index &&
188 read_tree_must_succeed $treeH &&
189 git checkout-index -u -f -q -a &&
190 echo rezrov rezrov >rezrov &&
191 git update-index --add rezrov &&
192 if read_tree_twoway $treeH $treeM; then false; else :; fi'
193
194test_expect_success \
195 '13 - unmatching local changes being removed.' \
196 'rm -f .git/index &&
197 read_tree_must_succeed $treeH &&
198 git checkout-index -u -f -q -a &&
199 echo rezrov rezrov >rezrov &&
200 git update-index --add rezrov &&
201 echo rezrov >rezrov &&
202 if read_tree_twoway $treeH $treeM; then false; else :; fi'
203
204cat >expected <<EOF
205-100644 X 0 nitfol
206+100644 X 0 nitfol
207EOF
208
209test_expect_success \
210 '14 - unchanged in two heads.' \
211 'rm -f .git/index &&
212 read_tree_must_succeed $treeH &&
213 git checkout-index -u -f -q -a &&
214 echo nitfol nitfol >nitfol &&
215 git update-index --add nitfol &&
216 read_tree_twoway $treeH $treeM &&
217 git ls-files --stage >14.out &&
218 test_must_fail git diff --no-index M.out 14.out >14diff.out &&
219 compare_change 14diff.out expected &&
220 check_cache_at nitfol clean'
221
222test_expect_success \
223 '15 - unchanged in two heads.' \
224 'rm -f .git/index &&
225 read_tree_must_succeed $treeH &&
226 git checkout-index -u -f -q -a &&
227 echo nitfol nitfol >nitfol &&
228 git update-index --add nitfol &&
229 echo nitfol nitfol nitfol >nitfol &&
230 read_tree_twoway $treeH $treeM &&
231 git ls-files --stage >15.out &&
232 test_must_fail git diff --no-index M.out 15.out >15diff.out &&
233 compare_change 15diff.out expected &&
234 check_cache_at nitfol dirty'
235
236test_expect_success \
237 '16 - conflicting local change.' \
238 'rm -f .git/index &&
239 read_tree_must_succeed $treeH &&
240 git checkout-index -u -f -q -a &&
241 echo bozbar bozbar >bozbar &&
242 git update-index --add bozbar &&
243 if read_tree_twoway $treeH $treeM; then false; else :; fi'
244
245test_expect_success \
246 '17 - conflicting local change.' \
247 'rm -f .git/index &&
248 read_tree_must_succeed $treeH &&
249 git checkout-index -u -f -q -a &&
250 echo bozbar bozbar >bozbar &&
251 git update-index --add bozbar &&
252 echo bozbar bozbar bozbar >bozbar &&
253 if read_tree_twoway $treeH $treeM; then false; else :; fi'
254
255test_expect_success \
256 '18 - local change already having a good result.' \
257 'rm -f .git/index &&
258 read_tree_must_succeed $treeH &&
259 git checkout-index -u -f -q -a &&
260 cat bozbar-new >bozbar &&
261 git update-index --add bozbar &&
262 read_tree_twoway $treeH $treeM &&
263 git ls-files --stage >18.out &&
264 test_cmp M.out 18.out &&
265 check_cache_at bozbar clean'
266
267test_expect_success \
268 '19 - local change already having a good result, further modified.' \
269 'rm -f .git/index &&
270 read_tree_must_succeed $treeH &&
271 git checkout-index -u -f -q -a &&
272 cat bozbar-new >bozbar &&
273 git update-index --add bozbar &&
274 echo gnusto gnusto >bozbar &&
275 read_tree_twoway $treeH $treeM &&
276 git ls-files --stage >19.out &&
277 test_cmp M.out 19.out &&
278 check_cache_at bozbar dirty'
279
280test_expect_success \
281 '20 - no local change, use new tree.' \
282 'rm -f .git/index &&
283 read_tree_must_succeed $treeH &&
284 git checkout-index -u -f -q -a &&
285 cat bozbar-old >bozbar &&
286 git update-index --add bozbar &&
287 read_tree_twoway $treeH $treeM &&
288 git ls-files --stage >20.out &&
289 test_cmp M.out 20.out &&
290 check_cache_at bozbar dirty'
291
292test_expect_success \
293 '21 - no local change, dirty cache.' \
294 'rm -f .git/index &&
295 read_tree_must_succeed $treeH &&
296 git checkout-index -u -f -q -a &&
297 cat bozbar-old >bozbar &&
298 git update-index --add bozbar &&
299 echo gnusto gnusto >bozbar &&
300 if read_tree_twoway $treeH $treeM; then false; else :; fi'
301
302# This fails with straight two-way fast-forward.
303test_expect_success \
304 '22 - local change cache updated.' \
305 'rm -f .git/index &&
306 read_tree_must_succeed $treeH &&
307 git checkout-index -u -f -q -a &&
308 sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
309 git update-index --add bozbar &&
310 if read_tree_twoway $treeH $treeM; then false; else :; fi'
311
312# Also make sure we did not break DF vs DF/DF case.
313test_expect_success \
314 'DF vs DF/DF case setup.' \
315 'rm -f .git/index &&
316 echo DF >DF &&
317 git update-index --add DF &&
318 treeDF=$(git write-tree) &&
319 echo treeDF $treeDF &&
320 git ls-tree $treeDF &&
321
322 rm -f DF &&
323 mkdir DF &&
324 echo DF/DF >DF/DF &&
325 git update-index --add --remove DF DF/DF &&
326 treeDFDF=$(git write-tree) &&
327 echo treeDFDF $treeDFDF &&
328 git ls-tree $treeDFDF &&
329 git ls-files --stage >DFDF.out'
330
331test_expect_success \
332 'DF vs DF/DF case test.' \
333 'rm -f .git/index &&
334 rm -fr DF &&
335 echo DF >DF &&
336 git update-index --add DF &&
337 read_tree_twoway $treeDF $treeDFDF &&
338 git ls-files --stage >DFDFcheck.out &&
339 test_cmp DFDF.out DFDFcheck.out &&
340 check_cache_at DF/DF dirty &&
341 :'
342
343test_expect_success \
344 'a/b (untracked) vs a case setup.' \
345 'rm -f .git/index &&
346 : >a &&
347 git update-index --add a &&
348 treeM=$(git write-tree) &&
349 echo treeM $treeM &&
350 git ls-tree $treeM &&
351 git ls-files --stage >treeM.out &&
352
353 rm -f a &&
354 git update-index --remove a &&
355 mkdir a &&
356 : >a/b &&
357 treeH=$(git write-tree) &&
358 echo treeH $treeH &&
359 git ls-tree $treeH'
360
361test_expect_success \
362 'a/b (untracked) vs a, plus c/d case test.' \
363 'read_tree_u_must_fail -u -m "$treeH" "$treeM" &&
364 git ls-files --stage &&
365 test -f a/b'
366
367test_expect_success \
368 'a/b vs a, plus c/d case setup.' \
369 'rm -f .git/index &&
370 rm -fr a &&
371 : >a &&
372 mkdir c &&
373 : >c/d &&
374 git update-index --add a c/d &&
375 treeM=$(git write-tree) &&
376 echo treeM $treeM &&
377 git ls-tree $treeM &&
378 git ls-files --stage >treeM.out &&
379
380 rm -f a &&
381 mkdir a &&
382 : >a/b &&
383 git update-index --add --remove a a/b &&
384 treeH=$(git write-tree) &&
385 echo treeH $treeH &&
386 git ls-tree $treeH'
387
388test_expect_success \
389 'a/b vs a, plus c/d case test.' \
390 'read_tree_u_must_succeed -u -m "$treeH" "$treeM" &&
391 git ls-files --stage | tee >treeMcheck.out &&
392 test_cmp treeM.out treeMcheck.out'
393
394test_expect_success '-m references the correct modified tree' '
395 echo >file-a &&
396 echo >file-b &&
397 git add file-a file-b &&
398 git commit -a -m "test for correct modified tree" &&
399 git branch initial-mod &&
400 echo b >file-b &&
401 git commit -a -m "B" &&
402 echo a >file-a &&
403 git add file-a &&
404 git ls-tree $(git write-tree) file-a >expect &&
405 read_tree_must_succeed -m HEAD initial-mod &&
406 git ls-tree $(git write-tree) file-a >actual &&
407 test_cmp expect actual
408'
409
410test_done