From 93bd26b9a9bf47643674bb8f6db78c4b39b35fa8 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Fri, 29 May 2026 13:04:45 +0200 Subject: [PATCH] Centralize scope expansion in Refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several downstream conditions in Refresh() relied on multi-scope predicates to express "if X is in scope, Y also needs refreshing". This makes it hard to add new code that needs to ask "does this refresh re-read refs?", because the answer involves mirroring one of those predicates and keeping them in sync forever. Expand the co-refreshing relationships once, up front, right after the scope set is built. The downstream conditions then collapse to single-scope checks against the (now-expanded) set. Behavior is preserved. Two of the scattered multi-scope conditions are intentionally left as-is because they express subsumption rather than co-refresh (one branch already does the work of another internally — expanding would cause double-refresh), and one expresses mid-function coupling on a flag set inside the COMMITS/BRANCHES block. --- pkg/gui/controllers/helpers/refresh_helper.go | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index d27b38feb..f1277e007 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -106,6 +106,23 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) { scopeSet = set.NewFromSlice(options.Scope) } + // Expand co-refreshing scopes up front so downstream conditions can be + // simple single-scope checks. The relationships are: + // - whenever the reflog or bisect info changes, commits and branches + // can change too (e.g. switching branches updates the reflog and + // can move HEAD), so refresh commits + branches alongside + // - submodules are refreshed as part of the files refresh + // - merge conflicts are part of what the files refresh produces + if scopeSet.Includes(types.REFLOG) || scopeSet.Includes(types.BISECT_INFO) { + scopeSet.Add(types.COMMITS, types.BRANCHES) + } + if scopeSet.Includes(types.SUBMODULES) { + scopeSet.Add(types.FILES) + } + if scopeSet.Includes(types.FILES) { + scopeSet.Add(types.MERGE_CONFLICTS) + } + wg := sync.WaitGroup{} refresh := func(name string, f func()) { // if we're in a demo we don't want any async refreshes because @@ -129,7 +146,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) { branchesAndRemotesWg := sync.WaitGroup{} includeWorktreesWithBranches := false - if scopeSet.Includes(types.COMMITS) || scopeSet.Includes(types.BRANCHES) || scopeSet.Includes(types.REFLOG) || scopeSet.Includes(types.BISECT_INFO) { + if scopeSet.Includes(types.COMMITS) || scopeSet.Includes(types.BRANCHES) { // whenever we change commits, we should update branches because the upstream/downstream // counts can change. Whenever we change branches we should also change commits // e.g. in the case of switching branches. @@ -166,7 +183,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) { } fileWg := sync.WaitGroup{} - if scopeSet.Includes(types.FILES) || scopeSet.Includes(types.SUBMODULES) { + if scopeSet.Includes(types.FILES) { fileWg.Add(1) refresh("files", func() { _ = self.refreshFilesAndSubmodules() @@ -212,7 +229,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) { refresh("patch building", func() { self.patchBuildingHelper.RefreshPatchBuildingPanel(types.OnFocusOpts{}) }) } - if scopeSet.Includes(types.MERGE_CONFLICTS) || scopeSet.Includes(types.FILES) { + if scopeSet.Includes(types.MERGE_CONFLICTS) { refresh("merge conflicts", func() { _ = self.mergeConflictsHelper.RefreshMergeState() }) }