Skip to content

Conversation

@MaxFangX
Copy link
Contributor

@MaxFangX MaxFangX commented Nov 5, 2025

Builds on top of #422 and #423.

Description

Fixes performance degradation during staging operations by suppressing redundant VGitSync events. Achieves 99.6% reduction in buffer refresh calls (1,380 -> 6 LiveGutter:fetch calls) and 95% reduction in total git operations (10,421 -> 564 calls across 41 staging operations).

When staging hunks in the diff view, DiffScreen already manually fetches and renders the current buffer, making VGitSync's refresh of all tracked buffers unnecessary and wasteful. Every staging operation (s, S, u, U, r, R keys in diff view) triggered a cascade: git index changes -> filesystem watcher detects change -> VGitSync event fires -> git_buffer_store.for_each() iterates all tracked buffers -> each buffer runs LiveGutter:fetch() -> GitBuffer:diff() -> 3-4 git commands per buffer. With 15 tracked buffers, this meant 15x unnecessary buffer refreshes per stage operation, resulting in thousands of redundant git command calls.

This adds suppress_sync_for(ms) API to git_buffer_store that temporarily disables VGitSync events. Applied this 200ms suppression window to all DiffScreen staging methods (stage_hunk, unstage_hunk, reset_hunk, stage, unstage, reset), preventing the cascade while DiffScreen handles its own refresh. Also includes with_selective_staging() API for future use cases where only specific buffers should refresh.

Tested with 15 tracked buffers over 41 staging operations. No functional regressions observed - all git operations complete successfully, gutter signs update correctly, and UI remains responsive.

Performance Summary

Improvement:

  • Total calls: 95% reduction (10,421 -> 564)
  • LiveGutter:fetch: 99.6% reduction (1,380 -> 6)
  • GitBuffer:diff: 99.6% reduction (1,381 -> 6)
  • git ls-files: 94% reduction (1,463 -> 87)

Profiling Details

Environment: 15 tracked buffers, ~40 stage operations (DiffScreen:stage_hunk)

Before:

Unique operations: 36
Total calls: 10,421

156054ms total (1380x, 113ms avg) - vgit.features.buffer.LiveGutter:fetch
102827ms total (1381x, 74ms avg) - vgit.git.GitBuffer:diff
69420ms total (1838x, 38ms avg) - vgit.git.git_buffer_store.dispatch
41300ms total (1463x, 28ms avg) - gitcli.run: git ls-files
20863ms total (768x, 27ms avg) - gitcli.run: git ls-files -u
18357ms total (468x, 39ms avg) - gitcli.run: git show
11166ms total (39x, 286ms avg) - vgit.features.screens.DiffScreen:stage_hunk

After:

Unique operations: 21
Total calls: 564

6502ms total (41x, 159ms avg) - vgit.features.screens.DiffScreen:stage_hunk
1410ms total (87x, 16ms avg) - gitcli.run: git ls-files
723ms total (38x, 19ms avg) - vgit.git.git_stager.stage_hunk
339ms total (6x, 57ms avg) - vgit.git.git_buffer_store.dispatch
242ms total (6x, 40ms avg) - vgit.features.buffer.LiveGutter:fetch
241ms total (6x, 40ms avg) - vgit.git.GitBuffer:diff

The VGitSync autocmd handler was being registered inside the
filesystem watcher callback, causing a new handler to accumulate
on every git directory change (i.e., every stage operation).

After N stage operations, N duplicate handlers would all fire on
each subsequent stage, causing O(N²) performance degradation.

Fixed by moving event.custom_on() registration outside the callback,
using vim.schedule() to avoid luv callback restrictions.
@MaxFangX MaxFangX force-pushed the 2025-11-05-suppress-unneeded-vgitsync branch from f64a3c1 to 33c16f2 Compare November 5, 2025 17:46
Adds API to git_buffer_store for suppressing VGitSync events during staging. Applies suppression in DiffScreen staging methods to prevent cascading buffer refreshes.

Performance from local profiling:
95% reduction in calls (10,421 → 564 per session staging 39 hunks),
99.6% reduction in LiveGutter:fetch (1,380 → 6).

DiffScreen already manually fetches and renders, making VGitSync refresh of all tracked buffers redundant.
@MaxFangX MaxFangX force-pushed the 2025-11-05-suppress-unneeded-vgitsync branch from 33c16f2 to 8cf1214 Compare November 5, 2025 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant