From ea83f50dc35f5fac893a8bb641efe4b86995f2ee Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 2 Jul 2026 22:01:39 +0200 Subject: [PATCH] Move post-FILES-refresh model reads into Then PromptToContinueRebase and WithEnsureCommittableFiles both read Model.Files right after a SYNC FILES refresh. This works today because the model write currently happens synchronously in the worker before Refresh's wg.Wait() returns, but an upcoming commit will bounce that write onto the UI thread instead, at which point wg.Wait() no longer guarantees it's been applied. Move both reads into Then ahead of that change. Then is already queued via OnUIThread (previous commit), so this is a behavior-preserving refactor on its own: the model is fully written by the time Then runs either way, whether that write is still synchronous or gets bounced later. As part of restructuring WithEnsureCommittableFiles, prepareFilesForCommit and syncRefresh are inlined into their single call sites. Co-Authored-By: Claude Sonnet 5 --- .../helpers/merge_and_rebase_helper.go | 41 ++++++++++--------- .../helpers/working_tree_helper.go | 39 +++++++----------- 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 847b89893..c25416a3b 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -309,27 +309,30 @@ func (self *MergeAndRebaseHelper) PromptToContinueRebase() error { // but this is not supported by all terminals or on all platforms. self.c.Refresh(types.RefreshOptions{ Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}, + Then: func() error { + unstagedFiles := GetUnstagedFilesExceptSubmodules(self.c.Model().Files, self.c.Model().Submodules) + if len(unstagedFiles) > 0 { + self.c.Confirm(types.ConfirmOpts{ + Title: self.c.Tr.Continue, + Prompt: self.c.Tr.UnstagedFilesAfterConflictsResolved, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.StageAllFiles) + if err := self.c.Git().WorkingTree.StageFiles(unstagedFiles, []string{}); err != nil { + return err + } + + return self.genericMergeCommand(REBASE_OPTION_CONTINUE) + }, + }) + + return nil + } + + return self.genericMergeCommand(REBASE_OPTION_CONTINUE) + }, }) - unstagedFiles := GetUnstagedFilesExceptSubmodules(self.c.Model().Files, self.c.Model().Submodules) - if len(unstagedFiles) > 0 { - self.c.Confirm(types.ConfirmOpts{ - Title: self.c.Tr.Continue, - Prompt: self.c.Tr.UnstagedFilesAfterConflictsResolved, - HandleConfirm: func() error { - self.c.LogAction(self.c.Tr.Actions.StageAllFiles) - if err := self.c.Git().WorkingTree.StageFiles(unstagedFiles, []string{}); err != nil { - return err - } - - return self.genericMergeCommand(REBASE_OPTION_CONTINUE) - }, - }) - - return nil - } - - return self.genericMergeCommand(REBASE_OPTION_CONTINUE) + return nil }, }) diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index 7e070ba31..7e321854b 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -222,15 +222,24 @@ func (self *WorkingTreeHelper) HandleCommitPress() error { } func (self *WorkingTreeHelper) WithEnsureCommittableFiles(handler func() error) error { - if err := self.prepareFilesForCommit(); err != nil { - return err - } - if len(self.c.Model().Files) == 0 { return errors.New(self.c.Tr.NoFilesStagedTitle) } if !self.AnyStagedFiles() { + if self.c.UserConfig().Gui.SkipNoStagedFilesWarning { + self.c.LogAction(self.c.Tr.Actions.StageAllFiles) + if err := self.c.Git().WorkingTree.StageAll(false); err != nil { + return err + } + self.c.Refresh(types.RefreshOptions{ + Mode: types.SYNC, + Scope: []types.RefreshableView{types.FILES}, + Then: handler, + }) + return nil + } + return self.promptToStageAllAndRetry(handler) } @@ -246,7 +255,7 @@ func (self *WorkingTreeHelper) promptToStageAllAndRetry(retry func() error) erro if err := self.c.Git().WorkingTree.StageAll(false); err != nil { return err } - self.syncRefresh() + self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}}) return retry() }, @@ -255,26 +264,6 @@ func (self *WorkingTreeHelper) promptToStageAllAndRetry(retry func() error) erro return nil } -// for when you need to refetch files before continuing an action. Runs synchronously. -func (self *WorkingTreeHelper) syncRefresh() { - self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}}) -} - -func (self *WorkingTreeHelper) prepareFilesForCommit() error { - noStagedFiles := !self.AnyStagedFiles() - if noStagedFiles && self.c.UserConfig().Gui.SkipNoStagedFilesWarning { - self.c.LogAction(self.c.Tr.Actions.StageAllFiles) - err := self.c.Git().WorkingTree.StageAll(false) - if err != nil { - return err - } - - self.syncRefresh() - } - - return nil -} - func (self *WorkingTreeHelper) commitPrefixConfigsForRepo() []config.CommitPrefixConfig { cfg, ok := self.c.UserConfig().Git.CommitPrefixes[self.c.Git().RepoPaths.RepoName()] if ok {