| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description=check-ignore |
| 4 | |
| 5 | TEST_CREATE_REPO_NO_TEMPLATE=1 |
| 6 | . ./test-lib.sh |
| 7 | |
| 8 | init_vars () { |
| 9 | global_excludes="global-excludes" |
| 10 | } |
| 11 | |
| 12 | enable_global_excludes () { |
| 13 | init_vars && |
| 14 | git config core.excludesfile "$global_excludes" |
| 15 | } |
| 16 | |
| 17 | expect_in () { |
| 18 | dest="$HOME/expected-$1" text="$2" |
| 19 | if test -z "$text" |
| 20 | then |
| 21 | >"$dest" # avoid newline |
| 22 | else |
| 23 | echo "$text" >"$dest" |
| 24 | fi |
| 25 | } |
| 26 | |
| 27 | expect () { |
| 28 | expect_in stdout "$1" |
| 29 | } |
| 30 | |
| 31 | expect_from_stdin () { |
| 32 | cat >"$HOME/expected-stdout" |
| 33 | } |
| 34 | |
| 35 | test_stderr () { |
| 36 | expected="$1" |
| 37 | expect_in stderr "$1" && |
| 38 | test_cmp "$HOME/expected-stderr" "$HOME/stderr" |
| 39 | } |
| 40 | |
| 41 | broken_c_unquote () { |
| 42 | sed -e 's/^"//' -e 's/\\//' -e 's/"$//' "$1" | tr '\n' '\0' |
| 43 | } |
| 44 | |
| 45 | broken_c_unquote_verbose () { |
| 46 | sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' "$1" | tr ':\t\n' '\000' |
| 47 | } |
| 48 | |
| 49 | stderr_contains () { |
| 50 | regexp="$1" |
| 51 | if test_grep "$regexp" "$HOME/stderr" |
| 52 | then |
| 53 | return 0 |
| 54 | else |
| 55 | echo "didn't find /$regexp/ in $HOME/stderr" |
| 56 | cat "$HOME/stderr" |
| 57 | return 1 |
| 58 | fi |
| 59 | } |
| 60 | |
| 61 | stderr_empty_on_success () { |
| 62 | expect_code="$1" |
| 63 | if test $expect_code = 0 |
| 64 | then |
| 65 | test_stderr "" |
| 66 | else |
| 67 | # If we expect failure then stderr might or might not be empty |
| 68 | # due to --quiet - the caller can check its contents |
| 69 | return 0 |
| 70 | fi |
| 71 | } |
| 72 | |
| 73 | test_check_ignore () { |
| 74 | args="$1" expect_code="${2:-0}" global_args="$3" |
| 75 | |
| 76 | init_vars && |
| 77 | rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" && |
| 78 | echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \ |
| 79 | >"$HOME/cmd" && |
| 80 | echo "$expect_code" >"$HOME/expected-exit-code" && |
| 81 | test_expect_code "$expect_code" \ |
| 82 | git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \ |
| 83 | >"$HOME/stdout" 2>"$HOME/stderr" && |
| 84 | test_cmp "$HOME/expected-stdout" "$HOME/stdout" && |
| 85 | stderr_empty_on_success "$expect_code" |
| 86 | } |
| 87 | |
| 88 | # Runs the same code with 4 different levels of output verbosity: |
| 89 | # |
| 90 | # 1. with -q / --quiet |
| 91 | # 2. with default verbosity |
| 92 | # 3. with -v / --verbose |
| 93 | # 4. with -v / --verbose, *and* -n / --non-matching |
| 94 | # |
| 95 | # expecting success each time. Takes advantage of the fact that |
| 96 | # check-ignore --verbose output is the same as normal output except |
| 97 | # for the extra first column. |
| 98 | # |
| 99 | # A parameter is used to determine if the tests are run with the |
| 100 | # normal case (using the index), or with the --no-index option. |
| 101 | # |
| 102 | # Arguments: |
| 103 | # - (optional) prereqs for this test, e.g. 'SYMLINKS' |
| 104 | # - test name |
| 105 | # - output to expect from the fourth verbosity mode (the output |
| 106 | # from the other verbosity modes is automatically inferred |
| 107 | # from this value) |
| 108 | # - code to run (should invoke test_check_ignore) |
| 109 | # - index option: --index or --no-index |
| 110 | test_expect_success_multiple () { |
| 111 | prereq= |
| 112 | if test $# -eq 5 |
| 113 | then |
| 114 | prereq=$1 |
| 115 | shift |
| 116 | fi |
| 117 | if test "$4" = "--index" |
| 118 | then |
| 119 | no_index_opt= |
| 120 | else |
| 121 | no_index_opt=$4 |
| 122 | fi |
| 123 | testname="$1" expect_all="$2" code="$3" |
| 124 | |
| 125 | expect_verbose=$(echo "$expect_all" | grep -v '^:: ' || :) |
| 126 | expect=$(echo "$expect_verbose" | sed -e 's/.* //') |
| 127 | |
| 128 | test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" ' |
| 129 | expect "$expect" && |
| 130 | eval "$code" |
| 131 | ' |
| 132 | |
| 133 | # --quiet is only valid when a single pattern is passed |
| 134 | if test $( echo "$expect_all" | wc -l ) = 1 |
| 135 | then |
| 136 | for quiet_opt in '-q' '--quiet' |
| 137 | do |
| 138 | opts="${no_index_opt:+$no_index_opt }$quiet_opt" |
| 139 | test_expect_success $prereq "$testname${opts:+ with $opts}" " |
| 140 | expect '' && |
| 141 | $code |
| 142 | " |
| 143 | done |
| 144 | quiet_opt= |
| 145 | fi |
| 146 | |
| 147 | for verbose_opt in '-v' '--verbose' |
| 148 | do |
| 149 | for non_matching_opt in '' '-n' '--non-matching' |
| 150 | do |
| 151 | if test -n "$non_matching_opt" |
| 152 | then |
| 153 | my_expect="$expect_all" |
| 154 | else |
| 155 | my_expect="$expect_verbose" |
| 156 | fi |
| 157 | |
| 158 | test_code=" |
| 159 | expect '$my_expect' && |
| 160 | $code |
| 161 | " |
| 162 | opts="${no_index_opt:+$no_index_opt }$verbose_opt${non_matching_opt:+ $non_matching_opt}" |
| 163 | test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code" |
| 164 | done |
| 165 | done |
| 166 | verbose_opt= |
| 167 | non_matching_opt= |
| 168 | no_index_opt= |
| 169 | } |
| 170 | |
| 171 | test_expect_success_multi () { |
| 172 | test_expect_success_multiple "$@" "--index" |
| 173 | } |
| 174 | |
| 175 | test_expect_success_no_index_multi () { |
| 176 | test_expect_success_multiple "$@" "--no-index" |
| 177 | } |
| 178 | |
| 179 | test_expect_success 'setup' ' |
| 180 | init_vars && |
| 181 | mkdir -p a/b/ignored-dir a/submodule b && |
| 182 | if test_have_prereq SYMLINKS |
| 183 | then |
| 184 | ln -s b a/symlink |
| 185 | fi && |
| 186 | ( |
| 187 | cd a/submodule && |
| 188 | git init && |
| 189 | echo a >a && |
| 190 | git add a && |
| 191 | git commit -m"commit in submodule" |
| 192 | ) && |
| 193 | git add a/submodule && |
| 194 | cat <<-\EOF >.gitignore && |
| 195 | one |
| 196 | ignored-* |
| 197 | top-level-dir/ |
| 198 | EOF |
| 199 | for dir in . a |
| 200 | do |
| 201 | : >$dir/not-ignored && |
| 202 | : >$dir/ignored-and-untracked && |
| 203 | : >$dir/ignored-but-in-index || return 1 |
| 204 | done && |
| 205 | git add -f ignored-but-in-index a/ignored-but-in-index && |
| 206 | cat <<-\EOF >a/.gitignore && |
| 207 | two* |
| 208 | *three |
| 209 | EOF |
| 210 | cat <<-\EOF >a/b/.gitignore && |
| 211 | four |
| 212 | five |
| 213 | # this comment should affect the line numbers |
| 214 | six |
| 215 | ignored-dir/ |
| 216 | # and so should this blank line: |
| 217 | |
| 218 | !on* |
| 219 | !two |
| 220 | EOF |
| 221 | echo "seven" >a/b/ignored-dir/.gitignore && |
| 222 | test -n "$HOME" && |
| 223 | cat <<-\EOF >"$global_excludes" && |
| 224 | globalone |
| 225 | !globaltwo |
| 226 | globalthree |
| 227 | EOF |
| 228 | mkdir .git/info && |
| 229 | cat <<-\EOF >.git/info/exclude |
| 230 | per-repo |
| 231 | EOF |
| 232 | ' |
| 233 | |
| 234 | ############################################################################ |
| 235 | # |
| 236 | # test invalid inputs |
| 237 | |
| 238 | test_expect_success_multi '. corner-case' ':: .' ' |
| 239 | test_check_ignore . 1 |
| 240 | ' |
| 241 | |
| 242 | test_expect_success_multi 'empty command line' '' ' |
| 243 | test_check_ignore "" 128 && |
| 244 | stderr_contains "fatal: no path specified" |
| 245 | ' |
| 246 | |
| 247 | test_expect_success_multi '--stdin with empty STDIN' '' ' |
| 248 | test_check_ignore "--stdin" 1 </dev/null && |
| 249 | test_stderr "" |
| 250 | ' |
| 251 | |
| 252 | test_expect_success '-q with multiple args' ' |
| 253 | expect "" && |
| 254 | test_check_ignore "-q one two" 128 && |
| 255 | stderr_contains "fatal: --quiet is only valid with a single pathname" |
| 256 | ' |
| 257 | |
| 258 | test_expect_success '--quiet with multiple args' ' |
| 259 | expect "" && |
| 260 | test_check_ignore "--quiet one two" 128 && |
| 261 | stderr_contains "fatal: --quiet is only valid with a single pathname" |
| 262 | ' |
| 263 | |
| 264 | for verbose_opt in '-v' '--verbose' |
| 265 | do |
| 266 | for quiet_opt in '-q' '--quiet' |
| 267 | do |
| 268 | test_expect_success "$quiet_opt $verbose_opt" " |
| 269 | expect '' && |
| 270 | test_check_ignore '$quiet_opt $verbose_opt foo' 128 && |
| 271 | stderr_contains 'fatal: cannot have both --quiet and --verbose' |
| 272 | " |
| 273 | done |
| 274 | done |
| 275 | |
| 276 | test_expect_success '--quiet with multiple args' ' |
| 277 | expect "" && |
| 278 | test_check_ignore "--quiet one two" 128 && |
| 279 | stderr_contains "fatal: --quiet is only valid with a single pathname" |
| 280 | ' |
| 281 | |
| 282 | test_expect_success_multi 'erroneous use of --' '' ' |
| 283 | test_check_ignore "--" 128 && |
| 284 | stderr_contains "fatal: no path specified" |
| 285 | ' |
| 286 | |
| 287 | test_expect_success_multi '--stdin with superfluous arg' '' ' |
| 288 | test_check_ignore "--stdin foo" 128 && |
| 289 | stderr_contains "fatal: cannot specify pathnames with --stdin" |
| 290 | ' |
| 291 | |
| 292 | test_expect_success_multi '--stdin -z with superfluous arg' '' ' |
| 293 | test_check_ignore "--stdin -z foo" 128 && |
| 294 | stderr_contains "fatal: cannot specify pathnames with --stdin" |
| 295 | ' |
| 296 | |
| 297 | test_expect_success_multi '-z without --stdin' '' ' |
| 298 | test_check_ignore "-z" 128 && |
| 299 | stderr_contains "fatal: -z only makes sense with --stdin" |
| 300 | ' |
| 301 | |
| 302 | test_expect_success_multi '-z without --stdin and superfluous arg' '' ' |
| 303 | test_check_ignore "-z foo" 128 && |
| 304 | stderr_contains "fatal: -z only makes sense with --stdin" |
| 305 | ' |
| 306 | |
| 307 | test_expect_success_multi 'needs work tree' '' ' |
| 308 | ( |
| 309 | cd .git && |
| 310 | test_check_ignore "foo" 128 |
| 311 | ) && |
| 312 | stderr_contains "fatal: this operation must be run in a work tree" |
| 313 | ' |
| 314 | |
| 315 | ############################################################################ |
| 316 | # |
| 317 | # test standard ignores |
| 318 | |
| 319 | # First make sure that the presence of a file in the working tree |
| 320 | # does not impact results, but that the presence of a file in the |
| 321 | # index does unless the --no-index option is used. |
| 322 | |
| 323 | for subdir in '' 'a/' |
| 324 | do |
| 325 | if test -z "$subdir" |
| 326 | then |
| 327 | where="at top-level" |
| 328 | else |
| 329 | where="in subdir $subdir" |
| 330 | fi |
| 331 | |
| 332 | test_expect_success_multi "non-existent file $where not ignored" \ |
| 333 | ":: ${subdir}non-existent" \ |
| 334 | "test_check_ignore '${subdir}non-existent' 1" |
| 335 | |
| 336 | test_expect_success_no_index_multi "non-existent file $where not ignored" \ |
| 337 | ":: ${subdir}non-existent" \ |
| 338 | "test_check_ignore '${subdir}non-existent' 1" |
| 339 | |
| 340 | test_expect_success_multi "non-existent file $where ignored" \ |
| 341 | ".gitignore:1:one ${subdir}one" \ |
| 342 | "test_check_ignore '${subdir}one'" |
| 343 | |
| 344 | test_expect_success_no_index_multi "non-existent file $where ignored" \ |
| 345 | ".gitignore:1:one ${subdir}one" \ |
| 346 | "test_check_ignore '${subdir}one'" |
| 347 | |
| 348 | test_expect_success_multi "existing untracked file $where not ignored" \ |
| 349 | ":: ${subdir}not-ignored" \ |
| 350 | "test_check_ignore '${subdir}not-ignored' 1" |
| 351 | |
| 352 | test_expect_success_no_index_multi "existing untracked file $where not ignored" \ |
| 353 | ":: ${subdir}not-ignored" \ |
| 354 | "test_check_ignore '${subdir}not-ignored' 1" |
| 355 | |
| 356 | test_expect_success_multi "existing tracked file $where not ignored" \ |
| 357 | ":: ${subdir}ignored-but-in-index" \ |
| 358 | "test_check_ignore '${subdir}ignored-but-in-index' 1" |
| 359 | |
| 360 | test_expect_success_no_index_multi "existing tracked file $where shown as ignored" \ |
| 361 | ".gitignore:2:ignored-* ${subdir}ignored-but-in-index" \ |
| 362 | "test_check_ignore '${subdir}ignored-but-in-index'" |
| 363 | |
| 364 | test_expect_success_multi "existing untracked file $where ignored" \ |
| 365 | ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \ |
| 366 | "test_check_ignore '${subdir}ignored-and-untracked'" |
| 367 | |
| 368 | test_expect_success_no_index_multi "existing untracked file $where ignored" \ |
| 369 | ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \ |
| 370 | "test_check_ignore '${subdir}ignored-and-untracked'" |
| 371 | |
| 372 | test_expect_success_multi "mix of file types $where" \ |
| 373 | ":: ${subdir}non-existent |
| 374 | .gitignore:1:one ${subdir}one |
| 375 | :: ${subdir}not-ignored |
| 376 | :: ${subdir}ignored-but-in-index |
| 377 | .gitignore:2:ignored-* ${subdir}ignored-and-untracked" \ |
| 378 | "test_check_ignore ' |
| 379 | ${subdir}non-existent |
| 380 | ${subdir}one |
| 381 | ${subdir}not-ignored |
| 382 | ${subdir}ignored-but-in-index |
| 383 | ${subdir}ignored-and-untracked' |
| 384 | " |
| 385 | |
| 386 | test_expect_success_no_index_multi "mix of file types $where" \ |
| 387 | ":: ${subdir}non-existent |
| 388 | .gitignore:1:one ${subdir}one |
| 389 | :: ${subdir}not-ignored |
| 390 | .gitignore:2:ignored-* ${subdir}ignored-but-in-index |
| 391 | .gitignore:2:ignored-* ${subdir}ignored-and-untracked" \ |
| 392 | "test_check_ignore ' |
| 393 | ${subdir}non-existent |
| 394 | ${subdir}one |
| 395 | ${subdir}not-ignored |
| 396 | ${subdir}ignored-but-in-index |
| 397 | ${subdir}ignored-and-untracked' |
| 398 | " |
| 399 | done |
| 400 | |
| 401 | # Having established the above, from now on we mostly test against |
| 402 | # files which do not exist in the working tree or index. |
| 403 | |
| 404 | test_expect_success 'sub-directory local ignore' ' |
| 405 | expect "a/3-three" && |
| 406 | test_check_ignore "a/3-three a/three-not-this-one" |
| 407 | ' |
| 408 | |
| 409 | test_expect_success 'sub-directory local ignore with --verbose' ' |
| 410 | expect "a/.gitignore:2:*three a/3-three" && |
| 411 | test_check_ignore "--verbose a/3-three a/three-not-this-one" |
| 412 | ' |
| 413 | |
| 414 | test_expect_success 'local ignore inside a sub-directory' ' |
| 415 | expect "3-three" && |
| 416 | ( |
| 417 | cd a && |
| 418 | test_check_ignore "3-three three-not-this-one" |
| 419 | ) |
| 420 | ' |
| 421 | test_expect_success 'local ignore inside a sub-directory with --verbose' ' |
| 422 | expect "a/.gitignore:2:*three 3-three" && |
| 423 | ( |
| 424 | cd a && |
| 425 | test_check_ignore "--verbose 3-three three-not-this-one" |
| 426 | ) |
| 427 | ' |
| 428 | |
| 429 | test_expect_success 'nested include of negated pattern' ' |
| 430 | expect "" && |
| 431 | test_check_ignore "a/b/one" 1 |
| 432 | ' |
| 433 | |
| 434 | test_expect_success 'nested include of negated pattern with -q' ' |
| 435 | expect "" && |
| 436 | test_check_ignore "-q a/b/one" 1 |
| 437 | ' |
| 438 | |
| 439 | test_expect_success 'nested include of negated pattern with -v' ' |
| 440 | expect "a/b/.gitignore:8:!on* a/b/one" && |
| 441 | test_check_ignore "-v a/b/one" 0 |
| 442 | ' |
| 443 | |
| 444 | test_expect_success 'nested include of negated pattern with -v -n' ' |
| 445 | expect "a/b/.gitignore:8:!on* a/b/one" && |
| 446 | test_check_ignore "-v -n a/b/one" 0 |
| 447 | ' |
| 448 | |
| 449 | ############################################################################ |
| 450 | # |
| 451 | # test ignored sub-directories |
| 452 | |
| 453 | test_expect_success_multi 'ignored sub-directory' \ |
| 454 | 'a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir' ' |
| 455 | test_check_ignore "a/b/ignored-dir" |
| 456 | ' |
| 457 | |
| 458 | test_expect_success 'multiple files inside ignored sub-directory' ' |
| 459 | expect_from_stdin <<-\EOF && |
| 460 | a/b/ignored-dir/foo |
| 461 | a/b/ignored-dir/twoooo |
| 462 | a/b/ignored-dir/seven |
| 463 | EOF |
| 464 | test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven" |
| 465 | ' |
| 466 | |
| 467 | test_expect_success 'multiple files inside ignored sub-directory with -v' ' |
| 468 | expect_from_stdin <<-\EOF && |
| 469 | a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/foo |
| 470 | a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/twoooo |
| 471 | a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/seven |
| 472 | EOF |
| 473 | test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven" |
| 474 | ' |
| 475 | |
| 476 | test_expect_success 'cd to ignored sub-directory' ' |
| 477 | expect_from_stdin <<-\EOF && |
| 478 | foo |
| 479 | twoooo |
| 480 | seven |
| 481 | ../../one |
| 482 | EOF |
| 483 | ( |
| 484 | cd a/b/ignored-dir && |
| 485 | test_check_ignore "foo twoooo ../one seven ../../one" |
| 486 | ) |
| 487 | ' |
| 488 | |
| 489 | test_expect_success 'cd to ignored sub-directory with -v' ' |
| 490 | expect_from_stdin <<-\EOF && |
| 491 | a/b/.gitignore:5:ignored-dir/ foo |
| 492 | a/b/.gitignore:5:ignored-dir/ twoooo |
| 493 | a/b/.gitignore:8:!on* ../one |
| 494 | a/b/.gitignore:5:ignored-dir/ seven |
| 495 | .gitignore:1:one ../../one |
| 496 | EOF |
| 497 | ( |
| 498 | cd a/b/ignored-dir && |
| 499 | test_check_ignore "-v foo twoooo ../one seven ../../one" |
| 500 | ) |
| 501 | ' |
| 502 | |
| 503 | ############################################################################ |
| 504 | # |
| 505 | # test handling of symlinks |
| 506 | |
| 507 | test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' ' |
| 508 | test_check_ignore "a/symlink" 1 |
| 509 | ' |
| 510 | |
| 511 | test_expect_success_multi SYMLINKS 'beyond a symlink' '' ' |
| 512 | test_check_ignore "a/symlink/foo" 128 && |
| 513 | test_stderr "fatal: pathspec '\''a/symlink/foo'\'' is beyond a symbolic link" |
| 514 | ' |
| 515 | |
| 516 | test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' ' |
| 517 | ( |
| 518 | cd a && |
| 519 | test_check_ignore "symlink/foo" 128 |
| 520 | ) && |
| 521 | test_stderr "fatal: pathspec '\''symlink/foo'\'' is beyond a symbolic link" |
| 522 | ' |
| 523 | |
| 524 | ############################################################################ |
| 525 | # |
| 526 | # test handling of submodules |
| 527 | |
| 528 | test_expect_success_multi 'submodule' '' ' |
| 529 | test_check_ignore "a/submodule/one" 128 && |
| 530 | test_stderr "fatal: Pathspec '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''" |
| 531 | ' |
| 532 | |
| 533 | test_expect_success_multi 'submodule from subdirectory' '' ' |
| 534 | ( |
| 535 | cd a && |
| 536 | test_check_ignore "submodule/one" 128 |
| 537 | ) && |
| 538 | test_stderr "fatal: Pathspec '\''submodule/one'\'' is in submodule '\''a/submodule'\''" |
| 539 | ' |
| 540 | |
| 541 | ############################################################################ |
| 542 | # |
| 543 | # test handling of global ignore files |
| 544 | |
| 545 | test_expect_success 'global ignore not yet enabled' ' |
| 546 | expect_from_stdin <<-\EOF && |
| 547 | .git/info/exclude:1:per-repo per-repo |
| 548 | a/.gitignore:2:*three a/globalthree |
| 549 | .git/info/exclude:1:per-repo a/per-repo |
| 550 | EOF |
| 551 | test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo" |
| 552 | ' |
| 553 | |
| 554 | test_expect_success 'global ignore' ' |
| 555 | enable_global_excludes && |
| 556 | expect_from_stdin <<-\EOF && |
| 557 | globalone |
| 558 | per-repo |
| 559 | globalthree |
| 560 | a/globalthree |
| 561 | a/per-repo |
| 562 | EOF |
| 563 | test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo" |
| 564 | ' |
| 565 | |
| 566 | test_expect_success 'global ignore with -v' ' |
| 567 | enable_global_excludes && |
| 568 | expect_from_stdin <<-EOF && |
| 569 | $global_excludes:1:globalone globalone |
| 570 | .git/info/exclude:1:per-repo per-repo |
| 571 | $global_excludes:3:globalthree globalthree |
| 572 | a/.gitignore:2:*three a/globalthree |
| 573 | .git/info/exclude:1:per-repo a/per-repo |
| 574 | $global_excludes:2:!globaltwo globaltwo |
| 575 | EOF |
| 576 | test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo" |
| 577 | ' |
| 578 | |
| 579 | ############################################################################ |
| 580 | # |
| 581 | # test --stdin |
| 582 | |
| 583 | cat <<-\EOF >stdin |
| 584 | one |
| 585 | not-ignored |
| 586 | a/one |
| 587 | a/not-ignored |
| 588 | a/b/on |
| 589 | a/b/one |
| 590 | a/b/one one |
| 591 | "a/b/one two" |
| 592 | "a/b/one\"three" |
| 593 | a/b/not-ignored |
| 594 | a/b/two |
| 595 | a/b/twooo |
| 596 | globaltwo |
| 597 | a/globaltwo |
| 598 | a/b/globaltwo |
| 599 | b/globaltwo |
| 600 | EOF |
| 601 | cat <<-\EOF >expected-default |
| 602 | one |
| 603 | a/one |
| 604 | a/b/twooo |
| 605 | EOF |
| 606 | cat <<-EOF >expected-verbose |
| 607 | .gitignore:1:one one |
| 608 | .gitignore:1:one a/one |
| 609 | a/b/.gitignore:8:!on* a/b/on |
| 610 | a/b/.gitignore:8:!on* a/b/one |
| 611 | a/b/.gitignore:8:!on* a/b/one one |
| 612 | a/b/.gitignore:8:!on* a/b/one two |
| 613 | a/b/.gitignore:8:!on* "a/b/one\\"three" |
| 614 | a/b/.gitignore:9:!two a/b/two |
| 615 | a/.gitignore:1:two* a/b/twooo |
| 616 | $global_excludes:2:!globaltwo globaltwo |
| 617 | $global_excludes:2:!globaltwo a/globaltwo |
| 618 | $global_excludes:2:!globaltwo a/b/globaltwo |
| 619 | $global_excludes:2:!globaltwo b/globaltwo |
| 620 | EOF |
| 621 | |
| 622 | broken_c_unquote stdin >stdin0 |
| 623 | |
| 624 | broken_c_unquote expected-default >expected-default0 |
| 625 | |
| 626 | broken_c_unquote_verbose expected-verbose >expected-verbose0 |
| 627 | |
| 628 | test_expect_success '--stdin' ' |
| 629 | expect_from_stdin <expected-default && |
| 630 | test_check_ignore "--stdin" <stdin |
| 631 | ' |
| 632 | |
| 633 | test_expect_success '--stdin -q' ' |
| 634 | expect "" && |
| 635 | test_check_ignore "-q --stdin" <stdin |
| 636 | ' |
| 637 | |
| 638 | test_expect_success '--stdin -v' ' |
| 639 | expect_from_stdin <expected-verbose && |
| 640 | test_check_ignore "-v --stdin" <stdin |
| 641 | ' |
| 642 | |
| 643 | for opts in '--stdin -z' '-z --stdin' |
| 644 | do |
| 645 | test_expect_success "$opts" " |
| 646 | expect_from_stdin <expected-default0 && |
| 647 | test_check_ignore '$opts' <stdin0 |
| 648 | " |
| 649 | |
| 650 | test_expect_success "$opts -q" " |
| 651 | expect "" && |
| 652 | test_check_ignore '-q $opts' <stdin0 |
| 653 | " |
| 654 | |
| 655 | test_expect_success "$opts -v" " |
| 656 | expect_from_stdin <expected-verbose0 && |
| 657 | test_check_ignore '-v $opts' <stdin0 |
| 658 | " |
| 659 | done |
| 660 | |
| 661 | cat <<-\EOF >stdin |
| 662 | ../one |
| 663 | ../not-ignored |
| 664 | one |
| 665 | not-ignored |
| 666 | b/on |
| 667 | b/one |
| 668 | b/one one |
| 669 | "b/one two" |
| 670 | "b/one\"three" |
| 671 | b/two |
| 672 | b/not-ignored |
| 673 | b/twooo |
| 674 | ../globaltwo |
| 675 | globaltwo |
| 676 | b/globaltwo |
| 677 | ../b/globaltwo |
| 678 | c/not-ignored |
| 679 | EOF |
| 680 | # N.B. we deliberately end STDIN with a non-matching pattern in order |
| 681 | # to test that the exit code indicates that one or more of the |
| 682 | # provided paths is ignored - in other words, that it represents an |
| 683 | # aggregation of all the results, not just the final result. |
| 684 | |
| 685 | cat <<-EOF >expected-all |
| 686 | .gitignore:1:one ../one |
| 687 | :: ../not-ignored |
| 688 | .gitignore:1:one one |
| 689 | :: not-ignored |
| 690 | a/b/.gitignore:8:!on* b/on |
| 691 | a/b/.gitignore:8:!on* b/one |
| 692 | a/b/.gitignore:8:!on* b/one one |
| 693 | a/b/.gitignore:8:!on* b/one two |
| 694 | a/b/.gitignore:8:!on* "b/one\\"three" |
| 695 | a/b/.gitignore:9:!two b/two |
| 696 | :: b/not-ignored |
| 697 | a/.gitignore:1:two* b/twooo |
| 698 | $global_excludes:2:!globaltwo ../globaltwo |
| 699 | $global_excludes:2:!globaltwo globaltwo |
| 700 | $global_excludes:2:!globaltwo b/globaltwo |
| 701 | $global_excludes:2:!globaltwo ../b/globaltwo |
| 702 | :: c/not-ignored |
| 703 | EOF |
| 704 | cat <<-EOF >expected-default |
| 705 | ../one |
| 706 | one |
| 707 | b/twooo |
| 708 | EOF |
| 709 | grep -v '^:: ' expected-all >expected-verbose |
| 710 | |
| 711 | broken_c_unquote stdin >stdin0 |
| 712 | |
| 713 | broken_c_unquote expected-default >expected-default0 |
| 714 | |
| 715 | broken_c_unquote_verbose expected-verbose >expected-verbose0 |
| 716 | |
| 717 | test_expect_success '--stdin from subdirectory' ' |
| 718 | expect_from_stdin <expected-default && |
| 719 | ( |
| 720 | cd a && |
| 721 | test_check_ignore "--stdin" <../stdin |
| 722 | ) |
| 723 | ' |
| 724 | |
| 725 | test_expect_success '--stdin from subdirectory with -v' ' |
| 726 | expect_from_stdin <expected-verbose && |
| 727 | ( |
| 728 | cd a && |
| 729 | test_check_ignore "--stdin -v" <../stdin |
| 730 | ) |
| 731 | ' |
| 732 | |
| 733 | test_expect_success '--stdin from subdirectory with -v -n' ' |
| 734 | expect_from_stdin <expected-all && |
| 735 | ( |
| 736 | cd a && |
| 737 | test_check_ignore "--stdin -v -n" <../stdin |
| 738 | ) |
| 739 | ' |
| 740 | |
| 741 | for opts in '--stdin -z' '-z --stdin' |
| 742 | do |
| 743 | test_expect_success "$opts from subdirectory" ' |
| 744 | expect_from_stdin <expected-default0 && |
| 745 | ( |
| 746 | cd a && |
| 747 | test_check_ignore "'"$opts"'" <../stdin0 |
| 748 | ) |
| 749 | ' |
| 750 | |
| 751 | test_expect_success "$opts from subdirectory with -v" ' |
| 752 | expect_from_stdin <expected-verbose0 && |
| 753 | ( |
| 754 | cd a && |
| 755 | test_check_ignore "'"$opts"' -v" <../stdin0 |
| 756 | ) |
| 757 | ' |
| 758 | done |
| 759 | |
| 760 | test_expect_success PIPE 'streaming support for --stdin' ' |
| 761 | mkfifo in out && |
| 762 | (git check-ignore -n -v --stdin <in >out &) && |
| 763 | |
| 764 | # We cannot just "echo >in" because check-ignore would get EOF |
| 765 | # after echo exited; instead we open the descriptor in our |
| 766 | # shell, and then echo to the fd. We make sure to close it at |
| 767 | # the end, so that the subprocess does get EOF and dies |
| 768 | # properly. |
| 769 | # |
| 770 | # Similarly, we must keep "out" open so that check-ignore does |
| 771 | # not ever get SIGPIPE trying to write to us. Not only would that |
| 772 | # produce incorrect results, but then there would be no writer on the |
| 773 | # other end of the pipe, and we would potentially block forever trying |
| 774 | # to open it. |
| 775 | exec 9>in && |
| 776 | exec 8<out && |
| 777 | test_when_finished "exec 9>&-" && |
| 778 | test_when_finished "exec 8<&-" && |
| 779 | echo >&9 one && |
| 780 | read response <&8 && |
| 781 | echo "$response" | grep "^\.gitignore:1:one one" && |
| 782 | echo >&9 two && |
| 783 | read response <&8 && |
| 784 | echo "$response" | grep "^:: two" |
| 785 | ' |
| 786 | |
| 787 | test_expect_success 'existing file and directory' ' |
| 788 | test_when_finished "rm one" && |
| 789 | test_when_finished "rmdir top-level-dir" && |
| 790 | >one && |
| 791 | mkdir top-level-dir && |
| 792 | git check-ignore one top-level-dir >actual && |
| 793 | test_grep one actual && |
| 794 | test_grep top-level-dir actual |
| 795 | ' |
| 796 | |
| 797 | test_expect_success 'existing directory and file' ' |
| 798 | test_when_finished "rm one" && |
| 799 | test_when_finished "rmdir top-level-dir" && |
| 800 | >one && |
| 801 | mkdir top-level-dir && |
| 802 | git check-ignore top-level-dir one >actual && |
| 803 | test_grep one actual && |
| 804 | test_grep top-level-dir actual |
| 805 | ' |
| 806 | |
| 807 | test_expect_success 'exact prefix matching (with root)' ' |
| 808 | test_when_finished rm -r a && |
| 809 | mkdir -p a/git a/git-foo && |
| 810 | touch a/git/foo a/git-foo/bar && |
| 811 | echo /git/ >a/.gitignore && |
| 812 | git check-ignore a/git a/git/foo a/git-foo a/git-foo/bar >actual && |
| 813 | cat >expect <<-\EOF && |
| 814 | a/git |
| 815 | a/git/foo |
| 816 | EOF |
| 817 | test_cmp expect actual |
| 818 | ' |
| 819 | |
| 820 | test_expect_success 'exact prefix matching (without root)' ' |
| 821 | test_when_finished rm -r a && |
| 822 | mkdir -p a/git a/git-foo && |
| 823 | touch a/git/foo a/git-foo/bar && |
| 824 | echo git/ >a/.gitignore && |
| 825 | git check-ignore a/git a/git/foo a/git-foo a/git-foo/bar >actual && |
| 826 | cat >expect <<-\EOF && |
| 827 | a/git |
| 828 | a/git/foo |
| 829 | EOF |
| 830 | test_cmp expect actual |
| 831 | ' |
| 832 | |
| 833 | test_expect_success 'directories and ** matches' ' |
| 834 | cat >.gitignore <<-\EOF && |
| 835 | data/** |
| 836 | !data/**/ |
| 837 | !data/**/*.txt |
| 838 | EOF |
| 839 | git check-ignore file \ |
| 840 | data/file data/data1/file1 data/data1/file1.txt \ |
| 841 | data/data2/file2 data/data2/file2.txt >actual && |
| 842 | cat >expect <<-\EOF && |
| 843 | data/file |
| 844 | data/data1/file1 |
| 845 | data/data2/file2 |
| 846 | EOF |
| 847 | test_cmp expect actual |
| 848 | ' |
| 849 | |
| 850 | test_expect_success '** not confused by matching leading prefix' ' |
| 851 | cat >.gitignore <<-\EOF && |
| 852 | foo**/bar |
| 853 | EOF |
| 854 | git check-ignore foobar foo/bar >actual && |
| 855 | cat >expect <<-\EOF && |
| 856 | foo/bar |
| 857 | EOF |
| 858 | test_cmp expect actual |
| 859 | ' |
| 860 | |
| 861 | ############################################################################ |
| 862 | # |
| 863 | # test whitespace handling |
| 864 | |
| 865 | test_expect_success 'trailing whitespace is ignored' ' |
| 866 | mkdir whitespace && |
| 867 | >whitespace/trailing && |
| 868 | >whitespace/untracked && |
| 869 | echo "whitespace/trailing " >ignore && |
| 870 | cat >expect <<EOF && |
| 871 | whitespace/untracked |
| 872 | EOF |
| 873 | git ls-files -o -X ignore whitespace >actual 2>err && |
| 874 | test_cmp expect actual && |
| 875 | test_must_be_empty err |
| 876 | ' |
| 877 | |
| 878 | test_expect_success !MINGW 'quoting allows trailing whitespace' ' |
| 879 | rm -rf whitespace && |
| 880 | mkdir whitespace && |
| 881 | >"whitespace/trailing " && |
| 882 | >whitespace/untracked && |
| 883 | echo "whitespace/trailing\\ \\ " >ignore && |
| 884 | echo whitespace/untracked >expect && |
| 885 | git ls-files -o -X ignore whitespace >actual 2>err && |
| 886 | test_cmp expect actual && |
| 887 | test_must_be_empty err |
| 888 | ' |
| 889 | |
| 890 | test_expect_success !MINGW,!CYGWIN 'correct handling of backslashes' ' |
| 891 | rm -rf whitespace && |
| 892 | mkdir whitespace && |
| 893 | >"whitespace/trailing 1 " && |
| 894 | >"whitespace/trailing 2 \\\\" && |
| 895 | >"whitespace/trailing 3 \\\\" && |
| 896 | >"whitespace/trailing 4 \\ " && |
| 897 | >"whitespace/trailing 5 \\ \\ " && |
| 898 | >"whitespace/trailing 6 \\a\\" && |
| 899 | >whitespace/untracked && |
| 900 | sed -e "s/Z$//" >ignore <<-\EOF && |
| 901 | whitespace/trailing 1 \ Z |
| 902 | whitespace/trailing 2 \\\\Z |
| 903 | whitespace/trailing 3 \\\\ Z |
| 904 | whitespace/trailing 4 \\\ Z |
| 905 | whitespace/trailing 5 \\ \\\ Z |
| 906 | whitespace/trailing 6 \\a\\Z |
| 907 | EOF |
| 908 | echo whitespace/untracked >expect && |
| 909 | git ls-files -o -X ignore whitespace >actual 2>err && |
| 910 | test_cmp expect actual && |
| 911 | test_must_be_empty err |
| 912 | ' |
| 913 | |
| 914 | test_expect_success 'info/exclude trumps core.excludesfile' ' |
| 915 | echo >>global-excludes usually-ignored && |
| 916 | echo >>.git/info/exclude "!usually-ignored" && |
| 917 | >usually-ignored && |
| 918 | echo "?? usually-ignored" >expect && |
| 919 | |
| 920 | git status --porcelain usually-ignored >actual && |
| 921 | test_cmp expect actual |
| 922 | ' |
| 923 | |
| 924 | test_expect_success SYMLINKS 'set up ignore file for symlink tests' ' |
| 925 | echo "*" >ignore && |
| 926 | rm -f .gitignore .git/info/exclude |
| 927 | ' |
| 928 | |
| 929 | test_expect_success SYMLINKS 'symlinks respected in core.excludesFile' ' |
| 930 | test_when_finished "rm symlink" && |
| 931 | ln -s ignore symlink && |
| 932 | test_config core.excludesFile "$(pwd)/symlink" && |
| 933 | echo file >expect && |
| 934 | git check-ignore file >actual 2>err && |
| 935 | test_cmp expect actual && |
| 936 | test_must_be_empty err |
| 937 | ' |
| 938 | |
| 939 | test_expect_success SYMLINKS 'symlinks respected in info/exclude' ' |
| 940 | test_when_finished "rm .git/info/exclude" && |
| 941 | ln -s ../../ignore .git/info/exclude && |
| 942 | echo file >expect && |
| 943 | git check-ignore file >actual 2>err && |
| 944 | test_cmp expect actual && |
| 945 | test_must_be_empty err |
| 946 | ' |
| 947 | |
| 948 | test_expect_success SYMLINKS 'symlinks not respected in-tree' ' |
| 949 | test_when_finished "rm -rf subdir .gitignore err actual" && |
| 950 | ln -s ignore .gitignore && |
| 951 | mkdir subdir && |
| 952 | ln -s ignore subdir/.gitignore && |
| 953 | test_must_fail git check-ignore subdir/file >actual 2>err && |
| 954 | test_must_be_empty actual && |
| 955 | test_grep "unable to access.*gitignore" err |
| 956 | ' |
| 957 | |
| 958 | test_expect_success EXPENSIVE 'large exclude file ignored in tree' ' |
| 959 | test_when_finished "rm .gitignore" && |
| 960 | find . -name .gitignore -exec rm "{}" ";" && |
| 961 | dd if=/dev/zero of=.gitignore bs=101M count=1 && |
| 962 | git ls-files -o --exclude-standard 2>err && |
| 963 | echo "warning: ignoring excessively large pattern file: .gitignore" >expect && |
| 964 | test_cmp expect err |
| 965 | ' |
| 966 | |
| 967 | test_done |