Merge branch 'js/range-diff-one-side-only'
[git] / t / t1700-split-index.sh
1 #!/bin/sh
2
3 test_description='split index mode tests'
4
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 . ./test-lib.sh
9
10 # We need total control of index splitting here
11 sane_unset GIT_TEST_SPLIT_INDEX
12
13 # Testing a hard coded SHA against an index with an extension
14 # that can vary from run to run is problematic so we disable
15 # those extensions.
16 sane_unset GIT_TEST_FSMONITOR
17 sane_unset GIT_TEST_INDEX_THREADS
18
19 # Create a file named as $1 with content read from stdin.
20 # Set the file's mtime to a few seconds in the past to avoid racy situations.
21 create_non_racy_file () {
22         cat >"$1" &&
23         test-tool chmtime =-5 "$1"
24 }
25
26 test_expect_success 'setup' '
27         test_oid_cache <<-EOF
28         own_v3 sha1:8299b0bcd1ac364e5f1d7768efb62fa2da79a339
29         own_v3 sha256:38a6d2925e3eceec33ad7b34cbff4e0086caa0daf28f31e51f5bd94b4a7af86b
30
31         base_v3 sha1:39d890139ee5356c7ef572216cebcd27aa41f9df
32         base_v3 sha256:c9baeadf905112bf6c17aefbd7d02267afd70ded613c30cafed2d40cb506e1ed
33
34         own_v4 sha1:432ef4b63f32193984f339431fd50ca796493569
35         own_v4 sha256:6738ac6319c25b694afa7bcc313deb182d1a59b68bf7a47b4296de83478c0420
36
37         base_v4 sha1:508851a7f0dfa8691e9f69c7f055865389012491
38         base_v4 sha256:3177d4adfdd4b6904f7e921d91d715a471c0dde7cf6a4bba574927f02b699508
39         EOF
40 '
41
42 test_expect_success 'enable split index' '
43         git config splitIndex.maxPercentChange 100 &&
44         git update-index --split-index &&
45         test-tool dump-split-index .git/index >actual &&
46         indexversion=$(test-tool index-version <.git/index) &&
47
48         # NEEDSWORK: Stop hard-coding checksums.
49         if test "$indexversion" = "4"
50         then
51                 own=$(test_oid own_v4)
52                 base=$(test_oid base_v4)
53         else
54                 own=$(test_oid own_v3)
55                 base=$(test_oid base_v3)
56         fi &&
57
58         cat >expect <<-EOF &&
59         own $own
60         base $base
61         replacements:
62         deletions:
63         EOF
64         test_cmp expect actual
65 '
66
67 test_expect_success 'add one file' '
68         create_non_racy_file one &&
69         git update-index --add one &&
70         git ls-files --stage >ls-files.actual &&
71         cat >ls-files.expect <<-EOF &&
72         100644 $EMPTY_BLOB 0    one
73         EOF
74         test_cmp ls-files.expect ls-files.actual &&
75
76         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
77         cat >expect <<-EOF &&
78         base $base
79         100644 $EMPTY_BLOB 0    one
80         replacements:
81         deletions:
82         EOF
83         test_cmp expect actual
84 '
85
86 test_expect_success 'disable split index' '
87         git update-index --no-split-index &&
88         git ls-files --stage >ls-files.actual &&
89         cat >ls-files.expect <<-EOF &&
90         100644 $EMPTY_BLOB 0    one
91         EOF
92         test_cmp ls-files.expect ls-files.actual &&
93
94         BASE=$(test-tool dump-split-index .git/index | sed -n "s/^own/base/p") &&
95         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
96         cat >expect <<-EOF &&
97         not a split index
98         EOF
99         test_cmp expect actual
100 '
101
102 test_expect_success 'enable split index again, "one" now belongs to base index"' '
103         git update-index --split-index &&
104         git ls-files --stage >ls-files.actual &&
105         cat >ls-files.expect <<-EOF &&
106         100644 $EMPTY_BLOB 0    one
107         EOF
108         test_cmp ls-files.expect ls-files.actual &&
109
110         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
111         cat >expect <<-EOF &&
112         $BASE
113         replacements:
114         deletions:
115         EOF
116         test_cmp expect actual
117 '
118
119 test_expect_success 'modify original file, base index untouched' '
120         echo modified | create_non_racy_file one &&
121         file1_blob=$(git hash-object one) &&
122         git update-index one &&
123         git ls-files --stage >ls-files.actual &&
124         cat >ls-files.expect <<-EOF &&
125         100644 $file1_blob 0    one
126         EOF
127         test_cmp ls-files.expect ls-files.actual &&
128
129         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
130         q_to_tab >expect <<-EOF &&
131         $BASE
132         100644 $file1_blob 0Q
133         replacements: 0
134         deletions:
135         EOF
136         test_cmp expect actual
137 '
138
139 test_expect_success 'add another file, which stays index' '
140         create_non_racy_file two &&
141         git update-index --add two &&
142         git ls-files --stage >ls-files.actual &&
143         cat >ls-files.expect <<-EOF &&
144         100644 $file1_blob 0    one
145         100644 $EMPTY_BLOB 0    two
146         EOF
147         test_cmp ls-files.expect ls-files.actual &&
148
149         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
150         q_to_tab >expect <<-EOF &&
151         $BASE
152         100644 $file1_blob 0Q
153         100644 $EMPTY_BLOB 0    two
154         replacements: 0
155         deletions:
156         EOF
157         test_cmp expect actual
158 '
159
160 test_expect_success 'remove file not in base index' '
161         git update-index --force-remove two &&
162         git ls-files --stage >ls-files.actual &&
163         cat >ls-files.expect <<-EOF &&
164         100644 $file1_blob 0    one
165         EOF
166         test_cmp ls-files.expect ls-files.actual &&
167
168         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
169         q_to_tab >expect <<-EOF &&
170         $BASE
171         100644 $file1_blob 0Q
172         replacements: 0
173         deletions:
174         EOF
175         test_cmp expect actual
176 '
177
178 test_expect_success 'remove file in base index' '
179         git update-index --force-remove one &&
180         git ls-files --stage >ls-files.actual &&
181         test_must_be_empty ls-files.actual &&
182
183         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
184         cat >expect <<-EOF &&
185         $BASE
186         replacements:
187         deletions: 0
188         EOF
189         test_cmp expect actual
190 '
191
192 test_expect_success 'add original file back' '
193         create_non_racy_file one &&
194         git update-index --add one &&
195         git ls-files --stage >ls-files.actual &&
196         cat >ls-files.expect <<-EOF &&
197         100644 $EMPTY_BLOB 0    one
198         EOF
199         test_cmp ls-files.expect ls-files.actual &&
200
201         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
202         cat >expect <<-EOF &&
203         $BASE
204         100644 $EMPTY_BLOB 0    one
205         replacements:
206         deletions: 0
207         EOF
208         test_cmp expect actual
209 '
210
211 test_expect_success 'add new file' '
212         create_non_racy_file two &&
213         git update-index --add two &&
214         git ls-files --stage >actual &&
215         cat >expect <<-EOF &&
216         100644 $EMPTY_BLOB 0    one
217         100644 $EMPTY_BLOB 0    two
218         EOF
219         test_cmp expect actual
220 '
221
222 test_expect_success 'unify index, two files remain' '
223         git update-index --no-split-index &&
224         git ls-files --stage >ls-files.actual &&
225         cat >ls-files.expect <<-EOF &&
226         100644 $EMPTY_BLOB 0    one
227         100644 $EMPTY_BLOB 0    two
228         EOF
229         test_cmp ls-files.expect ls-files.actual &&
230
231         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
232         cat >expect <<-EOF &&
233         not a split index
234         EOF
235         test_cmp expect actual
236 '
237
238 test_expect_success 'rev-parse --shared-index-path' '
239         test_create_repo split-index &&
240         (
241                 cd split-index &&
242                 git update-index --split-index &&
243                 echo .git/sharedindex* >expect &&
244                 git rev-parse --shared-index-path >actual &&
245                 test_cmp expect actual &&
246                 mkdir subdirectory &&
247                 cd subdirectory &&
248                 echo ../.git/sharedindex* >expect &&
249                 git rev-parse --shared-index-path >actual &&
250                 test_cmp expect actual
251         )
252 '
253
254 test_expect_success 'set core.splitIndex config variable to true' '
255         git config core.splitIndex true &&
256         create_non_racy_file three &&
257         git update-index --add three &&
258         git ls-files --stage >ls-files.actual &&
259         cat >ls-files.expect <<-EOF &&
260         100644 $EMPTY_BLOB 0    one
261         100644 $EMPTY_BLOB 0    three
262         100644 $EMPTY_BLOB 0    two
263         EOF
264         test_cmp ls-files.expect ls-files.actual &&
265         BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
266         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
267         cat >expect <<-EOF &&
268         $BASE
269         replacements:
270         deletions:
271         EOF
272         test_cmp expect actual
273 '
274
275 test_expect_success 'set core.splitIndex config variable to false' '
276         git config core.splitIndex false &&
277         git update-index --force-remove three &&
278         git ls-files --stage >ls-files.actual &&
279         cat >ls-files.expect <<-EOF &&
280         100644 $EMPTY_BLOB 0    one
281         100644 $EMPTY_BLOB 0    two
282         EOF
283         test_cmp ls-files.expect ls-files.actual &&
284         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
285         cat >expect <<-EOF &&
286         not a split index
287         EOF
288         test_cmp expect actual
289 '
290
291 test_expect_success 'set core.splitIndex config variable back to true' '
292         git config core.splitIndex true &&
293         create_non_racy_file three &&
294         git update-index --add three &&
295         BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
296         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
297         cat >expect <<-EOF &&
298         $BASE
299         replacements:
300         deletions:
301         EOF
302         test_cmp expect actual &&
303         create_non_racy_file four &&
304         git update-index --add four &&
305         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
306         cat >expect <<-EOF &&
307         $BASE
308         100644 $EMPTY_BLOB 0    four
309         replacements:
310         deletions:
311         EOF
312         test_cmp expect actual
313 '
314
315 test_expect_success 'check behavior with splitIndex.maxPercentChange unset' '
316         git config --unset splitIndex.maxPercentChange &&
317         create_non_racy_file five &&
318         git update-index --add five &&
319         BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
320         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
321         cat >expect <<-EOF &&
322         $BASE
323         replacements:
324         deletions:
325         EOF
326         test_cmp expect actual &&
327         create_non_racy_file six &&
328         git update-index --add six &&
329         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
330         cat >expect <<-EOF &&
331         $BASE
332         100644 $EMPTY_BLOB 0    six
333         replacements:
334         deletions:
335         EOF
336         test_cmp expect actual
337 '
338
339 test_expect_success 'check splitIndex.maxPercentChange set to 0' '
340         git config splitIndex.maxPercentChange 0 &&
341         create_non_racy_file seven &&
342         git update-index --add seven &&
343         BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
344         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
345         cat >expect <<-EOF &&
346         $BASE
347         replacements:
348         deletions:
349         EOF
350         test_cmp expect actual &&
351         create_non_racy_file eight &&
352         git update-index --add eight &&
353         BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
354         test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
355         cat >expect <<-EOF &&
356         $BASE
357         replacements:
358         deletions:
359         EOF
360         test_cmp expect actual
361 '
362
363 test_expect_success 'shared index files expire after 2 weeks by default' '
364         create_non_racy_file ten &&
365         git update-index --add ten &&
366         test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
367         just_under_2_weeks_ago=$((5-14*86400)) &&
368         test-tool chmtime =$just_under_2_weeks_ago .git/sharedindex.* &&
369         create_non_racy_file eleven &&
370         git update-index --add eleven &&
371         test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
372         just_over_2_weeks_ago=$((-1-14*86400)) &&
373         test-tool chmtime =$just_over_2_weeks_ago .git/sharedindex.* &&
374         create_non_racy_file twelve &&
375         git update-index --add twelve &&
376         test $(ls .git/sharedindex.* | wc -l) -le 2
377 '
378
379 test_expect_success 'check splitIndex.sharedIndexExpire set to 16 days' '
380         git config splitIndex.sharedIndexExpire "16.days.ago" &&
381         test-tool chmtime =$just_over_2_weeks_ago .git/sharedindex.* &&
382         create_non_racy_file thirteen &&
383         git update-index --add thirteen &&
384         test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
385         just_over_16_days_ago=$((-1-16*86400)) &&
386         test-tool chmtime =$just_over_16_days_ago .git/sharedindex.* &&
387         create_non_racy_file fourteen &&
388         git update-index --add fourteen &&
389         test $(ls .git/sharedindex.* | wc -l) -le 2
390 '
391
392 test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"' '
393         git config splitIndex.sharedIndexExpire never &&
394         just_10_years_ago=$((-365*10*86400)) &&
395         test-tool chmtime =$just_10_years_ago .git/sharedindex.* &&
396         create_non_racy_file fifteen &&
397         git update-index --add fifteen &&
398         test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
399         git config splitIndex.sharedIndexExpire now &&
400         just_1_second_ago=-1 &&
401         test-tool chmtime =$just_1_second_ago .git/sharedindex.* &&
402         create_non_racy_file sixteen &&
403         git update-index --add sixteen &&
404         test $(ls .git/sharedindex.* | wc -l) -le 2
405 '
406
407 test_expect_success POSIXPERM 'same mode for index & split index' '
408         git init same-mode &&
409         (
410                 cd same-mode &&
411                 test_commit A &&
412                 test_modebits .git/index >index_mode &&
413                 test_must_fail git config core.sharedRepository &&
414                 git -c core.splitIndex=true status &&
415                 shared=$(ls .git/sharedindex.*) &&
416                 case "$shared" in
417                 *" "*)
418                         # we have more than one???
419                         false ;;
420                 *)
421                         test_modebits "$shared" >split_index_mode &&
422                         test_cmp index_mode split_index_mode ;;
423                 esac
424         )
425 '
426
427 while read -r mode modebits
428 do
429         test_expect_success POSIXPERM "split index respects core.sharedrepository $mode" '
430                 # Remove existing shared index files
431                 git config core.splitIndex false &&
432                 git update-index --force-remove one &&
433                 rm -f .git/sharedindex.* &&
434                 # Create one new shared index file
435                 git config core.sharedrepository "$mode" &&
436                 git config core.splitIndex true &&
437                 create_non_racy_file one &&
438                 git update-index --add one &&
439                 echo "$modebits" >expect &&
440                 test_modebits .git/index >actual &&
441                 test_cmp expect actual &&
442                 shared=$(ls .git/sharedindex.*) &&
443                 case "$shared" in
444                 *" "*)
445                         # we have more than one???
446                         false ;;
447                 *)
448                         test_modebits "$shared" >actual &&
449                         test_cmp expect actual ;;
450                 esac
451         '
452 done <<\EOF
453 0666 -rw-rw-rw-
454 0642 -rw-r---w-
455 EOF
456
457 test_expect_success POSIXPERM,SANITY 'graceful handling when splitting index is not allowed' '
458         test_create_repo ro &&
459         (
460                 cd ro &&
461                 test_commit initial &&
462                 git update-index --split-index &&
463                 test -f .git/sharedindex.*
464         ) &&
465         cp ro/.git/index new-index &&
466         test_when_finished "chmod u+w ro/.git" &&
467         chmod u-w ro/.git &&
468         GIT_INDEX_FILE="$(pwd)/new-index" git -C ro update-index --split-index &&
469         chmod u+w ro/.git &&
470         rm ro/.git/sharedindex.* &&
471         GIT_INDEX_FILE=new-index git ls-files >actual &&
472         echo initial.t >expected &&
473         test_cmp expected actual
474 '
475
476 test_expect_success 'writing split index with null sha1 does not write cache tree' '
477         git config core.splitIndex true &&
478         git config splitIndex.maxPercentChange 0 &&
479         git commit -m "commit" &&
480         {
481                 git ls-tree HEAD &&
482                 printf "160000 commit $ZERO_OID\\tbroken\\n"
483         } >broken-tree &&
484         echo "add broken entry" >msg &&
485
486         tree=$(git mktree <broken-tree) &&
487         test_tick &&
488         commit=$(git commit-tree $tree -p HEAD <msg) &&
489         git update-ref HEAD "$commit" &&
490         GIT_ALLOW_NULL_SHA1=1 git reset --hard &&
491         test_might_fail test-tool dump-cache-tree >cache-tree.out &&
492         test_line_count = 0 cache-tree.out
493 '
494
495 test_expect_success 'do not refresh null base index' '
496         test_create_repo merge &&
497         (
498                 cd merge &&
499                 test_commit initial &&
500                 git checkout -b side-branch &&
501                 test_commit extra &&
502                 git checkout main &&
503                 git update-index --split-index &&
504                 test_commit more &&
505                 # must not write a new shareindex, or we wont catch the problem
506                 git -c splitIndex.maxPercentChange=100 merge --no-edit side-branch 2>err &&
507                 # i.e. do not expect warnings like
508                 # could not freshen shared index .../shareindex.00000...
509                 test_must_be_empty err
510         )
511 '
512
513 test_done