Skip to content

Commit ff4ae4a

Browse files
committed
Fix possible crash when deleting a branch while filtering is active
The code that tries to reselect the same branch again uses GetItems, which in case of filtering is the filtered list. After replacing the branches slice with a new one, the filtered list is no longer up to date, so we must reapply the filter before working with it. It so happens that refreshView does that, so simply call that before setting the selection again; I don't think the order matters in this case. Otherwise we'd have to insert another call to ReApplyFilter before the call to GetItems, which we can avoid this way. Note that this doesn't actually make anything work better in the case of deleting a branch, since we can't reselect the deleted branch anyway of course. But it avoids a possible crash if the branch that was deleted was the last one in the unfiltered list.
1 parent a0aa7a1 commit ff4ae4a

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

pkg/gui/controllers/helpers/refresh_helper.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
490490
self.refreshView(self.c.Contexts().Worktrees)
491491
}
492492

493+
self.refreshView(self.c.Contexts().Branches)
494+
493495
if !keepBranchSelectionIndex && prevSelectedBranch != nil {
494496
_, idx, found := lo.FindIndexOf(self.c.Contexts().Branches.GetItems(),
495497
func(b *models.Branch) bool { return b.Name == prevSelectedBranch.Name })
@@ -498,8 +500,6 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
498500
}
499501
}
500502

501-
self.refreshView(self.c.Contexts().Branches)
502-
503503
// Need to re-render the commits view because the visualization of local
504504
// branch heads might have changed
505505
self.c.Mutexes().LocalCommitsMutex.Lock()
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package branch
2+
3+
import (
4+
"github.com/jesseduffield/lazygit/pkg/config"
5+
. "github.com/jesseduffield/lazygit/pkg/integration/components"
6+
)
7+
8+
// Regression test for deleting the last branch in the unfiltered list while
9+
// filtering is on. This used to cause a segfault.
10+
var DeleteWhileFiltering = NewIntegrationTest(NewIntegrationTestArgs{
11+
Description: "Delete a local branch while there's a filter in the branches panel",
12+
ExtraCmdArgs: []string{},
13+
Skip: false,
14+
SetupConfig: func(config *config.AppConfig) {
15+
config.GetAppState().LocalBranchSortOrder = "alphabetic"
16+
},
17+
SetupRepo: func(shell *Shell) {
18+
shell.EmptyCommit("one")
19+
shell.NewBranch("branch1")
20+
shell.NewBranch("branch2")
21+
shell.Checkout("master")
22+
},
23+
Run: func(t *TestDriver, keys config.KeybindingConfig) {
24+
t.Views().Branches().
25+
Focus().
26+
Lines(
27+
Contains("master").IsSelected(),
28+
Contains("branch1"),
29+
Contains("branch2"),
30+
).
31+
FilterOrSearch("branch").
32+
Lines(
33+
Contains("branch1").IsSelected(),
34+
Contains("branch2"),
35+
).
36+
SelectNextItem().
37+
Press(keys.Universal.Remove).
38+
Tap(func() {
39+
t.ExpectPopup().
40+
Menu().
41+
Title(Equals("Delete branch 'branch2'?")).
42+
Select(Contains("Delete local branch")).
43+
Confirm()
44+
}).
45+
Lines(
46+
Contains("branch1").IsSelected(),
47+
)
48+
},
49+
})

pkg/integration/tests/test_list.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var tests = []*components.IntegrationTest{
4545
branch.DeleteMultiple,
4646
branch.DeleteRemoteBranchWithCredentialPrompt,
4747
branch.DeleteRemoteBranchWithDifferentName,
48+
branch.DeleteWhileFiltering,
4849
branch.DetachedHead,
4950
branch.NewBranchAutostash,
5051
branch.NewBranchFromRemoteTrackingDifferentName,

0 commit comments

Comments
 (0)