Mood: 😊
Category: Bugs
Summary
When a workspace contains a large untracked directory (100k+ files) that isn't excluded via .gitignore, the app repeatedly rebuilds a full diff-document manifest across all of those files on routine workspace-change refreshes. Each rebuild materializes tens of millions of row/anchor entries and appears to remain resident rather than being evicted, causing the main app process to grow by several GB per rebuild — reaching 20+ GB of physical footprint within a couple of hours of normal use.
Environment
|
|
| App version |
1.1.22 |
| OS |
macOS 26.7 (Apple Silicon) |
| Installation context |
Local repository whose working tree contains a large untracked directory not covered by .gitignore. Not tied to a specific organization. |
What happened?
The app's own internal logs surfaced the mechanism directly. It repeatedly logs a warning:
Skipping untracked additions count for runaway directory (likely missing .gitignore entry); files will show +0 top_dir=<dir> file_count=110000+ cap=1000
Despite this "skip" warning suggesting the directory is excluded from the file count, the diff engine still performs full manifest builds over the same file set whenever get_diff_document_manifest runs (triggered by opening a session, sending a prompt, or periodic workspace-change subscriptions). Log evidence from a single session:
diff_document.paged_build{files=111506} ... rows=81468112 anchors=111506 line_anchors=81248952 chunks=203671 manifest_only=true
diff_document_build_end ... total_rows=81468112 files=111506 duration_ms=1666
diff_document.residency_changed document_id="...:uncommitted:<hash>" documentResidentChunks=1
diff_document_manifest_service ... manifest_service_ms=73171 ... enrich_ms=64052 build_ms=1666
This full rebuild (producing ~81 million row/anchor entries, taking 70-95 seconds of internal processing) recurred at least 5 times within about 7 minutes of normal interactive use (opening sessions, sending prompts), each producing a new document_id and each logged as documentResidentChunks=1 (resident in memory), without an accompanying log entry indicating the previous document was evicted.
Correlated with this, the main app process's physical footprint (via vmmap -summary) grew from a healthy baseline of ~200-500 MB to over 20 GB, then continued oscillating between roughly 5 GB and 25 GB depending on activity, driving system swap to its limit and heavy memory-compressor activity. leaks on the process showed only ~220 MB of classically unreachable memory, indicating this is not a simple pointer leak but unbounded retention/caching of legitimately-referenced diff data.
Steps to reproduce
- Open a local repository whose working tree contains a directory with 100,000+ files that is not excluded via
.gitignore (e.g., a data/ or similar bulk-file directory).
- Open a session/workspace against that repository in the app.
- Interact normally — send prompts, switch sessions, let workspace-change subscriptions fire.
- Watch the app's log file (
~/.copilot/logs/github-app.<pid>.log) for repeated diff_document.paged_build{files=...} / diff_document_build_end entries with very large total_rows/anchors values.
- Monitor the main app process's physical footprint via Activity Monitor or
vmmap -summary <pid> — observe multi-GB jumps correlating with each rebuild.
Expected behavior
- A directory that's excluded from the untracked-file count for being a "runaway directory" should also be excluded (or at least capped/paginated) from full diff-manifest builds, not just from the display count.
- Diff documents superseded by a newer rebuild for the same workspace/changes-mode should be evicted from memory promptly instead of accumulating.
- Memory usage should stay roughly bounded regardless of working-tree size, especially for directories the app has already flagged as too large to process normally.
Additional context
vmmap -summary MALLOC_SMALL zone alone showed the process reaching ~15+ GB across millions of small allocations, consistent with many small per-row/per-anchor diff objects.
- This reproduces reliably and quickly (within minutes) given a sufficiently large untracked directory — happy to provide further sanitized
vmmap/log excerpts if helpful for triage.
- Workaround in the meantime: manually excluding the large directory via
.gitignore prevents the repeated full-manifest rebuilds and stops further growth.
Mood: 😊
Category: Bugs
Summary
When a workspace contains a large untracked directory (100k+ files) that isn't excluded via
.gitignore, the app repeatedly rebuilds a full diff-document manifest across all of those files on routine workspace-change refreshes. Each rebuild materializes tens of millions of row/anchor entries and appears to remain resident rather than being evicted, causing the main app process to grow by several GB per rebuild — reaching 20+ GB of physical footprint within a couple of hours of normal use.Environment
.gitignore. Not tied to a specific organization.What happened?
The app's own internal logs surfaced the mechanism directly. It repeatedly logs a warning:
Despite this "skip" warning suggesting the directory is excluded from the file count, the diff engine still performs full manifest builds over the same file set whenever
get_diff_document_manifestruns (triggered by opening a session, sending a prompt, or periodic workspace-change subscriptions). Log evidence from a single session:This full rebuild (producing ~81 million row/anchor entries, taking 70-95 seconds of internal processing) recurred at least 5 times within about 7 minutes of normal interactive use (opening sessions, sending prompts), each producing a new
document_idand each logged asdocumentResidentChunks=1(resident in memory), without an accompanying log entry indicating the previous document was evicted.Correlated with this, the main app process's physical footprint (via
vmmap -summary) grew from a healthy baseline of ~200-500 MB to over 20 GB, then continued oscillating between roughly 5 GB and 25 GB depending on activity, driving system swap to its limit and heavy memory-compressor activity.leakson the process showed only ~220 MB of classically unreachable memory, indicating this is not a simple pointer leak but unbounded retention/caching of legitimately-referenced diff data.Steps to reproduce
.gitignore(e.g., adata/or similar bulk-file directory).~/.copilot/logs/github-app.<pid>.log) for repeateddiff_document.paged_build{files=...}/diff_document_build_endentries with very largetotal_rows/anchorsvalues.vmmap -summary <pid>— observe multi-GB jumps correlating with each rebuild.Expected behavior
Additional context
vmmap -summaryMALLOC_SMALL zone alone showed the process reaching ~15+ GB across millions of small allocations, consistent with many small per-row/per-anchor diff objects.vmmap/log excerpts if helpful for triage..gitignoreprevents the repeated full-manifest rebuilds and stops further growth.