{"thread":{"id":"62384","subject":"Empty directory showing as untracked with untrackedCache (with reproduction script)","startedAt":"2024-10-21T16:59:04Z","lastAt":"2024-10-21T16:59:04Z","messageCount":1,"participants":["Nikita Leshenko"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"505714","messageId":"CAEXts1vjiFsMCL9ANsqnz-mwFCZQyM6S5u_qXz8v1P=z1o3gsQ@mail.gmail.com","threadId":"62384","inReplyTo":null,"subject":"Empty directory showing as untracked with untrackedCache (with reproduction script)","fromName":"Nikita Leshenko","fromEmail":"nikita@island.io","sentAt":"2024-10-21T16:58:51Z","receivedAt":"2024-10-21T16:59:04Z","isPatch":false,"sender":{"key":"nikita@island.io","avatar":null},"body":"Summary: Enabling untrackedCache sometimes causes an empty directory to show as\nuntracked (as if the directory contains content). This is racy but there's a\nscript to reproduce it deterministically.\n\nWhat did you do before the bug happened? (Steps to reproduce your issue)\n\n- Create repo with some content\n- Enable untrackedCache\n- git status, shows nothing\n- create aa/bb\n- git status, shows '?? aa/'\n- rm aa/bb (leaving aa/ empty)\n- git status\n\nWhat did you expect to happen? (Expected behavior)\n\ngit status should show nothing.\n\nWhat happened instead? (Actual behavior)\n\ngit status shows aa/ as having untracked content.\n\nAnything else you want to add:\n\nHere's a Python script to reproduce:\n------------------------ >8 ------------------------\nimport os\nfrom subprocess import check_output, check_call\n\ncheck_call(['git', 'init'])\n\n# Populate directory for some load, makes reproduction faster.\nfor a in range(40):\n  os.mkdir(f'z_{a}')\n  for b in range(40):\n    os.mkdir(f'z_{a}/{b}')\n    for c in range(40):\n      with open(f'z_{a}/{b}/{c}', 'w') as f:\n        pass\ncheck_call(['git', 'add', '.'])\ncheck_call(['git', 'commit', '-m', '.', '-q'])\n\n# Enable untracked cache.\ncheck_call(['git', 'update-index', '--test-untracked-cache'])\ncheck_call(['git', 'config', 'core.untrackedCache', 'true'])\n\n# Repeatedly create/delete same file.\nfor i in range(1, 1000):\n\n  s = check_output(['git', 'status', '--porcelain'])\n  assert not s, \"Expected clean git status\"\n\n  os.mkdir(f'aa')\n  with open('aa/bb', 'w') as f:\n    pass\n  s = check_output(['git', 'status', '--porcelain'])\n  assert s == b'?? aa/\\n', \"Expected aa dir to show up\"\n\n  os.unlink('aa/bb')\n\n  s = check_output(['git', 'status', '--porcelain'])\n  if s:\n    print(\"\\n\\n=============== REPRODUCED! ===============\\n\")\n    print(f'Reproduced in {i} attempts')\n\n    print(f'\\n$ ls -la aa/')\n    check_call(['ls', '-la', 'aa/'])\n\n    print(f'\\n$ git status')\n    check_call(['git', 'status'])\n\n    print(f'\\n$ git --version')\n    check_call(['git', '--version'])\n    break\n\n  os.rmdir(f'aa')\n\nelse:\n  print('Failed to reproduce')\n------------------------ >8 ------------------------\n\nExample output of this script:\n------------------------ >8 ------------------------\nInitialized empty Git repository in /home/user/tmp/repro/.git/\nTesting mtime in '/home/user/tmp/repro' ...... OK\n\n\n=============== REPRODUCED! ===============\n\nReproduced in 90 attempts\n\n$ ls -la aa/\ntotal 8\ndrwxr-xr-x.  2 user user 4096 Oct 21 19:46 .\ndrwxr-xr-x. 44 user user 4096 Oct 21 19:46 ..\n\n$ git status\nOn branch master\nUntracked files:\n  (use \"git add <file>...\" to include in what will be committed)\naa/\n\nnothing added to commit but untracked files present (use \"git add\" to track)\n\n$ git --version\ngit version 2.47.0.107.g34b6ce9b30\n------------------------ >8 ------------------------\n\nThis reproduced in the following Git versions:\n- Latest master (34b6ce9b30)\n- Latest shipping in Fedora (2.47.0)\n- Ubuntu 22 LTS (2.34.1)\n\n[System Info]\ngit version:\ngit version 2.47.0.107.g34b6ce9b30\ncpu: x86_64\nbuilt from commit: 34b6ce9b30747131b6e781ff718a45328aa887d0\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nlibcurl: 8.6.0\nOpenSSL: OpenSSL 3.2.2 4 Jun 2024\nzlib: 1.3.1.zlib-ng\nuname: Linux 6.11.3-200.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Oct 10\n22:31:19 UTC 2024 x86_64\ncompiler info: gnuc: 14.2\nlibc info: glibc: 2.39\n$SHELL (typically, interactive shell): /bin/zsh\n\n\n[Enabled Hooks]\n"}]}