romkatv / romkatv/gitstatus

VCS_STATUS_NUM_UNTRACKED overcounts in repos with nested .gitignore files

Open
#486 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
1.8k
Forks
134
Avg merge
2d 18h
Merged PRs (30d)
1

Description

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

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal reproduction in the issue and compare git ls-files --others --exclude-standard with VCS_STATUS_NUM_UNTRACKED. Then inspect gitstatus's use of libgit2 via git_diff_index_to_workdir(), checking how nested .gitignore files and ignored directories are counted. Done means the reported count matches Git's count for the reproduction.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, git
Domain
cli, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.