Auto-forward branches on a worker

AutoForwardBranches runs in the Then callback of the refresh after a
fetch. This is on the UI thread, so the git command for updating the
branches blocks the UI while it runs. This is fine for a single
update-ref, but the next commit adds a git status and a git merge for
each branch that is checked out in another worktree.

Keep reading the branches from the model on the UI thread, and move the
git work to a worker.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-09-27 11:05:47 +02:00
co-authored by Claude Opus 5.5
parent acc58a2d12
commit 245a613762
+25 -17
View File
@@ -421,14 +421,8 @@ func (self *BranchesHelper) PostFetchRefresh(fetchErr error, background bool, fe
if self.c.State().GetRepoGeneration() != fetchGeneration {
return nil
}
err := self.AutoForwardBranches(background)
if background && err != nil {
// The background poller discards this return value, so surface
// the error in the log rather than as a popup for background work.
self.c.Log.Error(err)
return nil
}
return err
self.AutoForwardBranches(background)
return nil
},
})
return fetchErr
@@ -628,14 +622,16 @@ func (self *BranchesHelper) worktreeArgs(worktree *models.Worktree) (string, str
return worktree.GitDir, worktree.Path
}
func (self *BranchesHelper) AutoForwardBranches(background bool) error {
// Reads the branches from the model, so it must be called on the UI thread; the
// git work happens on a worker.
func (self *BranchesHelper) AutoForwardBranches(background bool) {
if self.c.UserConfig().Git.AutoForwardBranches == "none" {
return nil
return
}
branches := self.c.Model().Branches
if len(branches) == 0 {
return nil
return
}
allBranches := self.c.UserConfig().Git.AutoForwardBranches == "allBranches"
@@ -653,14 +649,26 @@ func (self *BranchesHelper) AutoForwardBranches(background bool) error {
}
if updateCommands == "" {
return nil
return
}
self.c.LogAction(self.c.Tr.Actions.AutoForwardBranches)
self.c.LogCommand(strings.TrimRight(updateCommands, "\n"), false)
err := self.c.Git().Branch.UpdateBranchRefs(updateCommands, "lazygit: fast-forward to upstream branch")
// A background worker doesn't block switching repos, so it has to stick
// to the git commands of the repo that the branches came from
git := self.c.Git()
onWorker := lo.Ternary(background, self.c.OnWorkerBackground, self.c.OnWorker)
onWorker(func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.AutoForwardBranches)
self.c.LogCommand(strings.TrimRight(updateCommands, "\n"), false)
err := git.Branch.UpdateBranchRefs(updateCommands, "lazygit: fast-forward to upstream branch")
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES}, Background: background})
self.c.RefreshFromWorker(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES}, Background: background})
return err
if background && err != nil {
// Surface the error in the log rather than as a popup for background
// work
self.c.Log.Error(err)
return nil
}
return err
})
}