Skip to content

VCS_STATUS_NUM_UNTRACKED overcounts in repos with nested .gitignore files #486

@yulonglin

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().

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