t / t7063-status-untracked-cache.shon commit Merge branch 'jh/status-v2-porcelain' (00d2793)
   1#!/bin/sh
   2
   3test_description='test untracked cache'
   4
   5. ./test-lib.sh
   6
   7# On some filesystems (e.g. FreeBSD's ext2 and ufs) directory mtime
   8# is updated lazily after contents in the directory changes, which
   9# forces the untracked cache code to take the slow path.  A test
  10# that wants to make sure that the fast path works correctly should
  11# call this helper to make mtime of the containing directory in sync
  12# with the reality before checking the fast path behaviour.
  13#
  14# See <20160803174522.5571-1-pclouds@gmail.com> if you want to know
  15# more.
  16
  17sync_mtime () {
  18        find . -type d -ls >/dev/null
  19}
  20
  21avoid_racy() {
  22        sleep 1
  23}
  24
  25test_lazy_prereq UNTRACKED_CACHE '
  26        { git update-index --test-untracked-cache; ret=$?; } &&
  27        test $ret -ne 1
  28'
  29
  30if ! test_have_prereq UNTRACKED_CACHE; then
  31        skip_all='This system does not support untracked cache'
  32        test_done
  33fi
  34
  35test_expect_success 'core.untrackedCache is unset' '
  36        test_must_fail git config --get core.untrackedCache
  37'
  38
  39test_expect_success 'setup' '
  40        git init worktree &&
  41        cd worktree &&
  42        mkdir done dtwo dthree &&
  43        touch one two three done/one dtwo/two dthree/three &&
  44        git add one two done/one &&
  45        : >.git/info/exclude &&
  46        git update-index --untracked-cache
  47'
  48
  49test_expect_success 'untracked cache is empty' '
  50        test-dump-untracked-cache >../actual &&
  51        cat >../expect-empty <<EOF &&
  52info/exclude 0000000000000000000000000000000000000000
  53core.excludesfile 0000000000000000000000000000000000000000
  54exclude_per_dir .gitignore
  55flags 00000006
  56EOF
  57        test_cmp ../expect-empty ../actual
  58'
  59
  60cat >../status.expect <<EOF &&
  61A  done/one
  62A  one
  63A  two
  64?? dthree/
  65?? dtwo/
  66?? three
  67EOF
  68
  69cat >../dump.expect <<EOF &&
  70info/exclude $EMPTY_BLOB
  71core.excludesfile 0000000000000000000000000000000000000000
  72exclude_per_dir .gitignore
  73flags 00000006
  74/ 0000000000000000000000000000000000000000 recurse valid
  75dthree/
  76dtwo/
  77three
  78/done/ 0000000000000000000000000000000000000000 recurse valid
  79/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
  80three
  81/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
  82two
  83EOF
  84
  85test_expect_success 'status first time (empty cache)' '
  86        avoid_racy &&
  87        : >../trace &&
  88        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
  89        git status --porcelain >../actual &&
  90        test_cmp ../status.expect ../actual &&
  91        cat >../trace.expect <<EOF &&
  92node creation: 3
  93gitignore invalidation: 1
  94directory invalidation: 0
  95opendir: 4
  96EOF
  97        test_cmp ../trace.expect ../trace
  98'
  99
 100test_expect_success 'untracked cache after first status' '
 101        test-dump-untracked-cache >../actual &&
 102        test_cmp ../dump.expect ../actual
 103'
 104
 105test_expect_success 'status second time (fully populated cache)' '
 106        avoid_racy &&
 107        : >../trace &&
 108        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 109        git status --porcelain >../actual &&
 110        test_cmp ../status.expect ../actual &&
 111        cat >../trace.expect <<EOF &&
 112node creation: 0
 113gitignore invalidation: 0
 114directory invalidation: 0
 115opendir: 0
 116EOF
 117        test_cmp ../trace.expect ../trace
 118'
 119
 120test_expect_success 'untracked cache after second status' '
 121        test-dump-untracked-cache >../actual &&
 122        test_cmp ../dump.expect ../actual
 123'
 124
 125test_expect_success 'modify in root directory, one dir invalidation' '
 126        avoid_racy &&
 127        : >four &&
 128        : >../trace &&
 129        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 130        git status --porcelain >../actual &&
 131        cat >../status.expect <<EOF &&
 132A  done/one
 133A  one
 134A  two
 135?? dthree/
 136?? dtwo/
 137?? four
 138?? three
 139EOF
 140        test_cmp ../status.expect ../actual &&
 141        cat >../trace.expect <<EOF &&
 142node creation: 0
 143gitignore invalidation: 0
 144directory invalidation: 1
 145opendir: 1
 146EOF
 147        test_cmp ../trace.expect ../trace
 148
 149'
 150
 151test_expect_success 'verify untracked cache dump' '
 152        test-dump-untracked-cache >../actual &&
 153        cat >../expect <<EOF &&
 154info/exclude $EMPTY_BLOB
 155core.excludesfile 0000000000000000000000000000000000000000
 156exclude_per_dir .gitignore
 157flags 00000006
 158/ 0000000000000000000000000000000000000000 recurse valid
 159dthree/
 160dtwo/
 161four
 162three
 163/done/ 0000000000000000000000000000000000000000 recurse valid
 164/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 165three
 166/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 167two
 168EOF
 169        test_cmp ../expect ../actual
 170'
 171
 172test_expect_success 'new .gitignore invalidates recursively' '
 173        avoid_racy &&
 174        echo four >.gitignore &&
 175        : >../trace &&
 176        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 177        git status --porcelain >../actual &&
 178        cat >../status.expect <<EOF &&
 179A  done/one
 180A  one
 181A  two
 182?? .gitignore
 183?? dthree/
 184?? dtwo/
 185?? three
 186EOF
 187        test_cmp ../status.expect ../actual &&
 188        cat >../trace.expect <<EOF &&
 189node creation: 0
 190gitignore invalidation: 1
 191directory invalidation: 1
 192opendir: 4
 193EOF
 194        test_cmp ../trace.expect ../trace
 195
 196'
 197
 198test_expect_success 'verify untracked cache dump' '
 199        test-dump-untracked-cache >../actual &&
 200        cat >../expect <<EOF &&
 201info/exclude $EMPTY_BLOB
 202core.excludesfile 0000000000000000000000000000000000000000
 203exclude_per_dir .gitignore
 204flags 00000006
 205/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
 206.gitignore
 207dthree/
 208dtwo/
 209three
 210/done/ 0000000000000000000000000000000000000000 recurse valid
 211/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 212three
 213/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 214two
 215EOF
 216        test_cmp ../expect ../actual
 217'
 218
 219test_expect_success 'new info/exclude invalidates everything' '
 220        avoid_racy &&
 221        echo three >>.git/info/exclude &&
 222        : >../trace &&
 223        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 224        git status --porcelain >../actual &&
 225        cat >../status.expect <<EOF &&
 226A  done/one
 227A  one
 228A  two
 229?? .gitignore
 230?? dtwo/
 231EOF
 232        test_cmp ../status.expect ../actual &&
 233        cat >../trace.expect <<EOF &&
 234node creation: 0
 235gitignore invalidation: 1
 236directory invalidation: 0
 237opendir: 4
 238EOF
 239        test_cmp ../trace.expect ../trace
 240'
 241
 242test_expect_success 'verify untracked cache dump' '
 243        test-dump-untracked-cache >../actual &&
 244        cat >../expect <<EOF &&
 245info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 246core.excludesfile 0000000000000000000000000000000000000000
 247exclude_per_dir .gitignore
 248flags 00000006
 249/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
 250.gitignore
 251dtwo/
 252/done/ 0000000000000000000000000000000000000000 recurse valid
 253/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 254/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 255two
 256EOF
 257        test_cmp ../expect ../actual
 258'
 259
 260test_expect_success 'move two from tracked to untracked' '
 261        git rm --cached two &&
 262        test-dump-untracked-cache >../actual &&
 263        cat >../expect <<EOF &&
 264info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 265core.excludesfile 0000000000000000000000000000000000000000
 266exclude_per_dir .gitignore
 267flags 00000006
 268/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
 269/done/ 0000000000000000000000000000000000000000 recurse valid
 270/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 271/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 272two
 273EOF
 274        test_cmp ../expect ../actual
 275'
 276
 277test_expect_success 'status after the move' '
 278        : >../trace &&
 279        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 280        git status --porcelain >../actual &&
 281        cat >../status.expect <<EOF &&
 282A  done/one
 283A  one
 284?? .gitignore
 285?? dtwo/
 286?? two
 287EOF
 288        test_cmp ../status.expect ../actual &&
 289        cat >../trace.expect <<EOF &&
 290node creation: 0
 291gitignore invalidation: 0
 292directory invalidation: 0
 293opendir: 1
 294EOF
 295        test_cmp ../trace.expect ../trace
 296'
 297
 298test_expect_success 'verify untracked cache dump' '
 299        test-dump-untracked-cache >../actual &&
 300        cat >../expect <<EOF &&
 301info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 302core.excludesfile 0000000000000000000000000000000000000000
 303exclude_per_dir .gitignore
 304flags 00000006
 305/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
 306.gitignore
 307dtwo/
 308two
 309/done/ 0000000000000000000000000000000000000000 recurse valid
 310/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 311/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 312two
 313EOF
 314        test_cmp ../expect ../actual
 315'
 316
 317test_expect_success 'move two from untracked to tracked' '
 318        git add two &&
 319        test-dump-untracked-cache >../actual &&
 320        cat >../expect <<EOF &&
 321info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 322core.excludesfile 0000000000000000000000000000000000000000
 323exclude_per_dir .gitignore
 324flags 00000006
 325/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
 326/done/ 0000000000000000000000000000000000000000 recurse valid
 327/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 328/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 329two
 330EOF
 331        test_cmp ../expect ../actual
 332'
 333
 334test_expect_success 'status after the move' '
 335        : >../trace &&
 336        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 337        git status --porcelain >../actual &&
 338        cat >../status.expect <<EOF &&
 339A  done/one
 340A  one
 341A  two
 342?? .gitignore
 343?? dtwo/
 344EOF
 345        test_cmp ../status.expect ../actual &&
 346        cat >../trace.expect <<EOF &&
 347node creation: 0
 348gitignore invalidation: 0
 349directory invalidation: 0
 350opendir: 1
 351EOF
 352        test_cmp ../trace.expect ../trace
 353'
 354
 355test_expect_success 'verify untracked cache dump' '
 356        test-dump-untracked-cache >../actual &&
 357        cat >../expect <<EOF &&
 358info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 359core.excludesfile 0000000000000000000000000000000000000000
 360exclude_per_dir .gitignore
 361flags 00000006
 362/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
 363.gitignore
 364dtwo/
 365/done/ 0000000000000000000000000000000000000000 recurse valid
 366/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 367/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 368two
 369EOF
 370        test_cmp ../expect ../actual
 371'
 372
 373test_expect_success 'set up for sparse checkout testing' '
 374        echo two >done/.gitignore &&
 375        echo three >>done/.gitignore &&
 376        echo two >done/two &&
 377        git add -f done/two done/.gitignore &&
 378        git commit -m "first commit"
 379'
 380
 381test_expect_success 'status after commit' '
 382        : >../trace &&
 383        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 384        git status --porcelain >../actual &&
 385        cat >../status.expect <<EOF &&
 386?? .gitignore
 387?? dtwo/
 388EOF
 389        test_cmp ../status.expect ../actual &&
 390        cat >../trace.expect <<EOF &&
 391node creation: 0
 392gitignore invalidation: 0
 393directory invalidation: 0
 394opendir: 2
 395EOF
 396        test_cmp ../trace.expect ../trace
 397'
 398
 399test_expect_success 'untracked cache correct after commit' '
 400        test-dump-untracked-cache >../actual &&
 401        cat >../expect <<EOF &&
 402info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 403core.excludesfile 0000000000000000000000000000000000000000
 404exclude_per_dir .gitignore
 405flags 00000006
 406/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
 407.gitignore
 408dtwo/
 409/done/ 0000000000000000000000000000000000000000 recurse valid
 410/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 411/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 412two
 413EOF
 414        test_cmp ../expect ../actual
 415'
 416
 417test_expect_success 'set up sparse checkout' '
 418        echo "done/[a-z]*" >.git/info/sparse-checkout &&
 419        test_config core.sparsecheckout true &&
 420        git checkout master &&
 421        git update-index --force-untracked-cache &&
 422        git status --porcelain >/dev/null && # prime the cache
 423        test_path_is_missing done/.gitignore &&
 424        test_path_is_file done/one
 425'
 426
 427test_expect_success 'create/modify files, some of which are gitignored' '
 428        echo two bis >done/two &&
 429        echo three >done/three && # three is gitignored
 430        echo four >done/four && # four is gitignored at a higher level
 431        echo five >done/five && # five is not gitignored
 432        echo test >base && #we need to ensure that the root dir is touched
 433        rm base &&
 434        sync_mtime
 435'
 436
 437test_expect_success 'test sparse status with untracked cache' '
 438        : >../trace &&
 439        avoid_racy &&
 440        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 441        git status --porcelain >../status.actual &&
 442        cat >../status.expect <<EOF &&
 443 M done/two
 444?? .gitignore
 445?? done/five
 446?? dtwo/
 447EOF
 448        test_cmp ../status.expect ../status.actual &&
 449        cat >../trace.expect <<EOF &&
 450node creation: 0
 451gitignore invalidation: 1
 452directory invalidation: 2
 453opendir: 2
 454EOF
 455        test_cmp ../trace.expect ../trace
 456'
 457
 458test_expect_success 'untracked cache correct after status' '
 459        test-dump-untracked-cache >../actual &&
 460        cat >../expect <<EOF &&
 461info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 462core.excludesfile 0000000000000000000000000000000000000000
 463exclude_per_dir .gitignore
 464flags 00000006
 465/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
 466.gitignore
 467dtwo/
 468/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
 469five
 470/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 471/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 472two
 473EOF
 474        test_cmp ../expect ../actual
 475'
 476
 477test_expect_success 'test sparse status again with untracked cache' '
 478        avoid_racy &&
 479        : >../trace &&
 480        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 481        git status --porcelain >../status.actual &&
 482        cat >../status.expect <<EOF &&
 483 M done/two
 484?? .gitignore
 485?? done/five
 486?? dtwo/
 487EOF
 488        test_cmp ../status.expect ../status.actual &&
 489        cat >../trace.expect <<EOF &&
 490node creation: 0
 491gitignore invalidation: 0
 492directory invalidation: 0
 493opendir: 0
 494EOF
 495        test_cmp ../trace.expect ../trace
 496'
 497
 498test_expect_success 'set up for test of subdir and sparse checkouts' '
 499        mkdir done/sub &&
 500        mkdir done/sub/sub &&
 501        echo "sub" > done/sub/sub/file
 502'
 503
 504test_expect_success 'test sparse status with untracked cache and subdir' '
 505        avoid_racy &&
 506        : >../trace &&
 507        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 508        git status --porcelain >../status.actual &&
 509        cat >../status.expect <<EOF &&
 510 M done/two
 511?? .gitignore
 512?? done/five
 513?? done/sub/
 514?? dtwo/
 515EOF
 516        test_cmp ../status.expect ../status.actual &&
 517        cat >../trace.expect <<EOF &&
 518node creation: 2
 519gitignore invalidation: 0
 520directory invalidation: 1
 521opendir: 3
 522EOF
 523        test_cmp ../trace.expect ../trace
 524'
 525
 526test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
 527        test-dump-untracked-cache >../actual &&
 528        cat >../expect-from-test-dump <<EOF &&
 529info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 530core.excludesfile 0000000000000000000000000000000000000000
 531exclude_per_dir .gitignore
 532flags 00000006
 533/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
 534.gitignore
 535dtwo/
 536/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
 537five
 538sub/
 539/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
 540sub/
 541/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
 542file
 543/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
 544/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 545two
 546EOF
 547        test_cmp ../expect-from-test-dump ../actual
 548'
 549
 550test_expect_success 'test sparse status again with untracked cache and subdir' '
 551        avoid_racy &&
 552        : >../trace &&
 553        GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
 554        git status --porcelain >../status.actual &&
 555        test_cmp ../status.expect ../status.actual &&
 556        cat >../trace.expect <<EOF &&
 557node creation: 0
 558gitignore invalidation: 0
 559directory invalidation: 0
 560opendir: 0
 561EOF
 562        test_cmp ../trace.expect ../trace
 563'
 564
 565test_expect_success 'move entry in subdir from untracked to cached' '
 566        git add dtwo/two &&
 567        git status --porcelain >../status.actual &&
 568        cat >../status.expect <<EOF &&
 569 M done/two
 570A  dtwo/two
 571?? .gitignore
 572?? done/five
 573?? done/sub/
 574EOF
 575        test_cmp ../status.expect ../status.actual
 576'
 577
 578test_expect_success 'move entry in subdir from cached to untracked' '
 579        git rm --cached dtwo/two &&
 580        git status --porcelain >../status.actual &&
 581        cat >../status.expect <<EOF &&
 582 M done/two
 583?? .gitignore
 584?? done/five
 585?? done/sub/
 586?? dtwo/
 587EOF
 588        test_cmp ../status.expect ../status.actual
 589'
 590
 591test_expect_success '--no-untracked-cache removes the cache' '
 592        git update-index --no-untracked-cache &&
 593        test-dump-untracked-cache >../actual &&
 594        echo "no untracked cache" >../expect-no-uc &&
 595        test_cmp ../expect-no-uc ../actual
 596'
 597
 598test_expect_success 'git status does not change anything' '
 599        git status &&
 600        test-dump-untracked-cache >../actual &&
 601        test_cmp ../expect-no-uc ../actual
 602'
 603
 604test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
 605        git config core.untrackedCache true &&
 606        test-dump-untracked-cache >../actual &&
 607        test_cmp ../expect-no-uc ../actual &&
 608        git status &&
 609        test-dump-untracked-cache >../actual &&
 610        test_cmp ../expect-from-test-dump ../actual
 611'
 612
 613test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
 614        git update-index --no-untracked-cache &&
 615        test-dump-untracked-cache >../actual &&
 616        test_cmp ../expect-no-uc ../actual &&
 617        git update-index --untracked-cache &&
 618        test-dump-untracked-cache >../actual &&
 619        test_cmp ../expect-empty ../actual
 620'
 621
 622test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
 623        git config core.untrackedCache false &&
 624        test-dump-untracked-cache >../actual &&
 625        test_cmp ../expect-empty ../actual &&
 626        git status &&
 627        test-dump-untracked-cache >../actual &&
 628        test_cmp ../expect-no-uc ../actual
 629'
 630
 631test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
 632        git update-index --untracked-cache &&
 633        test-dump-untracked-cache >../actual &&
 634        test_cmp ../expect-empty ../actual
 635'
 636
 637test_expect_success 'setting core.untrackedCache to keep' '
 638        git config core.untrackedCache keep &&
 639        git update-index --untracked-cache &&
 640        test-dump-untracked-cache >../actual &&
 641        test_cmp ../expect-empty ../actual &&
 642        git status &&
 643        test-dump-untracked-cache >../actual &&
 644        test_cmp ../expect-from-test-dump ../actual &&
 645        git update-index --no-untracked-cache &&
 646        test-dump-untracked-cache >../actual &&
 647        test_cmp ../expect-no-uc ../actual &&
 648        git update-index --force-untracked-cache &&
 649        test-dump-untracked-cache >../actual &&
 650        test_cmp ../expect-empty ../actual &&
 651        git status &&
 652        test-dump-untracked-cache >../actual &&
 653        test_cmp ../expect-from-test-dump ../actual
 654'
 655
 656test_expect_success 'test ident field is working' '
 657        mkdir ../other_worktree &&
 658        cp -R done dthree dtwo four three ../other_worktree &&
 659        GIT_WORK_TREE=../other_worktree git status 2>../err &&
 660        echo "warning: Untracked cache is disabled on this system or location." >../expect &&
 661        test_i18ncmp ../expect ../err
 662'
 663
 664test_done