Fixing a Shell Prompt That Hangs Inside Git Repositories
A prompt that's slow only inside repositories is usually running expensive Git status work on every redraw — profile it, isolate repository scale, cache safely.
If pressing Enter is instant outside a repository but pauses inside one, the prompt is probably launching Git commands before every new command line. Large worktrees, slow filesystems, untracked-file scans, and synchronous network mounts can turn decorative status into interactive latency.
Prove that the prompt is responsible
Start a clean shell without user configuration:
bash --noprofile --norc
# or
zsh -f
Enter the same repository. If the delay disappears, temporarily replace the configured prompt with a literal string and disable prompt hooks one at a time. Do not assume Git itself is broken until the exact hook is identified.
Time the command the theme runs
Common prompt implementations call git status, git describe, or multiple git rev-parse commands. Run those explicitly with time. Compare a small repository, the slow repository, and a directory on a local filesystem.
Git status may scan the worktree for modifications and untracked files. Generated dependency trees, huge untracked build directories, antivirus inspection, or a repository located on NFS, SMB, WSL-mounted Windows storage, or a FUSE filesystem can dominate the cost.
Reduce work before adding clever caching
Ignore generated files appropriately, keep repositories out of pathological storage when possible, and configure the prompt to omit expensive details. Many themes have switches for untracked files, dirty state, fetch status, or command timeout. A branch name obtained cheaply is often enough.
Git’s built-in untracked cache and filesystem monitor can improve status performance on supported systems, but enable them based on measured need and repository policy—not as a substitute for discovering a giant untracked directory.
Cache without lying indefinitely
Asynchronous prompts keep the editor responsive and update Git information when a background query completes. Caches should be keyed by repository and invalidated after relevant changes or a short interval. Always provide a way to recognize stale information: prompt status is a convenience, never the authority for deciding what will be committed.
Skipping optional index locks for read-only prompt queries
git --no-optional-locks status
Setting GIT_OPTIONAL_LOCKS=0, or passing --no-optional-locks directly, tells Git to skip sub-operations that would otherwise take an index lock as a side effect of an otherwise read-only command like status — specifically useful for a prompt hook, which is a background, non-interactive caller that has no reason to contend for the index lock with a real foreground Git operation the user might be running at the same moment. If your specific prompt framework shells out to git status directly rather than through a wrapper, confirm whether it already passes this flag, and add it yourself if not.
What genuinely asynchronous prompt rendering looks like in practice
Modern prompt tools like Starship take the async-caching approach a step further than a simple background job: the prompt renders immediately with whatever git information is already available (or none at all), while the actual git status query runs separately and updates the displayed segment once it completes, rather than the whole prompt blocking until Git finishes. Configurable timeout and scan-depth settings let you cap how long the tool will wait on a slow repository before giving up on that particular segment for the current prompt draw — a graceful degradation model that a naive synchronous git status call embedded directly in a prompt function doesn’t have any real equivalent for, since a blocking call either finishes normally or hangs, with essentially nothing meaningful in between those two outcomes.
Related: How Shell Prompt Customization Actually Works · How to Configure a Custom Prompt With Starship
Sources: