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