From 2c139b6ac173842f88d03392017a3eecd5f05cc5 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Fri, 3 Jul 2026 14:01:45 +0200 Subject: [PATCH] Remove RefreshingFilesMutex/FileTreeViewModel.RWMutex, dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FileTreeViewModel.RWMutex is removed along with the withFileTreeViewModelMutex wrapper in FilesController that RLocked it: every writer (the bounce closure, previous commit) and every reader (key handlers, disabled-reason callbacks) now runs on the UI thread, so the mutex is redundant. RefreshingFilesMutex is removed entirely, including its last use in repos_helper's DispatchSwitchTo. That use predates the bounce and was never about FilesController's optimistic-rendering concern; it serialized a repo switch's onNewRepo() against an in-flight FILES refresh for the repo being switched away from, so that a slow refresh from the old repo couldn't write into the freshly-reset model for the new one. Bouncing the write already broke that guarantee on its own terms — the mutex's critical section never covered the bounced closure's actual execution, only the (now-removed) code that enqueued it — so by this point it was only still locked here without protecting anything real; the previous commit's repo-generation guard is what now actually closes that race, making this lock fully redundant rather than just relocated. Co-Authored-By: Claude Sonnet 5 --- pkg/gui/controllers/files_controller.go | 25 +++---------------- pkg/gui/controllers/helpers/refresh_helper.go | 3 --- pkg/gui/controllers/helpers/repos_helper.go | 3 --- pkg/gui/filetree/file_tree_view_model.go | 2 -- pkg/gui/types/common.go | 1 - 5 files changed, 4 insertions(+), 30 deletions(-) diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index a63c6a15a..d7720ee34 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -44,7 +44,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types { Keys: opts.GetKeys(opts.Config.Universal.Select), Handler: self.withItems(self.press), - GetDisabledReason: self.require(self.withFileTreeViewModelMutex(self.itemsSelected(self.canStageSelection))), + GetDisabledReason: self.require(self.itemsSelected(self.canStageSelection)), Description: self.c.Tr.Stage, Tooltip: self.c.Tr.StageTooltip, DisplayOnScreen: true, @@ -91,7 +91,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types { Keys: opts.GetKeys(opts.Config.Universal.Edit), Handler: self.withItems(self.edit), - GetDisabledReason: self.require(self.withFileTreeViewModelMutex(self.itemsSelected(self.canEditFiles))), + GetDisabledReason: self.require(self.itemsSelected(self.canEditFiles)), Description: self.c.Tr.Edit, Tooltip: self.c.Tr.EditFileTooltip, DisplayOnScreen: true, @@ -145,7 +145,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types { Keys: opts.GetKeys(opts.Config.Universal.Remove), Handler: self.withItems(self.remove), - GetDisabledReason: self.withFileTreeViewModelMutex(self.require(self.itemsSelected(self.canRemove))), + GetDisabledReason: self.require(self.itemsSelected(self.canRemove)), Description: self.c.Tr.Discard, Tooltip: self.c.Tr.DiscardFileChangesTooltip, OpensMenu: true, @@ -182,7 +182,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Handler: self.withItems(self.openMergeConflictMenu), Description: self.c.Tr.ViewMergeConflictOptions, Tooltip: self.c.Tr.ViewMergeConflictOptionsTooltip, - GetDisabledReason: self.require(self.withFileTreeViewModelMutex(self.itemsSelected(self.canOpenMergeConflictMenu))), + GetDisabledReason: self.require(self.itemsSelected(self.canOpenMergeConflictMenu)), OpensMenu: true, DisplayOnScreen: true, }, @@ -209,15 +209,6 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types } } -func (self *FilesController) withFileTreeViewModelMutex(callback func() *types.DisabledReason) func() *types.DisabledReason { - return func() *types.DisabledReason { - self.c.Contexts().Files.FileTreeViewModel.RWMutex.RLock() - defer self.c.Contexts().Files.FileTreeViewModel.RWMutex.RUnlock() - - return callback() - } -} - func (self *FilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { return []*gocui.ViewMouseBinding{ { @@ -574,11 +565,6 @@ func (self *FilesController) toggleStaged( } func (self *FilesController) pressWithLock(selectedNodes []*filetree.FileNode) error { - // Obtaining this lock because optimistic rendering requires us to mutate - // the files in our model. - self.c.Mutexes().RefreshingFilesMutex.Lock() - defer self.c.Mutexes().RefreshingFilesMutex.Unlock() - // When filtering, expand directory nodes to individual visible file paths // so that only filtered files are staged/unstaged. toPaths := func(nodes []*filetree.FileNode) []string { @@ -942,9 +928,6 @@ func (self *FilesController) toggleStagedAll() error { } func (self *FilesController) toggleStagedAllWithLock() error { - self.c.Mutexes().RefreshingFilesMutex.Lock() - defer self.c.Mutexes().RefreshingFilesMutex.Unlock() - root := self.context().FileTreeViewModel.GetRoot() stage := func(unstagedNodes []*filetree.FileNode) error { diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index 2f2210f49..875f55a30 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -740,9 +740,6 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele } func (self *RefreshHelper) refreshFilesAndSubmodules(background bool) error { - self.c.Mutexes().RefreshingFilesMutex.Lock() - defer self.c.Mutexes().RefreshingFilesMutex.Unlock() - configs, err := self.refreshStateSubmoduleConfigs() if err != nil { return err diff --git a/pkg/gui/controllers/helpers/repos_helper.go b/pkg/gui/controllers/helpers/repos_helper.go index bde1c47c6..94c9e4368 100644 --- a/pkg/gui/controllers/helpers/repos_helper.go +++ b/pkg/gui/controllers/helpers/repos_helper.go @@ -177,9 +177,6 @@ func (self *ReposHelper) DispatchSwitchTo(path string, errMsg string, contextKey self.c.Log.Errorf("error recording current directory: %v", err) } - self.c.Mutexes().RefreshingFilesMutex.Lock() - defer self.c.Mutexes().RefreshingFilesMutex.Unlock() - if err := self.onNewRepo(appTypes.StartArgs{}, contextKey); err != nil { return err } diff --git a/pkg/gui/filetree/file_tree_view_model.go b/pkg/gui/filetree/file_tree_view_model.go index 741550c19..aabbbce7f 100644 --- a/pkg/gui/filetree/file_tree_view_model.go +++ b/pkg/gui/filetree/file_tree_view_model.go @@ -2,7 +2,6 @@ package filetree import ( "strings" - "sync" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/common" @@ -22,7 +21,6 @@ type IFileTreeViewModel interface { // which item is selected. It also contains logic for repositioning that cursor // after the files are refreshed type FileTreeViewModel struct { - sync.RWMutex types.IListCursor IFileTree searchHistory *utils.HistoryBuffer[string] diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 7fc75aee0..2b7dc2312 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -338,7 +338,6 @@ type Model struct { } type Mutexes struct { - RefreshingFilesMutex deadlock.Mutex RefreshingBranchesMutex deadlock.Mutex RefreshingStatusMutex deadlock.Mutex RefreshingPullRequestsMutex deadlock.Mutex