Skip to content

[BUG] /vcs/diff spawns one git show HEAD:<file> process per changed file after large refactors #24739

Description

@ualtinok

Description

When the web/desktop review diff state refreshes after a large refactor, OpenCode can spawn hundreds of short-lived Git processes like:

git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false show HEAD:src/features/review/diff-view.ts
git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false show HEAD:src/services/git/diff-cache.ts
git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false show HEAD:test/review-panel/diff-refresh.test.ts

I observed this after a large refactor where many tracked files changed. The process list showed many concurrent/repeated git show HEAD:<path> commands for different files, including repeated paths.

The root cause appears to be the VCS diff path:

  • packages/app/src/pages/session.tsx invalidates VCS diff on file.watcher.updated events.
  • That triggers /vcs/diff.
  • /vcs/diff reaches packages/opencode/src/project/vcs.ts.
  • files(...) iterates the changed file list.
  • For every non-added tracked file, it calls git.show(cwd, ref, item.file, base).
  • git.show(...) runs git show ${ref}:${path} as a separate Git process.

So one VCS diff refresh over N modified/deleted tracked files can spawn roughly N git show HEAD:<file> processes. After a large refactor, watcher-triggered refreshes can multiply that cost.

This is separate from the broader full-context patch/OOM problem tracked in other issues. Even before addressing patch payload size, the current implementation creates avoidable process fan-out while loading the old HEAD contents for changed files.

A more scalable implementation would batch these old blob reads, for example with git cat-file --batch, similar to the existing snapshot diff batching precedent.

Related but not identical:

Plugins

No response

OpenCode version

Current dev branch / observed locally while working on upstream source.

Steps to reproduce

  1. Open a git-backed project in the web/desktop UI.
  2. Ensure the review/changes diff state is active or can be refreshed by file watcher events.
  3. Make a large refactor touching many tracked files.
  4. Observe OS process list while /vcs/diff refreshes.
  5. Many commands of this form are spawned:
git ... show HEAD:<changed-file>

Expected behavior: /vcs/diff should not spawn one Git process per changed file. Old blob contents should be loaded in a batched way.

Actual behavior: /vcs/diff fans out to many git show HEAD:<file> processes.

Screenshot and/or share link

Example process list excerpt with generated placeholder file paths:

git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false show HEAD:src/features/review/diff-view.ts
git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false show HEAD:src/services/git/diff-cache.ts
git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false show HEAD:test/review-panel/diff-refresh.test.ts
...

Operating System

macOS

Terminal

N/A

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions