Back to Blog
4 min read

How We Supercharged Git Context with Smarter Session Summaries and Performance Fixes

The Problem: Session Summaries Were Slowing Us Down

When we first built Git Context, our goal was simple: give developers real-time, relevant code insights based on their active Git session. But as repos grew and usage spiked, we hit a wall. The session summary logic—meant to aggregate metadata like changed files, branch state, and recent commits—was becoming a bottleneck.

Originally, we fetched and processed this data on every IDE heartbeat, even if nothing had changed. We were spawning fresh Git processes repeatedly, parsing the same diffs, and reconstructing session state from scratch each time. In large repos, this meant timeouts, UI jitter, and frustrated users. It wasn’t sustainable.

We realized the core issue wasn’t the data we were collecting—it was how often and how we were collecting it. The "summary" wasn’t summarizing; it was re-computing. And worse, we had no way to cancel long-running operations when the user moved on. Something had to change.

Architectural Fixes: Caching, Spawning, and Smart Cancellation

We took a step back and asked: what if the session summary wasn’t a one-off computation, but a living, cached state that only updated when needed?

First, we introduced a context-aware caching layer. Instead of re-running git status, git diff, and git log on every tick, we now track filesystem watch events and Git hooks to detect meaningful changes. If no files changed and the branch stayed the same, we skip the heavy lifting entirely. This alone eliminated over 60% of redundant operations in typical workflows.

Next, we optimized how we spawn Git processes. Previously, we used a generic exec wrapper that didn’t handle concurrency well. We replaced it with a bounded async pool that limits parallel Git invocations and prioritizes critical paths (like active file context) over background tasks. This prevented resource starvation in monorepos where dozens of Git operations could queue up at once.

But the biggest win came from adding cancellation support to our pipeline. We rebuilt the core execution flow using AbortController patterns, so when a user switches files or branches, pending operations get cleanly terminated. No more wasted CPU cycles on stale requests. This was especially impactful in VS Code, where rapid navigation used to trigger cascading delays.

We also refactored the session summary aggregation to batch related Git calls. Instead of three separate process spawns for status, diff, and log, we now use a single, optimized script that returns a structured payload. Less overhead, fewer edge cases.

Results: 40% Faster, More Reliable, Ready for Scale

The impact was immediate. In our internal benchmarks across repos ranging from 10K to 250K files, average session processing time dropped by 40%. More importantly, the 95th percentile latency—the one that used to spike during large diffs—improved by over 60%. Timeouts became rare, and the IDE felt snappier.

But performance wasn’t the only win. The new architecture made the system more predictable. With proper cancellation and throttling, we eliminated race conditions that previously caused inconsistent context states. Users no longer saw outdated or partial summaries after quick branch switches.

One of our frontend engineers put it best: "It just works now. I don’t think about it." That’s the kind of feedback every tooling developer dreams of.

This wasn’t a rewrite—it was a focused, data-driven refactoring. We leaned on observability (timing metrics, operation tracing) to identify hotspots, then applied surgical changes. No buzzwords, no over-engineering. Just better plumbing.

Looking ahead, this optimized foundation opens doors. We can now layer on smarter heuristics—like detecting "focus areas" in a diff or pre-warming context for likely next files—without worrying about dragging down performance. The pipeline is no longer the weak link.

If you’re building Git-integrated tools, here’s my takeaway: treat Git not as a CLI to shell out to, but as a service with state. Cache intelligently, cancel early, and batch aggressively. The speedups aren’t just nice-to-have—they’re what make advanced tooling feel native, not bolted-on.

Newer post

From Monolith to MVC: Refactoring a Legacy PHP File with Laravel Components

Older post

Deleting Documentation to Improve Code Quality: A Radical Move in Git Context