mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
We set GIT_OPTIONAL_LOCKS=0 for every git command we run. That env var only affects `git status`: it tells git not to take the optional lock it would otherwise use to write the index back after refreshing the cached stat information. The intent was to avoid contending for index.lock with git commands the user runs in a terminal. The downside is that our `git status` never persists the refreshed stat-cache. So whenever the working tree's cached stat info goes stale (e.g. editing files and discarding the changes, or a checkout), every subsequent status re-hashes the affected files to confirm they're clean, and stays slow until something else writes the index (such as the user running `git status` in a terminal). Fix this by only suppressing optional locks for refreshes that run unattended in the background; foreground refreshes triggered by a user action now run a plain `git status` that writes the refreshed index back, just like the command line does. Background refreshes keep passing --no-optional-locks so they still can't cause lock contention. RefreshOptions gains a Background flag that the background routines set, threaded down to the status command. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
42 lines
1.6 KiB
Go
42 lines
1.6 KiB
Go
package commands
|
|
|
|
import (
|
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// all we're doing here is wrapping the default command object builder with
|
|
// some git-specific stuff: e.g. adding a git-specific env var
|
|
|
|
type gitCmdObjBuilder struct {
|
|
innerBuilder *oscommands.CmdObjBuilder
|
|
}
|
|
|
|
var _ oscommands.ICmdObjBuilder = &gitCmdObjBuilder{}
|
|
|
|
func NewGitCmdObjBuilder(log *logrus.Entry, innerBuilder *oscommands.CmdObjBuilder) *gitCmdObjBuilder {
|
|
// the price of having a convenient interface where we can say .New(...).Run() is that our builder now depends on our runner, so when we want to wrap the default builder/runner in new functionality we need to jump through some hoops. We could avoid the use of a decorator function here by just exporting the runner field on the default builder but that would be misleading because we don't want anybody using that to run commands (i.e. we want there to be a single API used across the codebase)
|
|
updatedBuilder := innerBuilder.CloneWithNewRunner(func(runner oscommands.ICmdObjRunner) oscommands.ICmdObjRunner {
|
|
return &gitCmdObjRunner{
|
|
log: log,
|
|
innerRunner: runner,
|
|
}
|
|
})
|
|
|
|
return &gitCmdObjBuilder{
|
|
innerBuilder: updatedBuilder,
|
|
}
|
|
}
|
|
|
|
func (self *gitCmdObjBuilder) New(args []string) *oscommands.CmdObj {
|
|
return self.innerBuilder.New(args)
|
|
}
|
|
|
|
func (self *gitCmdObjBuilder) NewShell(cmdStr string, shellFunctionsFile string) *oscommands.CmdObj {
|
|
return self.innerBuilder.NewShell(cmdStr, shellFunctionsFile)
|
|
}
|
|
|
|
func (self *gitCmdObjBuilder) Quote(str string) string {
|
|
return self.innerBuilder.Quote(str)
|
|
}
|