Replies: 1 comment
-
|
Hi @stefanhaller I would appreciate your input on the direction we should take. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Context
In large repositories, staging or unstaging from the files panel can make the UI unresponsive for a noticeable amount of time. The slow path appears to come from two separate costs:
git status --untracked-files=allcan take multiple seconds.git add,git reset HEAD, orgit rm --cachedcan also take hundreds of milliseconds to more than a second.Today, the files panel does an optimistic in-memory update, but the real git operation and follow-up refresh can still block interaction long enough that scrolling the files panel or switching panels feels frozen.
Local measurements
These are local measurements from a large working tree, intended as directional data rather than a formal benchmark.
Before the prototype change:
2.4s - 3.9s.2.1s - 2.5s.2sjust to acquire the files refresh mutex while a full refresh was running.After the prototype change:
76ms - 188ms, averaging around100msin the latest sample.git add: roughly400ms - 550msin the latest sample.git reset HEAD: roughly900ms - 1.1sin the latest sample.git rm --cached: roughly340ms - 360msin the latest sample.git status --untracked-files=notook around735ms - 1.0sin the latest sample.15ms - 25ms.Prototype approach
I tried a prototype with these changes:
Split files refresh into a load phase and an apply phase.
Add generation-based refresh invalidation.
Use a faster background reconcile after stage/unstage.
--untracked-files=no.Move files-panel stage/unstage git writes onto a worker.
git add,git reset HEAD, orgit rm --cachedruns asynchronously.Main concern
The performance improvement is significant, but moving the git write operation to a worker introduces a semantic question.
There is now a short window where:
That means a user could potentially trigger another operation before the pending stage operation finishes, for example:
Without a shared barrier, those operations may observe the real index before the pending stage operation has completed, even though the UI already reflects the optimistic state.
Possible directions
I would like feedback on which direction fits lazygit's architecture best.
Option A: Keep git stage/unstage synchronous, only optimize refresh
This is the safest semantic option.
git add/reset/rmon the existing interaction path.git status.This should reduce the worst freezes caused by full files refreshes, but it will not hide slow
git addorgit reset HEAD.Option B: Workerize stage/unstage, but add a pending index-operation barrier
This preserves the best UI responsiveness but needs a stronger consistency mechanism.
The idea would be:
This keeps the UI responsive for navigation while preventing operations that depend on the index from racing ahead of the pending git write.
Option C: Workerize only selected cases
For example:
This reduces the semantic surface area, but the behavior becomes less uniform.
Additional edge cases
There are a few smaller correctness details to handle if we continue with the background reconcile approach:
*models.Filefields outside the files refresh mutex. A lightweight snapshot of the fields needed for auto-staging resolved conflicts may be safer than a shallow slice copy.Question
Would lazygit prefer the more conservative approach of keeping index writes synchronous while making refresh non-blocking, or is an asynchronous stage/unstage path acceptable if paired with a shared pending index-operation barrier?
Beta Was this translation helpful? Give feedback.
All reactions