{"thread":{"id":"66176","subject":"Bash completion very slow in large repo","startedAt":"2026-08-14T18:55:40Z","lastAt":"2026-08-19T20:25:50Z","messageCount":4,"participants":["Matthew Hughes","D. Ben Knoble"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"550636","messageId":"an9iXOqOOvFfyN4A@desktop","threadId":"66176","inReplyTo":null,"subject":"Bash completion very slow in large repo","fromName":"Matthew Hughes","fromEmail":"matthewhughes934@gmail.com","sentAt":"2026-08-14T18:55:36Z","receivedAt":"2026-08-14T18:55:40Z","isPatch":false,"body":"Hi,\n\nWhile working in a repo with _a lot_ of directories I've noticed a painful\nslowdown in some of the bash completion for git. Specifically, for any\ncompletion that calls `git ls-files` and needs to iterate through the\nfile-system (and not just check the index), e.g. `git add`. Has anyone run into\nthis? Are there existing solutions or workarounds?\n\nI first ran into it when running something like\n\n    $ git add ./<tab> # hangs for a good second or two\n\nFor reference the number of files/directories in the actual repo I work with:\n\n    # this many files\n    $ git ls-files | wc --lines\n    367628\n    # this many directories\n    $ git ls-files -z | xargs -0 dirname | sort --unique | wc --lines\n    58404\n\nSee below for a reproduction and my logic, but I conclude this is because e.g.\nin the case of `git add` (with no other args) git will need to look through\nevery directory in the repo to discover if there any untracked files at any\nlevel.\n\nI'm not sure about potential fixes. Hacking around on it the best I could come\nup with was a workaround: add an env var to skip index completion during bash\ncompletion, so the completion falls back to the default Bash file completion\n(i.e. complete any time), here that is (just for demonstration):\n\ndiff --git i/contrib/completion/git-completion.bash w/contrib/completion/git-completion.bash\nindex e875787710..7b412e5b74 100644\n--- i/contrib/completion/git-completion.bash\n+++ w/contrib/completion/git-completion.bash\n@@ -727,6 +727,10 @@ __git_index_files ()\n # The exception is --committable, which finds the files appropriate commit.\n __git_complete_index_file ()\n {\n+       if test -n \"${GIT_COMPLETION_NO_COMPLETE_INDEX-}\"\n+       then\n+               return\n+       fi\n        local dequoted_word pfx=\"\" cur_\n \n        __git_dequote \"$cur\"\n\nFor reproduction: here's a roughly similar setup of a repo, with many\ndirectories at the root:\n\n    $ git init .\n    $ for i in {1..25000}; do echo dir_$i/sub_dir/; done | xargs mkdir -p\n    $ for i in {1..25000}; do for j in {1..12}; do echo dir_$i/sub_dir/file_$j.txt; done; done | xargs touch\n    $ git add .\n\nWith that setup I see slow completion e.g. on `git add ./di<TAB>`. Debugging\nthe completion script I see it hangs for a while on:\n\n    git -C ./ -c core.quotePath=false ls-files --exclude-standard --others --modified --directory --no-empty-directory -- 'di*'\n\n(via `_git_add->__git_complete_index_file->__git_index_files`)\n\nAnd running that through `strace` (on my Linux/AMD64 machine) tells me for each\ndirectory there is (among other syscalls):\n\n* ~100_000 calls to `getdents64`\n* ~75_000 calls to `openat`\n* ~50_000 calls to `fstat`\n\nSo that explains the slowdown. \n\nThanks,\nMatt\n"},{"id":"550663","messageId":"CALnO6CAWA4szRqq_=1kAjB_y6WqA5zSyyMZzPmgnV7KGb+AS7Q@mail.gmail.com","threadId":"66176","inReplyTo":"an9iXOqOOvFfyN4A@desktop","subject":"Re: Bash completion very slow in large repo","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-15T14:17:19Z","receivedAt":"2026-08-15T14:17:33Z","isPatch":false,"body":"On Fri, Aug 14, 2026 at 2:55 PM Matthew Hughes\n<matthewhughes934@gmail.com> wrote:\n>\n> Hi,\n>\n> While working in a repo with _a lot_ of directories I've noticed a painful\n> slowdown in some of the bash completion for git. Specifically, for any\n> completion that calls `git ls-files` and needs to iterate through the\n> file-system (and not just check the index), e.g. `git add`. Has anyone run into\n> this? Are there existing solutions or workarounds?\n\nHi Matt, have you tried turning on \"feature.manyFiles\"? That enables a\nfew things (like the fsmonitor) that might help in large repositories.\n\n[snip]\n\nBest,\nBen\n"},{"id":"550668","messageId":"aoDB9roVjgoTeG5l@desktop","threadId":"66176","inReplyTo":"CALnO6CAWA4szRqq_=1kAjB_y6WqA5zSyyMZzPmgnV7KGb+AS7Q@mail.gmail.com","subject":"Re: Bash completion very slow in large repo","fromName":"Matthew Hughes","fromEmail":"matthewhughes934@gmail.com","sentAt":"2026-08-15T19:52:46Z","receivedAt":"2026-08-15T19:52:50Z","isPatch":false,"body":"On Sat, Aug 15, 2026 at 10:17:19AM -0400, D. Ben Knoble wrote:\n> Hi Matt, have you tried turning on \"feature.manyFiles\"? That enables a\n> few things (like the fsmonitor) that might help in large repositories.\n\nAh, thanks for calling that out: I should've mentioned this is in a repo that's\nalready configured via `git-scalar(1)`, so it sets that specific option off,\nbut justifies:\n\n> feature.manyFiles=false\n> This disables the \"many files\" optimizations grouped under this feature config.\n> The expectation is that all valuable optimizations are also set explicitly by\n> Scalar config, and any differences are intentional.\n\nThough also testing in a fresh repo with no scalar but that option on I didn't\nsee any significant performance change.\n\nI'm also not sure e.g. `git ls-files --exclude-standard --others --directory`\nknows about things like `fsmonitor`/the untracked cache, like e.g. `git status`\ndoes (disclaimer: I'm not at all familiar enough with the code to justify that\nclaim, it's based purely on my qualitative experience, I'm also not sure if it\n_could_ benefit from such things)\n\nCheers,\nMatt\n"},{"id":"550842","messageId":"aoYQ9CCzPM3qKVfZ@desktop","threadId":"66176","inReplyTo":"an9iXOqOOvFfyN4A@desktop","subject":"Re: Bash completion very slow in large repo","fromName":"Matthew Hughes","fromEmail":"matthewhughes934@gmail.com","sentAt":"2026-08-19T20:25:46Z","receivedAt":"2026-08-19T20:25:50Z","isPatch":false,"body":"On Fri, Aug 14, 2026 at 07:55:36PM +0100, Matthew Hughes wrote:\n> I'm not sure about potential fixes. Hacking around on it the best I could come\n> up with was a workaround: add an env var to skip index completion during bash\n> completion, so the completion falls back to the default Bash file completion\n> (i.e. complete any time), here that is (just for demonstration):\n\nMy final workaround (read: filthy hack) was to re-define\n`__git_complete_index_file` just after sourcing the completion script like:\n\n    # copy __git_complete_index_file to __orig__git_complete_index_file\n    eval \"__orig$(declare -f __git_complete_index_file)\"\n\n    __git_complete_index_file () {\n        # options that require 'git' to inspect all files on disk\n        local slow_opts_re=\"(^|[[:space:]])(--others|--modified|--deleted|--ignored|--killed)($|[[:space:]])\"    \n        if [[ \"$1\" =~ $slow_opts_re ]]\n        then\n            return\n        fi\n\n        __orig__git_complete_index_file \"$@\"\n    }\n"}]}