sparse-checkout: unquote C-style strings over --stdin
[git.git] / t / t1091-sparse-checkout-builtin.sh
bloba46a310740a7f26006a37ecba4703a0c42abc493
1 #!/bin/sh
3 test_description='sparse checkout builtin tests'
5 . ./test-lib.sh
7 list_files() {
8 # Do not replace this with 'ls "$1"', as "ls" with BSD-lineage
9 # enables "-A" by default for root and ends up including ".git" and
10 # such in its output. (Note, though, that running the test suite as
11 # root is generally not recommended.)
12 (cd "$1" && printf '%s\n' *)
15 check_files() {
16 list_files "$1" >actual &&
17 shift &&
18 printf "%s\n" $@ >expect &&
19 test_cmp expect actual
22 test_expect_success 'setup' '
23 git init repo &&
25 cd repo &&
26 echo "initial" >a &&
27 mkdir folder1 folder2 deep &&
28 mkdir deep/deeper1 deep/deeper2 &&
29 mkdir deep/deeper1/deepest &&
30 cp a folder1 &&
31 cp a folder2 &&
32 cp a deep &&
33 cp a deep/deeper1 &&
34 cp a deep/deeper2 &&
35 cp a deep/deeper1/deepest &&
36 git add . &&
37 git commit -m "initial commit"
41 test_expect_success 'git sparse-checkout list (empty)' '
42 git -C repo sparse-checkout list >list 2>err &&
43 test_must_be_empty list &&
44 test_i18ngrep "this worktree is not sparse (sparse-checkout file may not exist)" err
47 test_expect_success 'git sparse-checkout list (populated)' '
48 test_when_finished rm -f repo/.git/info/sparse-checkout &&
49 cat >repo/.git/info/sparse-checkout <<-\EOF &&
50 /folder1/*
51 /deep/
52 **/a
53 !*bin*
54 EOF
55 cp repo/.git/info/sparse-checkout expect &&
56 git -C repo sparse-checkout list >list &&
57 test_cmp expect list
60 test_expect_success 'git sparse-checkout init' '
61 git -C repo sparse-checkout init &&
62 cat >expect <<-\EOF &&
64 !/*/
65 EOF
66 test_cmp expect repo/.git/info/sparse-checkout &&
67 test_cmp_config -C repo true core.sparsecheckout &&
68 check_files repo a
71 test_expect_success 'git sparse-checkout list after init' '
72 git -C repo sparse-checkout list >actual &&
73 cat >expect <<-\EOF &&
75 !/*/
76 EOF
77 test_cmp expect actual
80 test_expect_success 'init with existing sparse-checkout' '
81 echo "*folder*" >> repo/.git/info/sparse-checkout &&
82 git -C repo sparse-checkout init &&
83 cat >expect <<-\EOF &&
85 !/*/
86 *folder*
87 EOF
88 test_cmp expect repo/.git/info/sparse-checkout &&
89 check_files repo a folder1 folder2
92 test_expect_success 'clone --sparse' '
93 git clone --sparse "file://$(pwd)/repo" clone &&
94 git -C clone sparse-checkout list >actual &&
95 cat >expect <<-\EOF &&
97 !/*/
98 EOF
99 test_cmp expect actual &&
100 check_files clone a
103 test_expect_success 'set enables config' '
104 git init empty-config &&
106 cd empty-config &&
107 test_commit test file &&
108 test_path_is_missing .git/config.worktree &&
109 test_must_fail git sparse-checkout set nothing &&
110 test_path_is_file .git/config.worktree &&
111 test_must_fail git config core.sparseCheckout &&
112 git sparse-checkout set "/*" &&
113 test_cmp_config true core.sparseCheckout
117 test_expect_success 'set sparse-checkout using builtin' '
118 git -C repo sparse-checkout set "/*" "!/*/" "*folder*" &&
119 cat >expect <<-\EOF &&
121 !/*/
122 *folder*
124 git -C repo sparse-checkout list >actual &&
125 test_cmp expect actual &&
126 test_cmp expect repo/.git/info/sparse-checkout &&
127 check_files repo a folder1 folder2
130 test_expect_success 'set sparse-checkout using --stdin' '
131 cat >expect <<-\EOF &&
133 !/*/
134 /folder1/
135 /folder2/
137 git -C repo sparse-checkout set --stdin <expect &&
138 git -C repo sparse-checkout list >actual &&
139 test_cmp expect actual &&
140 test_cmp expect repo/.git/info/sparse-checkout &&
141 check_files repo "a folder1 folder2"
144 test_expect_success 'cone mode: match patterns' '
145 git -C repo config --worktree core.sparseCheckoutCone true &&
146 rm -rf repo/a repo/folder1 repo/folder2 &&
147 git -C repo read-tree -mu HEAD 2>err &&
148 test_i18ngrep ! "disabling cone patterns" err &&
149 git -C repo reset --hard &&
150 check_files repo a folder1 folder2
153 test_expect_success 'cone mode: warn on bad pattern' '
154 test_when_finished mv sparse-checkout repo/.git/info/ &&
155 cp repo/.git/info/sparse-checkout . &&
156 echo "!/deep/deeper/*" >>repo/.git/info/sparse-checkout &&
157 git -C repo read-tree -mu HEAD 2>err &&
158 test_i18ngrep "unrecognized negative pattern" err
161 test_expect_success 'sparse-checkout disable' '
162 test_when_finished rm -rf repo/.git/info/sparse-checkout &&
163 git -C repo sparse-checkout disable &&
164 test_path_is_file repo/.git/info/sparse-checkout &&
165 git -C repo config --list >config &&
166 test_must_fail git config core.sparseCheckout &&
167 check_files repo a deep folder1 folder2
170 test_expect_success 'cone mode: init and set' '
171 git -C repo sparse-checkout init --cone &&
172 git -C repo config --list >config &&
173 test_i18ngrep "core.sparsecheckoutcone=true" config &&
174 list_files repo >dir &&
175 echo a >expect &&
176 test_cmp expect dir &&
177 git -C repo sparse-checkout set deep/deeper1/deepest/ 2>err &&
178 test_must_be_empty err &&
179 check_files repo a deep &&
180 check_files repo/deep a deeper1 &&
181 check_files repo/deep/deeper1 a deepest &&
182 cat >expect <<-\EOF &&
184 !/*/
185 /deep/
186 !/deep/*/
187 /deep/deeper1/
188 !/deep/deeper1/*/
189 /deep/deeper1/deepest/
191 test_cmp expect repo/.git/info/sparse-checkout &&
192 git -C repo sparse-checkout set --stdin 2>err <<-\EOF &&
193 folder1
194 folder2
196 test_must_be_empty err &&
197 check_files repo a folder1 folder2
200 test_expect_success 'cone mode: list' '
201 cat >expect <<-\EOF &&
202 folder1
203 folder2
205 git -C repo sparse-checkout set --stdin <expect &&
206 git -C repo sparse-checkout list >actual 2>err &&
207 test_must_be_empty err &&
208 test_cmp expect actual
211 test_expect_success 'cone mode: set with nested folders' '
212 git -C repo sparse-checkout set deep deep/deeper1/deepest 2>err &&
213 test_line_count = 0 err &&
214 cat >expect <<-\EOF &&
216 !/*/
217 /deep/
219 test_cmp repo/.git/info/sparse-checkout expect
222 test_expect_success 'revert to old sparse-checkout on bad update' '
223 test_when_finished git -C repo reset --hard &&
224 echo update >repo/deep/deeper2/a &&
225 cp repo/.git/info/sparse-checkout expect &&
226 test_must_fail git -C repo sparse-checkout set deep/deeper1 2>err &&
227 test_i18ngrep "cannot set sparse-checkout patterns" err &&
228 test_cmp repo/.git/info/sparse-checkout expect &&
229 check_files repo/deep a deeper1 deeper2
232 test_expect_success 'revert to old sparse-checkout on empty update' '
233 git init empty-test &&
235 echo >file &&
236 git add file &&
237 git commit -m "test" &&
238 test_must_fail git sparse-checkout set nothing 2>err &&
239 test_i18ngrep "Sparse checkout leaves no entry on working directory" err &&
240 test_i18ngrep ! ".git/index.lock" err &&
241 git sparse-checkout set file
245 test_expect_success 'fail when lock is taken' '
246 test_when_finished rm -rf repo/.git/info/sparse-checkout.lock &&
247 touch repo/.git/info/sparse-checkout.lock &&
248 test_must_fail git -C repo sparse-checkout set deep 2>err &&
249 test_i18ngrep "File exists" err
252 test_expect_success '.gitignore should not warn about cone mode' '
253 git -C repo config --worktree core.sparseCheckoutCone true &&
254 echo "**/bin/*" >repo/.gitignore &&
255 git -C repo reset --hard 2>err &&
256 test_i18ngrep ! "disabling cone patterns" err
259 test_expect_success 'sparse-checkout (init|set|disable) fails with dirty status' '
260 git clone repo dirty &&
261 echo dirty >dirty/folder1/a &&
262 test_must_fail git -C dirty sparse-checkout init &&
263 test_must_fail git -C dirty sparse-checkout set /folder2/* /deep/deeper1/* &&
264 test_must_fail git -C dirty sparse-checkout disable &&
265 git -C dirty reset --hard &&
266 git -C dirty sparse-checkout init &&
267 git -C dirty sparse-checkout set /folder2/* /deep/deeper1/* &&
268 git -C dirty sparse-checkout disable
271 test_expect_success 'cone mode: set with core.ignoreCase=true' '
272 git -C repo sparse-checkout init --cone &&
273 git -C repo -c core.ignoreCase=true sparse-checkout set folder1 &&
274 cat >expect <<-\EOF &&
276 !/*/
277 /folder1/
279 test_cmp expect repo/.git/info/sparse-checkout &&
280 check_files repo a folder1
283 test_expect_success 'interaction with submodules' '
284 git clone repo super &&
286 cd super &&
287 mkdir modules &&
288 git submodule add ../repo modules/child &&
289 git add . &&
290 git commit -m "add submodule" &&
291 git sparse-checkout init --cone &&
292 git sparse-checkout set folder1
293 ) &&
294 check_files super a folder1 modules &&
295 check_files super/modules/child a deep folder1 folder2
298 test_expect_success 'different sparse-checkouts with worktrees' '
299 git -C repo worktree add --detach ../worktree &&
300 check_files worktree "a deep folder1 folder2" &&
301 git -C worktree sparse-checkout init --cone &&
302 git -C repo sparse-checkout set folder1 &&
303 git -C worktree sparse-checkout set deep/deeper1 &&
304 check_files repo a folder1 &&
305 check_files worktree a deep
308 check_read_tree_errors () {
309 REPO=$1
310 FILES=$2
311 ERRORS=$3
312 git -C $REPO -c core.sparseCheckoutCone=false read-tree -mu HEAD 2>err &&
313 test_must_be_empty err &&
314 check_files $REPO "$FILES" &&
315 git -C $REPO read-tree -mu HEAD 2>err &&
316 if test -z "$ERRORS"
317 then
318 test_must_be_empty err
319 else
320 test_i18ngrep "$ERRORS" err
321 fi &&
322 check_files $REPO $FILES
325 test_expect_success 'pattern-checks: /A/**' '
326 cat >repo/.git/info/sparse-checkout <<-\EOF &&
328 !/*/
329 /folder1/**
331 check_read_tree_errors repo "a folder1" "disabling cone pattern matching"
334 test_expect_success 'pattern-checks: /A/**/B/' '
335 cat >repo/.git/info/sparse-checkout <<-\EOF &&
337 !/*/
338 /deep/**/deepest
340 check_read_tree_errors repo "a deep" "disabling cone pattern matching" &&
341 check_files repo/deep "deeper1" &&
342 check_files repo/deep/deeper1 "deepest"
345 test_expect_success 'pattern-checks: too short' '
346 cat >repo/.git/info/sparse-checkout <<-\EOF &&
348 !/*/
351 check_read_tree_errors repo "a" "disabling cone pattern matching"
354 test_expect_success 'pattern-checks: trailing "*"' '
355 cat >repo/.git/info/sparse-checkout <<-\EOF &&
357 !/*/
360 check_read_tree_errors repo "a" "disabling cone pattern matching"
363 test_expect_success 'pattern-checks: starting "*"' '
364 cat >repo/.git/info/sparse-checkout <<-\EOF &&
366 !/*/
367 *eep/
369 check_read_tree_errors repo "a deep" "disabling cone pattern matching"
372 test_expect_success 'pattern-checks: contained glob characters' '
373 for c in "[a]" "\\" "?" "*"
375 cat >repo/.git/info/sparse-checkout <<-EOF &&
377 !/*/
378 something$c-else/
380 check_read_tree_errors repo "a" "disabling cone pattern matching"
381 done
384 test_expect_success BSLASHPSPEC 'pattern-checks: escaped "*"' '
385 git clone repo escaped &&
386 TREEOID=$(git -C escaped rev-parse HEAD:folder1) &&
387 NEWTREE=$(git -C escaped mktree <<-EOF
388 $(git -C escaped ls-tree HEAD)
389 040000 tree $TREEOID zbad\\dir
390 040000 tree $TREEOID zdoes*exist
392 ) &&
393 COMMIT=$(git -C escaped commit-tree $NEWTREE -p HEAD) &&
394 git -C escaped reset --hard $COMMIT &&
395 check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist" &&
396 git -C escaped sparse-checkout init --cone &&
397 git -C escaped sparse-checkout set zbad\\dir/bogus "zdoes*not*exist" "zdoes*exist" &&
398 cat >expect <<-\EOF &&
400 !/*/
401 /zbad\\dir/
402 !/zbad\\dir/*/
403 /zbad\\dir/bogus/
404 /zdoes\*exist/
405 /zdoes\*not\*exist/
407 test_cmp expect escaped/.git/info/sparse-checkout &&
408 check_read_tree_errors escaped "a zbad\\dir zdoes*exist" &&
409 git -C escaped ls-tree -d --name-only HEAD | git -C escaped sparse-checkout set --stdin &&
410 cat >expect <<-\EOF &&
412 !/*/
413 /deep/
414 /folder1/
415 /folder2/
416 /zbad\\dir/
417 /zdoes\*exist/
419 test_cmp expect escaped/.git/info/sparse-checkout &&
420 check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist"
423 test_done