directory rename detection: basic testcases

Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Apr 19, 2018 at 10:57 UTC 04550ab56f3191a27cb8e4f10a7398b396094f58
1 file changed +442
t/t6043-merge-rename-directories.sh new
+442
@@ -0,0 +1,442 @@
1 +#!/bin/sh
2 +
3 +test_description="recursive merge with directory renames"
4 +# includes checking of many corner cases, with a similar methodology to:
5 +# t6042: corner cases with renames but not criss-cross merges
6 +# t6036: corner cases with both renames and criss-cross merges
7 +#
8 +# The setup for all of them, pictorially, is:
9 +#
10 +# A
11 +# o
12 +# / \
13 +# O o ?
14 +# \ /
15 +# o
16 +# B
17 +#
18 +# To help make it easier to follow the flow of tests, they have been
19 +# divided into sections and each test will start with a quick explanation
20 +# of what commits O, A, and B contain.
21 +#
22 +# Notation:
23 +# z/{b,c} means files z/b and z/c both exist
24 +# x/d_1 means file x/d exists with content d1. (Purpose of the
25 +# underscore notation is to differentiate different
26 +# files that might be renamed into each other's paths.)
27 +
28 +. ./test-lib.sh
29 +
30 +
31 +###########################################################################
32 +# SECTION 1: Basic cases we should be able to handle
33 +###########################################################################
34 +
35 +# Testcase 1a, Basic directory rename.
36 +# Commit O: z/{b,c}
37 +# Commit A: y/{b,c}
38 +# Commit B: z/{b,c,d,e/f}
39 +# Expected: y/{b,c,d,e/f}
40 +
41 +test_expect_success '1a-setup: Simple directory rename detection' '
42 + test_create_repo 1a &&
43 + (
44 + cd 1a &&
45 +
46 + mkdir z &&
47 + echo b >z/b &&
48 + echo c >z/c &&
49 + git add z &&
50 + test_tick &&
51 + git commit -m "O" &&
52 +
53 + git branch O &&
54 + git branch A &&
55 + git branch B &&
56 +
57 + git checkout A &&
58 + git mv z y &&
59 + test_tick &&
60 + git commit -m "A" &&
61 +
62 + git checkout B &&
63 + echo d >z/d &&
64 + mkdir z/e &&
65 + echo f >z/e/f &&
66 + git add z/d z/e/f &&
67 + test_tick &&
68 + git commit -m "B"
69 + )
70 +'
71 +
72 +test_expect_failure '1a-check: Simple directory rename detection' '
73 + (
74 + cd 1a &&
75 +
76 + git checkout A^0 &&
77 +
78 + git merge -s recursive B^0 &&
79 +
80 + git ls-files -s >out &&
81 + test_line_count = 4 out &&
82 +
83 + git rev-parse >actual \
84 + HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e/f &&
85 + git rev-parse >expect \
86 + O:z/b O:z/c B:z/d B:z/e/f &&
87 + test_cmp expect actual &&
88 +
89 + git hash-object y/d >actual &&
90 + git rev-parse B:z/d >expect &&
91 + test_cmp expect actual &&
92 +
93 + test_must_fail git rev-parse HEAD:z/d &&
94 + test_must_fail git rev-parse HEAD:z/e/f &&
95 + test_path_is_missing z/d &&
96 + test_path_is_missing z/e/f
97 + )
98 +'
99 +
100 +# Testcase 1b, Merge a directory with another
101 +# Commit O: z/{b,c}, y/d
102 +# Commit A: z/{b,c,e}, y/d
103 +# Commit B: y/{b,c,d}
104 +# Expected: y/{b,c,d,e}
105 +
106 +test_expect_success '1b-setup: Merge a directory with another' '
107 + test_create_repo 1b &&
108 + (
109 + cd 1b &&
110 +
111 + mkdir z &&
112 + echo b >z/b &&
113 + echo c >z/c &&
114 + mkdir y &&
115 + echo d >y/d &&
116 + git add z y &&
117 + test_tick &&
118 + git commit -m "O" &&
119 +
120 + git branch O &&
121 + git branch A &&
122 + git branch B &&
123 +
124 + git checkout A &&
125 + echo e >z/e &&
126 + git add z/e &&
127 + test_tick &&
128 + git commit -m "A" &&
129 +
130 + git checkout B &&
131 + git mv z/b y &&
132 + git mv z/c y &&
133 + rmdir z &&
134 + test_tick &&
135 + git commit -m "B"
136 + )
137 +'
138 +
139 +test_expect_failure '1b-check: Merge a directory with another' '
140 + (
141 + cd 1b &&
142 +
143 + git checkout A^0 &&
144 +
145 + git merge -s recursive B^0 &&
146 +
147 + git ls-files -s >out &&
148 + test_line_count = 4 out &&
149 +
150 + git rev-parse >actual \
151 + HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e &&
152 + git rev-parse >expect \
153 + O:z/b O:z/c O:y/d A:z/e &&
154 + test_cmp expect actual &&
155 + test_must_fail git rev-parse HEAD:z/e
156 + )
157 +'
158 +
159 +# Testcase 1c, Transitive renaming
160 +# (Related to testcases 3a and 6d -- when should a transitive rename apply?)
161 +# (Related to testcases 9c and 9d -- can transitivity repeat?)
162 +# Commit O: z/{b,c}, x/d
163 +# Commit A: y/{b,c}, x/d
164 +# Commit B: z/{b,c,d}
165 +# Expected: y/{b,c,d} (because x/d -> z/d -> y/d)
166 +
167 +test_expect_success '1c-setup: Transitive renaming' '
168 + test_create_repo 1c &&
169 + (
170 + cd 1c &&
171 +
172 + mkdir z &&
173 + echo b >z/b &&
174 + echo c >z/c &&
175 + mkdir x &&
176 + echo d >x/d &&
177 + git add z x &&
178 + test_tick &&
179 + git commit -m "O" &&
180 +
181 + git branch O &&
182 + git branch A &&
183 + git branch B &&
184 +
185 + git checkout A &&
186 + git mv z y &&
187 + test_tick &&
188 + git commit -m "A" &&
189 +
190 + git checkout B &&
191 + git mv x/d z/d &&
192 + test_tick &&
193 + git commit -m "B"
194 + )
195 +'
196 +
197 +test_expect_failure '1c-check: Transitive renaming' '
198 + (
199 + cd 1c &&
200 +
201 + git checkout A^0 &&
202 +
203 + git merge -s recursive B^0 &&
204 +
205 + git ls-files -s >out &&
206 + test_line_count = 3 out &&
207 +
208 + git rev-parse >actual \
209 + HEAD:y/b HEAD:y/c HEAD:y/d &&
210 + git rev-parse >expect \
211 + O:z/b O:z/c O:x/d &&
212 + test_cmp expect actual &&
213 + test_must_fail git rev-parse HEAD:x/d &&
214 + test_must_fail git rev-parse HEAD:z/d &&
215 + test_path_is_missing z/d
216 + )
217 +'
218 +
219 +# Testcase 1d, Directory renames (merging two directories into one new one)
220 +# cause a rename/rename(2to1) conflict
221 +# (Related to testcases 1c and 7b)
222 +# Commit O. z/{b,c}, y/{d,e}
223 +# Commit A. x/{b,c}, y/{d,e,m,wham_1}
224 +# Commit B. z/{b,c,n,wham_2}, x/{d,e}
225 +# Expected: x/{b,c,d,e,m,n}, CONFLICT:(y/wham_1 & z/wham_2 -> x/wham)
226 +# Note: y/m & z/n should definitely move into x. By the same token, both
227 +# y/wham_1 & z/wham_2 should too...giving us a conflict.
228 +
229 +test_expect_success '1d-setup: Directory renames cause a rename/rename(2to1) conflict' '
230 + test_create_repo 1d &&
231 + (
232 + cd 1d &&
233 +
234 + mkdir z &&
235 + echo b >z/b &&
236 + echo c >z/c &&
237 + mkdir y &&
238 + echo d >y/d &&
239 + echo e >y/e &&
240 + git add z y &&
241 + test_tick &&
242 + git commit -m "O" &&
243 +
244 + git branch O &&
245 + git branch A &&
246 + git branch B &&
247 +
248 + git checkout A &&
249 + git mv z x &&
250 + echo m >y/m &&
251 + echo wham1 >y/wham &&
252 + git add y &&
253 + test_tick &&
254 + git commit -m "A" &&
255 +
256 + git checkout B &&
257 + git mv y x &&
258 + echo n >z/n &&
259 + echo wham2 >z/wham &&
260 + git add z &&
261 + test_tick &&
262 + git commit -m "B"
263 + )
264 +'
265 +
266 +test_expect_failure '1d-check: Directory renames cause a rename/rename(2to1) conflict' '
267 + (
268 + cd 1d &&
269 +
270 + git checkout A^0 &&
271 +
272 + test_must_fail git merge -s recursive B^0 >out &&
273 + test_i18ngrep "CONFLICT (rename/rename)" out &&
274 +
275 + git ls-files -s >out &&
276 + test_line_count = 8 out &&
277 + git ls-files -u >out &&
278 + test_line_count = 2 out &&
279 + git ls-files -o >out &&
280 + test_line_count = 3 out &&
281 +
282 + git rev-parse >actual \
283 + :0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n &&
284 + git rev-parse >expect \
285 + O:z/b O:z/c O:y/d O:y/e A:y/m B:z/n &&
286 + test_cmp expect actual &&
287 +
288 + test_must_fail git rev-parse :0:x/wham &&
289 + git rev-parse >actual \
290 + :2:x/wham :3:x/wham &&
291 + git rev-parse >expect \
292 + A:y/wham B:z/wham &&
293 + test_cmp expect actual &&
294 +
295 + test_path_is_missing x/wham &&
296 + test_path_is_file x/wham~HEAD &&
297 + test_path_is_file x/wham~B^0 &&
298 +
299 + git hash-object >actual \
300 + x/wham~HEAD x/wham~B^0 &&
301 + git rev-parse >expect \
302 + A:y/wham B:z/wham &&
303 + test_cmp expect actual
304 + )
305 +'
306 +
307 +# Testcase 1e, Renamed directory, with all filenames being renamed too
308 +# Commit O: z/{oldb,oldc}
309 +# Commit A: y/{newb,newc}
310 +# Commit B: z/{oldb,oldc,d}
311 +# Expected: y/{newb,newc,d}
312 +
313 +test_expect_success '1e-setup: Renamed directory, with all files being renamed too' '
314 + test_create_repo 1e &&
315 + (
316 + cd 1e &&
317 +
318 + mkdir z &&
319 + echo b >z/oldb &&
320 + echo c >z/oldc &&
321 + git add z &&
322 + test_tick &&
323 + git commit -m "O" &&
324 +
325 + git branch O &&
326 + git branch A &&
327 + git branch B &&
328 +
329 + git checkout A &&
330 + mkdir y &&
331 + git mv z/oldb y/newb &&
332 + git mv z/oldc y/newc &&
333 + test_tick &&
334 + git commit -m "A" &&
335 +
336 + git checkout B &&
337 + echo d >z/d &&
338 + git add z/d &&
339 + test_tick &&
340 + git commit -m "B"
341 + )
342 +'
343 +
344 +test_expect_failure '1e-check: Renamed directory, with all files being renamed too' '
345 + (
346 + cd 1e &&
347 +
348 + git checkout A^0 &&
349 +
350 + git merge -s recursive B^0 &&
351 +
352 + git ls-files -s >out &&
353 + test_line_count = 3 out &&
354 +
355 + git rev-parse >actual \
356 + HEAD:y/newb HEAD:y/newc HEAD:y/d &&
357 + git rev-parse >expect \
358 + O:z/oldb O:z/oldc B:z/d &&
359 + test_cmp expect actual &&
360 + test_must_fail git rev-parse HEAD:z/d
361 + )
362 +'
363 +
364 +# Testcase 1f, Split a directory into two other directories
365 +# (Related to testcases 3a, all of section 2, and all of section 4)
366 +# Commit O: z/{b,c,d,e,f}
367 +# Commit A: z/{b,c,d,e,f,g}
368 +# Commit B: y/{b,c}, x/{d,e,f}
369 +# Expected: y/{b,c}, x/{d,e,f,g}
370 +
371 +test_expect_success '1f-setup: Split a directory into two other directories' '
372 + test_create_repo 1f &&
373 + (
374 + cd 1f &&
375 +
376 + mkdir z &&
377 + echo b >z/b &&
378 + echo c >z/c &&
379 + echo d >z/d &&
380 + echo e >z/e &&
381 + echo f >z/f &&
382 + git add z &&
383 + test_tick &&
384 + git commit -m "O" &&
385 +
386 + git branch O &&
387 + git branch A &&
388 + git branch B &&
389 +
390 + git checkout A &&
391 + echo g >z/g &&
392 + git add z/g &&
393 + test_tick &&
394 + git commit -m "A" &&
395 +
396 + git checkout B &&
397 + mkdir y &&
398 + mkdir x &&
399 + git mv z/b y/ &&
400 + git mv z/c y/ &&
401 + git mv z/d x/ &&
402 + git mv z/e x/ &&
403 + git mv z/f x/ &&
404 + rmdir z &&
405 + test_tick &&
406 + git commit -m "B"
407 + )
408 +'
409 +
410 +test_expect_failure '1f-check: Split a directory into two other directories' '
411 + (
412 + cd 1f &&
413 +
414 + git checkout A^0 &&
415 +
416 + git merge -s recursive B^0 &&
417 +
418 + git ls-files -s >out &&
419 + test_line_count = 6 out &&
420 +
421 + git rev-parse >actual \
422 + HEAD:y/b HEAD:y/c HEAD:x/d HEAD:x/e HEAD:x/f HEAD:x/g &&
423 + git rev-parse >expect \
424 + O:z/b O:z/c O:z/d O:z/e O:z/f A:z/g &&
425 + test_cmp expect actual &&
426 + test_path_is_missing z/g &&
427 + test_must_fail git rev-parse HEAD:z/g
428 + )
429 +'
430 +
431 +###########################################################################
432 +# Rules suggested by testcases in section 1:
433 +#
434 +# We should still detect the directory rename even if it wasn't just
435 +# the directory renamed, but the files within it. (see 1b)
436 +#
437 +# If renames split a directory into two or more others, the directory
438 +# with the most renames, "wins" (see 1c). However, see the testcases
439 +# in section 2, plus testcases 3a and 4a.
440 +###########################################################################
441 +
442 +test_done