Raw
1 #!/bin/sh
2
3 test_description='merge-recursive rename options
4
5 Test rename detection by examining rename/delete conflicts.
6
7 * (HEAD -> rename) rename
8 | * (main) delete
9 |/
10 * base
11
12 git diff --name-status base main
13 D 0-old
14 D 1-old
15 D 2-old
16 D 3-old
17
18 git diff --name-status -M01 base rename
19 R025 0-old 0-new
20 R050 1-old 1-new
21 R075 2-old 2-new
22 R100 3-old 3-new
23
24 Actual similarity indices are parsed from diff output. We rely on the fact that
25 they are rounded down (see, e.g., Documentation/diff-generate-patch.adoc, which
26 mentions this in a different context).
27 '
28
29 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
30 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
31
32 . ./test-lib.sh
33
34 get_expected_stages () {
35 git checkout rename -- $1-new &&
36 git ls-files --stage $1-new >expected-stages-undetected-$1 &&
37 git ls-tree HEAD^ $1-old >tmp &&
38 git ls-tree HEAD $1-new >>tmp &&
39 cat tmp | awk '{print $1 " " $3 " " NR "\t" '$1'"-new"}' \
40 >expected-stages-detected-$1 &&
41 git read-tree -u --reset HEAD
42 }
43
44 rename_detected () {
45 git ls-files --stage $1-old $1-new >stages-actual-$1 &&
46 test_cmp expected-stages-detected-$1 stages-actual-$1
47 }
48
49 rename_undetected () {
50 git ls-files --stage $1-old $1-new >stages-actual-$1 &&
51 test_cmp expected-stages-undetected-$1 stages-actual-$1
52 }
53
54 check_common () {
55 git ls-files --stage >stages-actual &&
56 test_line_count = $1 stages-actual
57 }
58
59 check_threshold_0 () {
60 check_common 8 &&
61 rename_detected 0 &&
62 rename_detected 1 &&
63 rename_detected 2 &&
64 rename_detected 3
65 }
66
67 check_threshold_1 () {
68 check_common 7 &&
69 rename_undetected 0 &&
70 rename_detected 1 &&
71 rename_detected 2 &&
72 rename_detected 3
73 }
74
75 check_threshold_2 () {
76 check_common 6 &&
77 rename_undetected 0 &&
78 rename_undetected 1 &&
79 rename_detected 2 &&
80 rename_detected 3
81 }
82
83 check_exact_renames () {
84 check_common 5 &&
85 rename_undetected 0 &&
86 rename_undetected 1 &&
87 rename_undetected 2 &&
88 rename_detected 3
89 }
90
91 check_no_renames () {
92 check_common 4 &&
93 rename_undetected 0 &&
94 rename_undetected 1 &&
95 rename_undetected 2 &&
96 rename_undetected 3
97 }
98
99 test_expect_success 'setup repo' '
100 cat <<-\EOF >3-old &&
101 33a
102 33b
103 33c
104 33d
105 EOF
106 sed s/33/22/ <3-old >2-old &&
107 sed s/33/11/ <3-old >1-old &&
108 sed s/33/00/ <3-old >0-old &&
109 git add [0-3]-old &&
110 git commit -m base &&
111 git rm [0-3]-old &&
112 git commit -m delete &&
113 git checkout -b rename HEAD^ &&
114 cp 3-old 3-new &&
115 sed 1,1s/./x/ <2-old >2-new &&
116 sed 1,2s/./x/ <1-old >1-new &&
117 sed 1,3s/./x/ <0-old >0-new &&
118 git add [0-3]-new &&
119 git rm [0-3]-old &&
120 git commit -m rename &&
121 get_expected_stages 0 &&
122 get_expected_stages 1 &&
123 get_expected_stages 2 &&
124 get_expected_stages 3 &&
125 check_50="false" &&
126 tail="HEAD^ -- HEAD main"
127 '
128
129 test_expect_success 'setup thresholds' '
130 git diff --name-status -M01 HEAD^ HEAD >diff-output &&
131 test_debug "cat diff-output" &&
132 test_line_count = 4 diff-output &&
133 grep "R[0-9][0-9][0-9] \([0-3]\)-old \1-new" diff-output \
134 >grep-output &&
135 test_cmp diff-output grep-output &&
136 th0=$(sed -n "s/R\(...\) 0-old 0-new/\1/p" <diff-output) &&
137 th1=$(sed -n "s/R\(...\) 1-old 1-new/\1/p" <diff-output) &&
138 th2=$(sed -n "s/R\(...\) 2-old 2-new/\1/p" <diff-output) &&
139 th3=$(sed -n "s/R\(...\) 3-old 3-new/\1/p" <diff-output) &&
140 test "$th0" -lt "$th1" &&
141 test "$th1" -lt "$th2" &&
142 test "$th2" -lt "$th3" &&
143 test "$th3" = 100 &&
144 if test 50 -le "$th0"
145 then
146 check_50=check_threshold_0
147 elif test 50 -le "$th1"
148 then
149 check_50=check_threshold_1
150 elif test 50 -le "$th2"
151 then
152 check_50=check_threshold_2
153 fi &&
154 th0="$th0%" &&
155 th1="$th1%" &&
156 th2="$th2%" &&
157 th3="$th3%"
158 '
159
160 test_expect_success 'assumption for tests: rename detection with diff' '
161 git diff --name-status -M$th0 --diff-filter=R HEAD^ HEAD \
162 >diff-output-0 &&
163 git diff --name-status -M$th1 --diff-filter=R HEAD^ HEAD \
164 >diff-output-1 &&
165 git diff --name-status -M$th2 --diff-filter=R HEAD^ HEAD \
166 >diff-output-2 &&
167 git diff --name-status -M100% --diff-filter=R HEAD^ HEAD \
168 >diff-output-3 &&
169 test_line_count = 4 diff-output-0 &&
170 test_line_count = 3 diff-output-1 &&
171 test_line_count = 2 diff-output-2 &&
172 test_line_count = 1 diff-output-3
173 '
174
175 test_expect_success 'default similarity threshold is 50%' '
176 git read-tree --reset -u HEAD &&
177 test_must_fail git merge-recursive $tail &&
178 $check_50
179 '
180
181 test_expect_success 'low rename threshold' '
182 git read-tree --reset -u HEAD &&
183 test_must_fail git merge-recursive --find-renames=$th0 $tail &&
184 check_threshold_0
185 '
186
187 test_expect_success 'medium rename threshold' '
188 git read-tree --reset -u HEAD &&
189 test_must_fail git merge-recursive --find-renames=$th1 $tail &&
190 check_threshold_1
191 '
192
193 test_expect_success 'high rename threshold' '
194 git read-tree --reset -u HEAD &&
195 test_must_fail git merge-recursive --find-renames=$th2 $tail &&
196 check_threshold_2
197 '
198
199 test_expect_success 'exact renames only' '
200 git read-tree --reset -u HEAD &&
201 test_must_fail git merge-recursive --find-renames=100% $tail &&
202 check_exact_renames
203 '
204
205 test_expect_success 'rename threshold is truncated' '
206 git read-tree --reset -u HEAD &&
207 test_must_fail git merge-recursive --find-renames=200% $tail &&
208 check_exact_renames
209 '
210
211 test_expect_success 'disabled rename detection' '
212 git read-tree --reset -u HEAD &&
213 git merge-recursive --no-renames $tail &&
214 check_no_renames
215 '
216
217 test_expect_success 'last wins in --find-renames=<m> --find-renames=<n>' '
218 git read-tree --reset -u HEAD &&
219 test_must_fail git merge-recursive \
220 --find-renames=$th0 --find-renames=$th2 $tail &&
221 check_threshold_2
222 '
223
224 test_expect_success '--find-renames resets threshold' '
225 git read-tree --reset -u HEAD &&
226 test_must_fail git merge-recursive \
227 --find-renames=$th0 --find-renames $tail &&
228 $check_50
229 '
230
231 test_expect_success 'last wins in --no-renames --find-renames' '
232 git read-tree --reset -u HEAD &&
233 test_must_fail git merge-recursive --no-renames --find-renames $tail &&
234 $check_50
235 '
236
237 test_expect_success 'last wins in --find-renames --no-renames' '
238 git read-tree --reset -u HEAD &&
239 git merge-recursive --find-renames --no-renames $tail &&
240 check_no_renames
241 '
242
243 test_expect_success 'assumption for further tests: trivial merge succeeds' '
244 git read-tree --reset -u HEAD &&
245 git merge-recursive HEAD -- HEAD HEAD &&
246 git diff --quiet --cached &&
247 git merge-recursive --find-renames=$th0 HEAD -- HEAD HEAD &&
248 git diff --quiet --cached &&
249 git merge-recursive --find-renames=$th2 HEAD -- HEAD HEAD &&
250 git diff --quiet --cached &&
251 git merge-recursive --find-renames=100% HEAD -- HEAD HEAD &&
252 git diff --quiet --cached &&
253 git merge-recursive --no-renames HEAD -- HEAD HEAD &&
254 git diff --quiet --cached
255 '
256
257 test_expect_success '--find-renames rejects negative argument' '
258 git read-tree --reset -u HEAD &&
259 test_must_fail git merge-recursive --find-renames=-25 \
260 HEAD -- HEAD HEAD &&
261 git diff --quiet --cached
262 '
263
264 test_expect_success '--find-renames rejects non-numbers' '
265 git read-tree --reset -u HEAD &&
266 test_must_fail git merge-recursive --find-renames=0xf \
267 HEAD -- HEAD HEAD &&
268 git diff --quiet --cached
269 '
270
271 test_expect_success 'rename-threshold=<n> is a synonym for find-renames=<n>' '
272 git read-tree --reset -u HEAD &&
273 test_must_fail git merge-recursive --rename-threshold=$th0 $tail &&
274 check_threshold_0
275 '
276
277 test_expect_success 'last wins in --no-renames --rename-threshold=<n>' '
278 git read-tree --reset -u HEAD &&
279 test_must_fail git merge-recursive --no-renames --rename-threshold=$th0 $tail &&
280 check_threshold_0
281 '
282
283 test_expect_success 'last wins in --rename-threshold=<n> --no-renames' '
284 git read-tree --reset -u HEAD &&
285 git merge-recursive --rename-threshold=$th0 --no-renames $tail &&
286 check_no_renames
287 '
288
289 test_expect_success '--rename-threshold=<n> rejects negative argument' '
290 git read-tree --reset -u HEAD &&
291 test_must_fail git merge-recursive --rename-threshold=-25 \
292 HEAD -- HEAD HEAD &&
293 git diff --quiet --cached
294 '
295
296 test_expect_success '--rename-threshold=<n> rejects non-numbers' '
297 git read-tree --reset -u HEAD &&
298 test_must_fail git merge-recursive --rename-threshold=0xf \
299 HEAD -- HEAD HEAD &&
300 git diff --quiet --cached
301 '
302
303 test_expect_success 'last wins in --rename-threshold=<m> --find-renames=<n>' '
304 git read-tree --reset -u HEAD &&
305 test_must_fail git merge-recursive \
306 --rename-threshold=$th0 --find-renames=$th2 $tail &&
307 check_threshold_2
308 '
309
310 test_expect_success 'last wins in --find-renames=<m> --rename-threshold=<n>' '
311 git read-tree --reset -u HEAD &&
312 test_must_fail git merge-recursive \
313 --find-renames=$th2 --rename-threshold=$th0 $tail &&
314 check_threshold_0
315 '
316
317 test_expect_success 'merge.renames disables rename detection' '
318 git read-tree --reset -u HEAD &&
319 git -c merge.renames=false merge-recursive $tail &&
320 check_no_renames
321 '
322
323 test_expect_success 'merge.renames defaults to diff.renames' '
324 git read-tree --reset -u HEAD &&
325 git -c diff.renames=false merge-recursive $tail &&
326 check_no_renames
327 '
328
329 test_expect_success 'merge.renames overrides diff.renames' '
330 git read-tree --reset -u HEAD &&
331 test_must_fail git -c diff.renames=false -c merge.renames=true merge-recursive $tail &&
332 $check_50
333 '
334
335 test_done