Skip to content

VCS_STATUS_NUM_UNTRACKED overcounts in repos with nested .gitignore files #486

Open

Description

@yulonglin

Bug: VCS_STATUS_NUM_UNTRACKED overcounts vs git status in repos with nested .gitignore files

Environment

  • gitstatus v1.5.4
  • macOS 15.3.1 (arm64)
  • powerlevel10k (latest via oh-my-zsh)
  • POWERLEVEL9K_VCS_RECURSE_UNTRACKED_DIRS=0 (default)

Symptom

VCS_STATUS_NUM_UNTRACKED consistently reports more untracked files than git ls-files --others --exclude-standard. The overcount is stable across p10k reload and full shell restarts (exec zsh).

$ print $VCS_STATUS_NUM_UNTRACKED
10
$ git ls-files --others --exclude-standard | wc -l
6

Repo structure

The repo has nested .gitignore files:

.gitignore           # root (covers OS, Python, IDE, LaTeX patterns)
claude/.gitignore    # Claude Code runtime state (plugins/, cache/, etc.)
codex/.gitignore     # Codex CLI runtime state

The claude/ directory contains runtime subdirectories (plugins/, cache/, teams/, logs/, tasks/) whose contents are gitignored by claude/.gitignore using relative patterns (e.g., plugins/, tasks/, logs/).

Diagnosis

git ls-files --others --exclude-standard --directory shows zero unmatched directories — all phantom directories are properly gitignored. Yet gitstatus's libgit2 still counts ~4 extra entries.

The overcount appears to come from libgit2 treating directories as "untracked" even when all their contents are covered by nested .gitignore patterns. Git CLI correctly suppresses these directories; libgit2 does not.

Minimal reproduction

  1. Create a repo with a subdirectory containing a .gitignore
  2. Add files to the subdirectory that are ignored by the nested .gitignore but not by root
  3. Compare VCS_STATUS_NUM_UNTRACKED with git ls-files --others --exclude-standard | wc -l
mkdir /tmp/gitstatus-repro && cd /tmp/gitstatus-repro
git init
echo "*.log" > .gitignore

mkdir -p sub
echo "cache/" > sub/.gitignore
mkdir -p sub/cache
touch sub/cache/file1 sub/cache/file2 sub/cache/file3

git add .gitignore sub/.gitignore
git commit -m "init"

# git sees 0 untracked; check if gitstatus agrees
git ls-files --others --exclude-standard | wc -l  # expect: 0
# Compare with VCS_STATUS_NUM_UNTRACKED after cd-ing into the repo

Expected behavior

VCS_STATUS_NUM_UNTRACKED should match git ls-files --others --exclude-standard | wc -l.

Notes

This may be an upstream libgit2 issue rather than gitstatus-specific, since gitstatus delegates gitignore processing to libgit2 via git_diff_index_to_workdir().

Activity

  1. yulonglin commented on Feb 18, 2026

    @yulonglin
    Author

    Real-world reproduction

    This can be reproduced with https://github.com/yulonglin/dotfiles — a dotfiles repo where claude/ (symlinked to ~/.claude/) has its own .gitignore with relative patterns for runtime state directories.

    Related issues

    This appears to be a known class of libgit2 bugs with nested .gitignore processing:

    The gitstatus author noted in #59 that "this part of libgit2 is riddled with bugs and is terribly inefficient."

  2. added a commit that references this issue on Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions