3 test_description
='Test grep recurse-submodules feature
5 This test verifies the recurse-submodules feature correctly greps across
11 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
=1
12 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
14 test_expect_success
'setup directory structure and submodule' '
15 echo "(1|2)d(3|4)" >a &&
19 git commit -m "add a and b" &&
22 echo "(1|2)d(3|4)" >submodule/a &&
23 git -C submodule add a &&
24 git -C submodule commit -m "add a" &&
25 git submodule add ./submodule &&
26 git commit -m "added submodule" &&
30 test_expect_success
'grep correctly finds patterns in a submodule' '
31 cat >expect <<-\EOF &&
34 submodule/a:(1|2)d(3|4)
37 git grep -e "(3|4)" --recurse-submodules >actual &&
38 test_cmp expect actual
41 test_expect_success
'grep finds patterns in a submodule via config' '
42 test_config submodule.recurse true &&
43 # expect from previous test
44 git grep -e "(3|4)" >actual &&
45 test_cmp expect actual
48 test_expect_success
'grep --no-recurse-submodules overrides config' '
49 test_config submodule.recurse true &&
50 cat >expect <<-\EOF &&
55 git grep -e "(3|4)" --no-recurse-submodules >actual &&
56 test_cmp expect actual
59 test_expect_success
'grep and basic pathspecs' '
60 cat >expect <<-\EOF &&
61 submodule/a:(1|2)d(3|4)
64 git grep -e. --recurse-submodules -- submodule >actual &&
65 test_cmp expect actual
68 test_expect_success
'grep and nested submodules' '
69 git init submodule/sub &&
70 echo "(1|2)d(3|4)" >submodule/sub/a &&
71 git -C submodule/sub add a &&
72 git -C submodule/sub commit -m "add a" &&
74 git -C submodule submodule add ./sub &&
75 git -C submodule add sub &&
76 git -C submodule commit -m "added sub" &&
79 git commit -m "updated submodule" &&
82 cat >expect <<-\EOF &&
85 submodule/a:(1|2)d(3|4)
86 submodule/sub/a:(1|2)d(3|4)
89 git grep -e "(3|4)" --recurse-submodules >actual &&
90 test_cmp expect actual
93 test_expect_success
'grep and multiple patterns' '
94 cat >expect <<-\EOF &&
96 submodule/a:(1|2)d(3|4)
97 submodule/sub/a:(1|2)d(3|4)
100 git grep -e "(3|4)" --and -e "(1|2)" --recurse-submodules >actual &&
101 test_cmp expect actual
104 test_expect_success
'grep and multiple patterns' '
105 cat >expect <<-\EOF &&
109 git grep -e "(3|4)" --and --not -e "(1|2)" --recurse-submodules >actual &&
110 test_cmp expect actual
113 test_expect_success
'basic grep tree' '
114 cat >expect <<-\EOF &&
117 HEAD:submodule/a:(1|2)d(3|4)
118 HEAD:submodule/sub/a:(1|2)d(3|4)
121 git grep -e "(3|4)" --recurse-submodules HEAD >actual &&
122 test_cmp expect actual
125 test_expect_success
'grep tree HEAD^' '
126 cat >expect <<-\EOF &&
129 HEAD^:submodule/a:(1|2)d(3|4)
132 git grep -e "(3|4)" --recurse-submodules HEAD^ >actual &&
133 test_cmp expect actual
136 test_expect_success
'grep tree HEAD^^' '
137 cat >expect <<-\EOF &&
142 git grep -e "(3|4)" --recurse-submodules HEAD^^ >actual &&
143 test_cmp expect actual
146 test_expect_success
'grep tree and pathspecs' '
147 cat >expect <<-\EOF &&
148 HEAD:submodule/a:(1|2)d(3|4)
149 HEAD:submodule/sub/a:(1|2)d(3|4)
152 git grep -e "(3|4)" --recurse-submodules HEAD -- submodule >actual &&
153 test_cmp expect actual
156 test_expect_success
'grep tree and pathspecs' '
157 cat >expect <<-\EOF &&
158 HEAD:submodule/a:(1|2)d(3|4)
159 HEAD:submodule/sub/a:(1|2)d(3|4)
162 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodule*a" >actual &&
163 test_cmp expect actual
166 test_expect_success
'grep tree and more pathspecs' '
167 cat >expect <<-\EOF &&
168 HEAD:submodule/a:(1|2)d(3|4)
171 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodul?/a" >actual &&
172 test_cmp expect actual
175 test_expect_success
'grep tree and more pathspecs' '
176 cat >expect <<-\EOF &&
177 HEAD:submodule/sub/a:(1|2)d(3|4)
180 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodul*/sub/a" >actual &&
181 test_cmp expect actual
184 test_expect_success
!MINGW
'grep recurse submodule colon in name' '
186 test_when_finished "rm -rf parent" &&
187 echo "(1|2)d(3|4)" >"parent/fi:le" &&
188 git -C parent add "fi:le" &&
189 git -C parent commit -m "add fi:le" &&
193 test_when_finished "rm -rf su:b" &&
194 echo "(1|2)d(3|4)" >"su:b/fi:le" &&
195 git -C "su:b" add "fi:le" &&
196 git -C "su:b" commit -m "add fi:le" &&
199 git -C parent submodule add "../su:b" "su:b" &&
200 git -C parent commit -m "add submodule" &&
203 cat >expect <<-\EOF &&
205 su:b/fi:le:(1|2)d(3|4)
207 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
208 test_cmp expect actual &&
210 cat >expect <<-\EOF &&
211 HEAD:fi:le:(1|2)d(3|4)
212 HEAD:su:b/fi:le:(1|2)d(3|4)
214 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules HEAD >actual &&
215 test_cmp expect actual
218 test_expect_success
'grep history with moved submoules' '
220 test_when_finished "rm -rf parent" &&
221 echo "(1|2)d(3|4)" >parent/file &&
222 git -C parent add file &&
223 git -C parent commit -m "add file" &&
227 test_when_finished "rm -rf sub" &&
228 echo "(1|2)d(3|4)" >sub/file &&
229 git -C sub add file &&
230 git -C sub commit -m "add file" &&
233 git -C parent submodule add ../sub dir/sub &&
234 git -C parent commit -m "add submodule" &&
237 cat >expect <<-\EOF &&
238 dir/sub/file:(1|2)d(3|4)
241 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
242 test_cmp expect actual &&
244 git -C parent mv dir/sub sub-moved &&
245 git -C parent commit -m "moved submodule" &&
248 cat >expect <<-\EOF &&
250 sub-moved/file:(1|2)d(3|4)
252 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
253 test_cmp expect actual &&
255 cat >expect <<-\EOF &&
256 HEAD^:dir/sub/file:(1|2)d(3|4)
257 HEAD^:file:(1|2)d(3|4)
259 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules HEAD^ >actual &&
260 test_cmp expect actual
263 test_expect_success
'grep using relative path' '
264 test_when_finished "rm -rf parent sub" &&
266 echo "(1|2)d(3|4)" >sub/file &&
267 git -C sub add file &&
268 git -C sub commit -m "add file" &&
272 echo "(1|2)d(3|4)" >parent/file &&
273 git -C parent add file &&
275 echo "(1|2)d(3|4)" >parent/src/file2 &&
276 git -C parent add src/file2 &&
277 git -C parent submodule add ../sub &&
278 git -C parent commit -m "add files and submodule" &&
282 cat >expect <<-\EOF &&
284 src/file2:(1|2)d(3|4)
287 git -C parent grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
288 test_cmp expect actual &&
290 # Relative path to top
291 cat >expect <<-\EOF &&
294 ../sub/file:(1|2)d(3|4)
296 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" -- .. >actual &&
297 test_cmp expect actual &&
299 # Relative path to submodule
300 cat >expect <<-\EOF &&
301 ../sub/file:(1|2)d(3|4)
303 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" -- ../sub >actual &&
304 test_cmp expect actual
307 test_expect_success
'grep from a subdir' '
308 test_when_finished "rm -rf parent sub" &&
310 echo "(1|2)d(3|4)" >sub/file &&
311 git -C sub add file &&
312 git -C sub commit -m "add file" &&
317 echo "(1|2)d(3|4)" >parent/src/file &&
318 git -C parent add src/file &&
319 git -C parent submodule add ../sub src/sub &&
320 git -C parent submodule add ../sub sub &&
321 git -C parent commit -m "add files and submodules" &&
324 # Verify grep from root works
325 cat >expect <<-\EOF &&
327 src/sub/file:(1|2)d(3|4)
330 git -C parent grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
331 test_cmp expect actual &&
333 # Verify grep from a subdir works
334 cat >expect <<-\EOF &&
338 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
339 test_cmp expect actual
342 test_incompatible_with_recurse_submodules
()
344 test_expect_success
"--recurse-submodules and $1 are incompatible" "
345 test_must_fail git grep -e. --recurse-submodules $1 2>actual &&
346 test_i18ngrep 'not supported with --recurse-submodules' actual
350 test_incompatible_with_recurse_submodules
--untracked
352 test_expect_success
'grep --recurse-submodules --no-index ignores --recurse-submodules' '
353 git grep --recurse-submodules --no-index -e "^(.|.)[\d]" >actual &&
354 cat >expect <<-\EOF &&
356 submodule/a:(1|2)d(3|4)
357 submodule/sub/a:(1|2)d(3|4)
359 test_cmp expect actual
362 test_expect_success
'grep --recurse-submodules should pass the pattern type along' '
364 test_must_fail git grep -F --recurse-submodules -e "(.|.)[\d]" &&
365 test_must_fail git -c grep.patternType=fixed grep --recurse-submodules -e "(.|.)[\d]" &&
368 git grep -G --recurse-submodules -e "(.|.)[\d]" >actual &&
369 cat >expect <<-\EOF &&
371 submodule/a:(1|2)d(3|4)
372 submodule/sub/a:(1|2)d(3|4)
374 test_cmp expect actual &&
375 git -c grep.patternType=basic grep --recurse-submodules -e "(.|.)[\d]" >actual &&
376 test_cmp expect actual &&
379 git grep -E --recurse-submodules -e "(.|.)[\d]" >actual &&
380 cat >expect <<-\EOF &&
381 .gitmodules:[submodule "submodule"]
382 .gitmodules: path = submodule
383 .gitmodules: url = ./submodule
385 submodule/.gitmodules:[submodule "sub"]
386 submodule/a:(1|2)d(3|4)
387 submodule/sub/a:(1|2)d(3|4)
389 test_cmp expect actual &&
390 git -c grep.patternType=extended grep --recurse-submodules -e "(.|.)[\d]" >actual &&
391 test_cmp expect actual &&
392 git -c grep.extendedRegexp=true grep --recurse-submodules -e "(.|.)[\d]" >actual &&
393 test_cmp expect actual &&
396 if test_have_prereq PCRE
398 git grep -P --recurse-submodules -e "(.|.)[\d]" >actual &&
399 cat >expect <<-\EOF &&
402 submodule/a:(1|2)d(3|4)
403 submodule/sub/a:(1|2)d(3|4)
405 test_cmp expect actual &&
406 git -c grep.patternType=perl grep --recurse-submodules -e "(.|.)[\d]" >actual &&
407 test_cmp expect actual
411 test_expect_success
'grep --recurse-submodules with submodules without .gitmodules in the working tree' '
412 test_when_finished "git -C submodule checkout .gitmodules" &&
413 rm submodule/.gitmodules &&
414 git grep --recurse-submodules -e "(.|.)[\d]" >actual &&
415 cat >expect <<-\EOF &&
417 submodule/a:(1|2)d(3|4)
418 submodule/sub/a:(1|2)d(3|4)
420 test_cmp expect actual
426 git submodule foreach
--recursive 'git reset --hard' &&
427 git submodule foreach
--recursive 'git clean -fd'
430 test_expect_success
'grep --recurse-submodules without --cached considers worktree modifications' '
432 echo "A modified line in submodule" >>submodule/a &&
433 echo "submodule/a:A modified line in submodule" >expect &&
434 git grep --recurse-submodules "A modified line in submodule" >actual &&
435 test_cmp expect actual
438 test_expect_success
'grep --recurse-submodules with --cached ignores worktree modifications' '
440 echo "A modified line in submodule" >>submodule/a &&
441 test_must_fail git grep --recurse-submodules --cached "A modified line in submodule" >actual 2>&1 &&
442 test_must_be_empty actual
445 test_expect_failure
'grep --textconv: superproject .gitattributes does not affect submodules' '
447 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
448 echo "a diff=d2x" >.gitattributes &&
450 cat >expect <<-\EOF &&
453 git grep --textconv --recurse-submodules x >actual &&
454 test_cmp expect actual
457 test_expect_failure
'grep --textconv: superproject .gitattributes (from index) does not affect submodules' '
459 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
460 echo "a diff=d2x" >.gitattributes &&
461 git add .gitattributes &&
464 cat >expect <<-\EOF &&
467 git grep --textconv --recurse-submodules x >actual &&
468 test_cmp expect actual
471 test_expect_failure
'grep --textconv: superproject .git/info/attributes does not affect submodules' '
473 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
474 super_attr="$(git rev-parse --git-path info/attributes)" &&
475 test_when_finished "rm -f \"$super_attr\"" &&
476 echo "a diff=d2x" >"$super_attr" &&
478 cat >expect <<-\EOF &&
481 git grep --textconv --recurse-submodules x >actual &&
482 test_cmp expect actual
485 # Note: what currently prevents this test from passing is not that the
486 # .gitattributes file from "./submodule" is being ignored, but that it is being
487 # propagated to the nested "./submodule/sub" files.
489 test_expect_failure
'grep --textconv correctly reads submodule .gitattributes' '
491 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
492 echo "a diff=d2x" >submodule/.gitattributes &&
494 cat >expect <<-\EOF &&
495 submodule/a:(1|2)x(3|4)
497 git grep --textconv --recurse-submodules x >actual &&
498 test_cmp expect actual
501 test_expect_failure
'grep --textconv correctly reads submodule .gitattributes (from index)' '
503 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
504 echo "a diff=d2x" >submodule/.gitattributes &&
505 git -C submodule add .gitattributes &&
506 rm submodule/.gitattributes &&
508 cat >expect <<-\EOF &&
509 submodule/a:(1|2)x(3|4)
511 git grep --textconv --recurse-submodules x >actual &&
512 test_cmp expect actual
515 test_expect_failure
'grep --textconv correctly reads submodule .git/info/attributes' '
517 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
519 submodule_attr="$(git -C submodule rev-parse --path-format=absolute --git-path info/attributes)" &&
520 test_when_finished "rm -f \"$submodule_attr\"" &&
521 echo "a diff=d2x" >"$submodule_attr" &&
523 cat >expect <<-\EOF &&
524 submodule/a:(1|2)x(3|4)
526 git grep --textconv --recurse-submodules x >actual &&
527 test_cmp expect actual
530 test_expect_failure
'grep saves textconv cache in the appropriate repository' '
532 test_config_global diff.d2x_cached.textconv "sed -e \"s/d/x/\"" &&
533 test_config_global diff.d2x_cached.cachetextconv true &&
534 echo "a diff=d2x_cached" >submodule/.gitattributes &&
536 # We only read/write to the textconv cache when grepping from an OID,
537 # as the working tree file might have modifications.
538 git grep --textconv --cached --recurse-submodules x &&
540 super_textconv_cache="$(git rev-parse --git-path refs/notes/textconv/d2x_cached)" &&
541 sub_textconv_cache="$(git -C submodule rev-parse \
542 --path-format=absolute --git-path refs/notes/textconv/d2x_cached)" &&
543 test_path_is_missing "$super_textconv_cache" &&
544 test_path_is_file "$sub_textconv_cache"