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