summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Haller <stefan@haller-berlin.de>2023-10-10 08:32:42 +0200
committerGitHub <noreply@github.com>2023-10-10 08:32:42 +0200
commit013cfc77a1e82316681b2a759d90849cd1593dae (patch)
treeba137ca27bce0ba9f3eb002e22554a0558c9a836
parent16f7b01fec5111146bff8c9d5c1eb5a63e78f14d (diff)
parent235f5bb22100ad5fd7f338680b6d37f55c07005c (diff)
Show sync status in branches list (#3021)
-rw-r--r--pkg/commands/git.go6
-rw-r--r--pkg/commands/git_commands/common.go5
-rw-r--r--pkg/commands/git_commands/remote.go4
-rw-r--r--pkg/commands/git_commands/sync.go9
-rw-r--r--pkg/commands/git_commands/tag.go2
-rw-r--r--pkg/commands/models/branch.go4
-rw-r--r--pkg/commands/models/tag.go4
-rw-r--r--pkg/gui/context/branches_context.go1
-rw-r--r--pkg/gui/context/tags_context.go5
-rw-r--r--pkg/gui/controllers.go1
-rw-r--r--pkg/gui/controllers/branches_controller.go41
-rw-r--r--pkg/gui/controllers/helpers/helpers.go2
-rw-r--r--pkg/gui/controllers/helpers/inline_status_helper.go129
-rw-r--r--pkg/gui/controllers/helpers/refresh_helper.go31
-rw-r--r--pkg/gui/controllers/helpers/repos_helper.go5
-rw-r--r--pkg/gui/controllers/status_controller.go2
-rw-r--r--pkg/gui/controllers/sync_controller.go55
-rw-r--r--pkg/gui/controllers/tags_controller.go26
-rw-r--r--pkg/gui/gui.go32
-rw-r--r--pkg/gui/gui_common.go6
-rw-r--r--pkg/gui/presentation/branches.go22
-rw-r--r--pkg/gui/presentation/item_operations.go23
-rw-r--r--pkg/gui/presentation/status.go5
-rw-r--r--pkg/gui/presentation/tags.go21
-rw-r--r--pkg/gui/types/common.go28
-rw-r--r--pkg/i18n/chinese.go2
-rw-r--r--pkg/i18n/dutch.go2
-rw-r--r--pkg/i18n/english.go6
-rw-r--r--pkg/i18n/korean.go2
-rw-r--r--pkg/i18n/russian.go2
-rw-r--r--pkg/i18n/traditional_chinese.go2
31 files changed, 377 insertions, 108 deletions
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index f057f8d54..510661034 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -7,7 +7,6 @@ import (
"strings"
"github.com/go-errors/errors"
- "github.com/sasha-s/go-deadlock"
"github.com/spf13/afero"
gogit "github.com/jesseduffield/go-git/v5"
@@ -63,7 +62,6 @@ func NewGitCommand(
version *git_commands.GitVersion,
osCommand *oscommands.OSCommand,
gitConfig git_config.IGitConfig,
- syncMutex *deadlock.Mutex,
) (*GitCommand, error) {
currentPath, err := os.Getwd()
if err != nil {
@@ -118,7 +116,6 @@ func NewGitCommand(
gitConfig,
repoPaths,
repository,
- syncMutex,
), nil
}
@@ -129,7 +126,6 @@ func NewGitCommandAux(
gitConfig git_config.IGitConfig,
repoPaths *git_commands.RepoPaths,
repo *gogit.Repository,
- syncMutex *deadlock.Mutex,
) *GitCommand {
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd)
@@ -140,7 +136,7 @@ func NewGitCommandAux(
// common ones are: cmn, osCommand, dotGitDir, configCommands
configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo)
- gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands, syncMutex)
+ gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands)
fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands)
statusCommands := git_commands.NewStatusCommands(gitCommon)
diff --git a/pkg/commands/git_commands/common.go b/pkg/commands/git_commands/common.go
index cf8250863..b9537165c 100644
--- a/pkg/commands/git_commands/common.go
+++ b/pkg/commands/git_commands/common.go
@@ -4,7 +4,6 @@ import (
gogit "github.com/jesseduffield/go-git/v5"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
- "github.com/sasha-s/go-deadlock"
)
type GitCommon struct {
@@ -15,8 +14,6 @@ type GitCommon struct {
repoPaths *RepoPaths
repo *gogit.Repository
config *ConfigCommands
- // mutex for doing things like push/pull/fetch
- syncMutex *deadlock.Mutex
}
func NewGitCommon(
@@ -27,7 +24,6 @@ func NewGitCommon(
repoPaths *RepoPaths,
repo *gogit.Repository,
config *ConfigCommands,
- syncMutex *deadlock.Mutex,
) *GitCommon {
return &GitCommon{
Common: cmn,
@@ -37,6 +33,5 @@ func NewGitCommon(
repoPaths: repoPaths,
repo: repo,
config: config,
- syncMutex: syncMutex,
}
}
diff --git a/pkg/commands/git_commands/remote.go b/pkg/commands/git_commands/remote.go
index ce8f79442..acfb51dc9 100644
--- a/pkg/commands/git_commands/remote.go
+++ b/pkg/commands/git_commands/remote.go
@@ -53,7 +53,7 @@ func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName strin
Arg(remoteName, "--delete", branchName).
ToArgv()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}
func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string, tagName string) error {
@@ -61,7 +61,7 @@ func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string,
Arg(remoteName, "--delete", tagName).
ToArgv()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}
// CheckRemoteBranchExists Returns remote branch
diff --git a/pkg/commands/git_commands/sync.go b/pkg/commands/git_commands/sync.go
index c32286e6d..fd7584aea 100644
--- a/pkg/commands/git_commands/sync.go
+++ b/pkg/commands/git_commands/sync.go
@@ -36,7 +36,7 @@ func (self *SyncCommands) PushCmdObj(task gocui.Task, opts PushOpts) (oscommands
ArgIf(opts.UpstreamBranch != "", opts.UpstreamBranch).
ToArgv()
- cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex)
+ cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)
return cmdObj, nil
}
@@ -70,7 +70,6 @@ func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
cmdObj := self.cmd.New(cmdArgs)
cmdObj.DontLog().FailOnCredentialRequest()
- cmdObj.WithMutex(self.syncMutex)
return cmdObj
}
@@ -96,7 +95,7 @@ func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
// has 'pull.rebase = interactive' configured.
- return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).Run()
}
func (self *SyncCommands) FastForward(
@@ -110,7 +109,7 @@ func (self *SyncCommands) FastForward(
Arg(remoteBranchName + ":" + branchName).
ToArgv()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}
func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error {
@@ -118,5 +117,5 @@ func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error
Arg(remoteName).
ToArgv()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}
diff --git a/pkg/commands/git_commands/tag.go b/pkg/commands/git_commands/tag.go
index 0656e1e19..d2b01ba7e 100644
--- a/pkg/commands/git_commands/tag.go
+++ b/pkg/commands/git_commands/tag.go
@@ -52,5 +52,5 @@ func (self *TagCommands) Push(task gocui.Task, remoteName string, tagName string
cmdArgs := NewGitCmd("push").Arg(remoteName, "tag", tagName).
ToArgv()
- return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
+ return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}
diff --git a/pkg/commands/models/branch.go b/pkg/commands/models/branch.go
index 5fc887f87..c5fcfdaed 100644
--- a/pkg/commands/models/branch.go
+++ b/pkg/commands/models/branch.go
@@ -65,6 +65,10 @@ func (b *Branch) ID() string {
return b.RefName()
}
+func (b *Branch) URN() string {
+ return "branch-" + b.ID()
+}
+
func (b *Branch) Description() string {
return b.RefName()
}
diff --git a/pkg/commands/models/tag.go b/pkg/commands/models/tag.go
index ab6076a7a..24cb83254 100644
--- a/pkg/commands/models/tag.go
+++ b/pkg/commands/models/tag.go
@@ -24,6 +24,10 @@ func (t *Tag) ID() string {
return t.RefName()
}
+func (t *Tag) URN() string {
+ return "tag-" + t.ID()
+}
+
func (t *Tag) Description() string {
return t.Message
}
diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go
index ac1fae52c..68324d020 100644
--- a/pkg/gui/context/branches_context.go
+++ b/pkg/gui/context/branches_context.go
@@ -27,6 +27,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext {
getDisplayStrings := func(_ int, _ int) [][]string {
return presentation.GetBranchListDisplayStrings(
viewModel.GetItems(),
+ c.State().GetItemOperation,
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().Diffing.Ref,
c.Tr,
diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go
index 4a9f525f6..3da5a9576 100644
--- a/pkg/gui/context/tags_context.go
+++ b/pkg/gui/context/tags_context.go
@@ -27,7 +27,10 @@ func NewTagsContext(
)
getDisplayStrings := func(_ int, _ int) [][]string {
- return presentation.GetTagListDisplayStrings(viewModel.GetItems(), c.Modes().Diffing.Ref)
+ return presentation.GetTagListDisplayStrings(
+ viewModel.GetItems(),
+ c.State().GetItemOperation,
+ c.Modes().Diffing.Ref, c.Tr)
}
return &TagsContext{
diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go
index 40a482f30..43b226b58 100644
--- a/pkg/gui/controllers.go
+++ b/pkg/gui/controllers.go
@@ -112,6 +112,7 @@ func (gui *Gui) resetHelpersAndControllers() {
Confirmation: helpers.NewConfirmationHelper(helperCommon),
Mode: modeHelper,
AppStatus: appStatusHelper,
+ InlineStatus: helpers.NewInlineStatusHelper(helperCommon),
WindowArrangement: helpers.NewWindowArrangementHelper(
gui.c,
windowHelper,
diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go
index 45f950457..403c51b4f 100644
--- a/pkg/gui/controllers/branches_controller.go
+++ b/pkg/gui/controllers/branches_controller.go
@@ -34,9 +34,10 @@ func NewBranchesController(
func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
- Key: opts.GetKey(opts.Config.Universal.Select),
- Handler: self.checkSelected(self.press),
- Description: self.c.Tr.Checkout,
+ Key: opts.GetKey(opts.Config.Universal.Select),
+ Handler: self.checkSelected(self.press),
+ GetDisabledReason: self.getDisabledReasonForPress,
+ Description: self.c.Tr.Checkout,
},
{
Key: opts.GetKey(opts.Config.Universal.New),
@@ -299,6 +300,18 @@ func (self *BranchesController) press(selectedBranch *models.Branch) error {
return self.c.Helpers().Refs.CheckoutRef(selectedBranch.Name, types.CheckoutRefOptions{})
}
+func (self *BranchesController) getDisabledReasonForPress() string {
+ currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
+ if currentBranch != nil {
+ op := self.c.State().GetItemOperation(currentBranch)
+ if op == types.ItemOperationFastForwarding || op == types.ItemOperationPulling {
+ return self.c.Tr.CantCheckoutBranchWhilePulling
+ }
+ }
+
+ return ""
+}
+
func (self *BranchesController) worktreeForBranch(branch *models.Branch) (*models.Worktree, bool) {
return git_commands.WorktreeForBranch(branch, self.c.Model().Worktrees)
}
@@ -563,14 +576,7 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
action := self.c.Tr.Actions.FastForwardBranch
- message := utils.ResolvePlaceholderString(
- self.c.Tr.FastForwarding,
- map[string]string{
- "branch": branch.Name,
- },
- )
-
- return self.c.WithWaitingStatus(message, func(task gocui.Task) error {
+ return self.c.WithInlineStatus(branch, types.ItemOperationFastForwarding, context.LOCAL_BRANCHES_CONTEXT_KEY, func(task gocui.Task) error {
worktree, ok := self.worktreeForBranch(branch)
if ok {
self.c.LogAction(action)
@@ -590,24 +596,17 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
WorktreeGitDir: worktreeGitDir,
},
)
- if err != nil {
- _ = self.c.Error(err)
- }
-
- return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
+ _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
+ return err
} else {
self.c.LogAction(action)
err := self.c.Git().Sync.FastForward(
task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch,
)
- if err != nil {
- _ = self.c.Error(err)
- }
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
+ return err
}
-
- return nil
})
}
diff --git a/pkg/gui/controllers/helpers/helpers.go b/pkg/gui/controllers/helpers/helpers.go
index 06c5cc973..9e05ba163 100644
--- a/pkg/gui/controllers/helpers/helpers.go
+++ b/pkg/gui/controllers/helpers/helpers.go
@@ -46,6 +46,7 @@ type Helpers struct {
Confirmation *ConfirmationHelper
Mode *ModeHelper
AppStatus *AppStatusHelper
+ InlineStatus *InlineStatusHelper
WindowArrangement *WindowArrangementHelper
Search *SearchHelper
Worktree *WorktreeHelper
@@ -81,6 +82,7 @@ func NewStubHelpers() *Helpers {
Confirmation: &ConfirmationHelper{},
Mode: &ModeHelper{},
AppStatus: &AppStatusHelper{},
+ InlineStatus: &InlineStatusHelper{},
WindowArrangement: &WindowArrangementHelper{},
Search: &SearchHelper{},
Worktree: &WorktreeHelper{},
diff --git a/pkg/gui/controllers/helpers/inline_status_helper.go b/pkg/gui/controllers/helpers/inline_status_helper.go
new file mode 100644
index 000000000..d4435e5b9
--- /dev/null
+++ b/pkg/gui/controllers/helpers/inline_status_helper.go
@@ -0,0 +1,129 @@
+package helpers
+
+import (
+ "time"
+
+ "github.com/jesseduffield/gocui"
+ "github.com/jesseduffield/lazygit/pkg/gui/types"
+ "github.com/jesseduffield/lazygit/pkg/utils"
+ "github.com/sasha-s/go-deadlock"
+)
+
+type InlineStatusHelper struct {
+ c *HelperCommon
+
+ contextsWithInlineStatus map[types.ContextKey]*inlineStatusInfo
+ mutex *deadlock.Mutex
+}
+
+func NewInlineStatusHelper(c *HelperCommon) *InlineStatusHelper {
+ return &InlineStatusHelper{
+ c: c,
+ contextsWithInlineStatus: make(map[types.ContextKey]*inlineStatusInfo),
+ mutex: &deadlock.Mutex{},
+ }
+}
+
+type InlineStatusOpts struct {
+ Item types.HasUrn
+ Operation types.ItemOperation
+ ContextKey types.ContextKey
+}
+
+type inlineStatusInfo struct {
+ refCount int
+ stop chan struct{}
+}
+
+// A custom task for WithInlineStatus calls; it wraps the original one and
+// hides the status whenever the task is paused, and shows it again when
+// continued.
+type inlineStatusHelperTask struct {
+ gocui.Task
+
+ inlineStatusHelper *InlineStatusHelper
+ opts InlineStatusOpts
+}
+
+// poor man's version of explicitly saying that struct X implements interface Y
+var _ gocui.Task = inlineStatusHelperTask{}
+
+func (self inlineStatusHelperTask) Pause() {
+ self.inlineStatusHelper.stop(self.opts)
+ self.Task.Pause()
+
+ self.inlineStatusHelper.renderContext(self.opts.ContextKey)
+}
+
+func (self inlineStatusHelperTask) Continue() {
+ self.Task.Continue()
+ self.inlineStatusHelper.start(self.opts)
+}
+
+func (self *InlineStatusHelper) WithInlineStatus(opts InlineStatusOpts, f func(gocui.Task) error) {
+ self.c.OnWorker(func(task gocui.Task) {
+ self.start(opts)
+
+ err := f(inlineStatusHelperTask{task, self, opts})
+ if err != nil {
+ self.c.OnUIThread(func() error {
+ return self.c.Error(err)
+ })
+ }
+
+ self.stop(opts)
+ })
+}
+
+func (self *InlineStatusHelper) start(opts InlineStatusOpts) {
+ self.c.State().SetItemOperation(opts.Item, opts.Operation)
+
+ self.mutex.Lock()
+ defer self.mutex.Unlock()
+
+ info := self.contextsWithInlineStatus[opts.ContextKey]
+ if info == nil {
+ info = &inlineStatusInfo{refCount: 0, stop: make(chan struct{})}
+ self.contextsWithInlineStatus[opts.ContextKey] = info
+
+ go utils.Safe(func() {
+ ticker := time.NewTicker(time.Millisecond * utils.LoaderAnimationInterval)
+ defer ticker.Stop()
+ outer:
+ for {
+ select {
+ case <-ticker.C:
+ self.renderContext(opts.ContextKey)
+ case <-info.stop:
+ break outer
+ }
+ }
+ })
+ }
+
+ info.refCount++
+}
+
+func (self *InlineStatusHelper) stop(opts InlineStatusOpts) {
+ self.mutex.Lock()
+
+ if info := self.contextsWithInlineStatus[opts.ContextKey]; info != nil {
+ info.refCount--
+ if info.refCount <= 0 {
+ info.stop <- struct{}{}
+ delete(self.contextsWithInlineStatus, opts.ContextKey)
+ }
+
+ }
+
+ self.mutex.Unlock()
+
+ self.c.State().ClearItemOperation(opts.Item)
+}
+
+func (self *InlineStatusHelper) renderContext(contextKey types.ContextKey) {
+ self.c.OnUIThread(func() error {
+ _ = self.c.ContextForKey(contextKey).HandleRender()
+ return nil
+ })
+}
diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go
index f04b102e4..a299ea431 100644
--- a/pkg/gui/controllers/helpers/refresh_helper.go
+++ b/pkg/gui/controllers/helpers/refresh_helper.go
@@ -115,12 +115,15 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
}
}
+ includeWorktreesWithBranches := false
if scopeSet.Includes(types.COMMITS) || scopeSet.Includes(types.BRANCHES) || scopeSet.Includes(types.REFLOG) || scopeSet.Includes(types.BISECT_INFO) {
// 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.
refresh("commits and commit files", self.refreshCommitsAndCommitFiles)
- refresh("reflog and branches", self.refreshReflogAndBranches)
+
+ includeWorktreesWithBranches = scopeSet.Includes(types.WORKTREES)
+ refresh("reflog and branches", func() { self.refreshReflogAndBranches(includeWorktreesWithBranches) })
} else if scopeSet.Includes(types.REBASE_COMMITS) {
// the above block handles rebase commits so we only need to call this one
// if we've asked specifically for rebase commits and not those other things
@@ -157,7 +160,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
refresh("remotes", func() { _ = self.refreshRemotes() })
}
- if scopeSet.Includes(types.WORKTREES) {
+ if scopeSet.Includes(types.WORKTREES) && !includeWorktreesWithBranches {
refresh("worktrees", func() { _ = self.refreshWorktrees() })
}
@@ -242,7 +245,7 @@ func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
case types.INITIAL:
self.c.OnWorker(func(_ gocui.Task) {
_ = self.refreshReflogCommits()
- self.refreshBranches()
+ self.refreshBranches(false)
self.c.State().GetRepoState().SetStartupStage(types.COMPLETE)
})
@@ -251,10 +254,10 @@ func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
}
}
-func (self *RefreshHelper) refreshReflogAndBranches() {
+func (self *RefreshHelper) refreshReflogAndBranches(refreshWorktrees bool) {
self.refreshReflogCommitsConsideringStartup()
- self.refreshBranches()
+ self.refreshBranches(refreshWorktrees)
}
func (self *RefreshHelper) refreshCommitsAndCommitFiles() {
@@ -419,7 +422,7 @@ func (self *RefreshHelper) refreshStateSubmoduleConfigs() error {
// self.refreshStatus is called at the end of this because that's when we can
// be sure there is a State.Model.Branches array to pick the current branch from
-func (self *RefreshHelper) refreshBranches() {
+func (self *RefreshHelper) refreshBranches(refreshWorktrees bool) {
self.c.Mutexes().RefreshingBranchesMutex.Lock()
defer self.c.Mutexes().RefreshingBranchesMutex.Unlock()
@@ -443,6 +446,13 @@ func (self *RefreshHelper) refreshBranches() {
self.c.Model().Branches = branches
+ if refreshWorktrees {
+ self.loadWorktrees()
+ if err := self.c.PostRefreshUpdate(self.c.Contexts().Worktrees); err != nil {
+ self.c.Log.Error(err)
+ }
+ }
+
if err := self.c.PostRefreshUpdate(self.c.Contexts().Branches); err != nil {
self.c.Log.Error(err)
}
@@ -636,15 +646,18 @@ func (self *RefreshHelper) refreshRemotes() error {
return nil
}
-func (self *RefreshHelper) refreshWorktrees() error {
+func (self *RefreshHelper) loadWorktrees() {
worktrees, err := self.c.Git().Loaders.Worktrees.GetWorktrees()
if err != nil {
self.c.Log.Error(err)
self.c.Model().Worktrees = []*models.Worktree{}
- return nil
}
self.c.Model().Worktrees = worktrees
+}
+
+func (self *RefreshHelper) refreshWorktrees() error {
+ self.loadWorktrees()
// need to refresh branches because the branches view shows worktrees against
// branches
@@ -678,7 +691,7 @@ func (self *RefreshHelper) refreshStatus() {
repoName := self.c.Git().RepoPaths.RepoName()
- status := presentation.FormatStatus(repoName, currentBranch, linkedWorktreeName, workingTreeState, self.c.Tr)
+ status := presentation.FormatStatus(repoName, currentBranch, types.ItemOperationNone, linkedWorktreeName, workingTreeState, self.c.Tr)
self.c.SetViewContent(self.c.Views().Status, status)
}
diff --git a/pkg/gui/controllers/helpers/repos_helper.go b/pkg/gui/controllers/helpers/repos_helper.go
index 3ebd7767d..59d45e0c1 100644
--- a/pkg/gui/controllers/helpers/repos_helper.go
+++ b/pkg/gui/controllers/helpers/repos_helper.go
@@ -173,11 +173,6 @@ func (self *ReposHelper) DispatchSwitchTo(path string, errMsg string, contextKey
return err
}
- // these two mutexes are used by our background goroutines (triggered via `self.goEvery`. We don't want to
- // switch to a repo while one of these goroutines is in the process of updating something
- self.c.Mutexes().SyncMutex.Lock()
- defer self.c.Mutexes().SyncMutex.Unlock()
-
self.c.Mutexes().RefreshingFilesMutex.Lock()
defer self.c.Mutexes().RefreshingFilesMutex.Unlock()
diff --git a/pkg/gui/controllers/status_controller.go b/pkg/gui/controllers/status_controller.go
index 8344dfe76..2a186670b 100644
--- a/pkg/gui/controllers/status_controller.go
+++ b/pkg/gui/controllers/status_controller.go
@@ -106,7 +106,7 @@ func (self *StatusController) onClick() error {
}
cx, _ := self.c.Views().Status.Cursor()
- upstreamStatus := presentation.BranchStatus(currentBranch, self.c.Tr)
+ upstreamStatus := presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr)
repoName := self.c.Git().RepoPaths.RepoName()
workingTreeState := self.c.Git().Status.WorkingTreeState()
switch workingTreeState {
diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go
index a77d047a6..4e3369e0a 100644
--- a/pkg/gui/controllers/sync_controller.go
+++ b/pkg/gui/controllers/sync_controller.go
@@ -7,6 +7,7 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
+ "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
@@ -30,14 +31,16 @@ func NewSyncController(
func (self *SyncController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{
{
- Key: opts.GetKey(opts.Config.Universal.Push),
- Handler: opts.Guards.NoPopupPanel(self.HandlePush),
- Description: self.c.Tr.Push,
+ Key: opts.GetKey(opts.Config.Universal.Push),
+ Handler: opts.Guards.NoPopupPanel(self.HandlePush),
+ GetDisabledReason: self.getDisabledReasonForPushOrPull,
+ Description: self.c.Tr.Push,
},
{
- Key: opts.GetKey(opts.Config.Universal.Pull),
- Handler: opts.Guards.NoPopupPanel(self.HandlePull),
- Description: self.c.Tr.Pull,
+ Key: opts.GetKey(opts.Config.Universal.Pull),
+ Handler: opts.Guards.NoPopupPanel(self.HandlePull),
+ GetDisabledReason: self.getDisabledReasonForPushOrPull,
+ Description: self.c.Tr.Pull,
},
}
@@ -56,6 +59,18 @@ func (self *SyncController) HandlePull() error {
return self.branchCheckedOut(self.pull)()
}
+func (self *SyncController) getDisabledReasonForPushOrPull() string {
+ currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
+ if currentBranch != nil {
+ op := self.c.State().GetItemOperation(currentBranch)
+ if op != types.ItemOperationNone {
+ return self.c.Tr.CantPullOrPushSameBranchTwice
+ }
+ }
+
+ return ""
+}
+
func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func() error {
return func() error {
currentBranch := self.c.Helpers().Refs.GetCheckedOutRef()
@@ -73,13 +88,13 @@ func (self *SyncController) push(currentBranch *models.Branch) error {
if currentBranch.IsTrackingRemote() {
opts := pushOpts{}
if currentBranch.HasCommitsToPull() {
- return self.requestToForcePush(opts)
+ return self.requestToForcePush(currentBranch, opts)
} else {
- return self.pushAux(opts)
+ return self.pushAux(currentBranch, opts)
}
} else {
if self.c.Git().Config.GetPushToCurrent() {
- return self.pushAux(pushOpts{setUpstream: true})
+ return self.pushAux(currentBranch, pushOpts{setUpstream: true})
} else {
return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(currentBranch, func(upstream string) error {
upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream)
@@ -87,7 +102,7 @@ func (self *SyncController) push(currentBranch *models.Branch) error {
return self.c.Error(err)
}
- return self.pushAux(pushOpts{
+ return self.pushAux(currentBranch, pushOpts{
setUpstream: true,
upstreamRemote: upstreamRemote,
upstreamBranch: upstreamBranch,
@@ -107,11 +122,11 @@ func (self *SyncController) pull(currentBranch *models.Branch) error {
return self.c.Error(err)
}
- return self.PullAux(PullFilesOptions{Action: action})
+ return self.PullAux(currentBranch, PullFilesOptions{Action: action})
})
}
- return self.PullAux(PullFilesOptions{Action: action})
+ return self.PullAux(currentBranch, PullFilesOptions{Action: action})
}
func (self *SyncController) setCur