Skip to content

Commit

Permalink
Fix cancelled autostash resulting in stuck inline status (#3860)
Browse files Browse the repository at this point in the history
- **PR Description**

When switching branches, there is a "Checking out" inline status
displayed next to the branch (but only sometimes? I think if the action
completes too quickly there is no status). If it does get displayed and
the checkout results in an autostash confirmation prompt, pressing
escape to cancel the action will cancel the checkout and close the
prompt. However, the inline status will still be displayed next to the
branch and doesn't go away by itself. Performing a manual UI refresh
(`R`) fixes the state.

If the prompt was confirmed instead, then this issue would not happen.

Reproduction:
```bash
git init
echo -e "a\n\nb" > file
git add .
git commit -m "add file"
echo -e "a\n\nc" > file
git add .
git commit -m "edit last line"
git checkout -b dev HEAD~
echo -e "b\n\nb" > file
lazygit
```

Switch to the other branch in the branches panel and press escape on the
prompt. The "Checking out" inline status should be stuck.
  • Loading branch information
stefanhaller committed Aug 27, 2024
2 parents fb9f615 + ae61da7 commit 4525216
Showing 1 changed file with 40 additions and 30 deletions.
70 changes: 40 additions & 30 deletions pkg/gui/controllers/helpers/refs_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,19 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions

refreshOptions := types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true}

f := func(gocui.Task) error {
localBranch, found := lo.Find(self.c.Model().Branches, func(branch *models.Branch) bool {
return branch.Name == ref
})

withCheckoutStatus := func(f func(gocui.Task) error) error {
if found {
return self.c.WithInlineStatus(localBranch, types.ItemOperationCheckingOut, context.LOCAL_BRANCHES_CONTEXT_KEY, f)
} else {
return self.c.WithWaitingStatus(waitingStatus, f)
}
}

return withCheckoutStatus(func(gocui.Task) error {
if err := self.c.Git().Branch.Checkout(ref, cmdOptions); err != nil {
// note, this will only work for english-language git commands. If we force git to use english, and the error isn't this one, then the user will receive an english command they may not understand. I'm not sure what the best solution to this is. Running the command once in english and a second time in the native language is one option

Expand All @@ -64,44 +76,42 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions

if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") {
// offer to autostash changes
return self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error {
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + ref); err != nil {
return err
}
if err := self.c.Git().Branch.Checkout(ref, cmdOptions); err != nil {
return err
}

onSuccess()
if err := self.c.Git().Stash.Pop(0); err != nil {
if err := self.c.Refresh(refreshOptions); err != nil {
return err
}
return err
}
return self.c.Refresh(refreshOptions)
},
self.c.OnUIThread(func() error {
// (Before showing the prompt, render again to remove the inline status)
_ = self.c.Contexts().Branches.HandleRender()
return self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error {
return withCheckoutStatus(func(gocui.Task) error {
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + ref); err != nil {
return err
}
if err := self.c.Git().Branch.Checkout(ref, cmdOptions); err != nil {
return err
}

onSuccess()
if err := self.c.Git().Stash.Pop(0); err != nil {
if err := self.c.Refresh(refreshOptions); err != nil {
return err
}
return err
}
return self.c.Refresh(refreshOptions)
})
},
})
})
return nil
}

return err
}
onSuccess()

return self.c.Refresh(refreshOptions)
}

localBranch, found := lo.Find(self.c.Model().Branches, func(branch *models.Branch) bool {
return branch.Name == ref
})
if found {
return self.c.WithInlineStatus(localBranch, types.ItemOperationCheckingOut, context.LOCAL_BRANCHES_CONTEXT_KEY, f)
} else {
return self.c.WithWaitingStatus(waitingStatus, f)
}
}

// Shows a prompt to choose between creating a new branch or checking out a detached head
Expand Down

0 comments on commit 4525216

Please sign in to comment.