1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-15 01:34:26 +02:00

Move LocalBranchSortOrder and RemoteBranchSortOrder to user config

At the same time, we change the defaults for both of them to "date" (they were
"recency" and "alphabetical", respectively, before). This is the reason we need
to touch so many integration tests. For some of them I decided to adapt the test
assertions to the changed sort order; for others, I added a SetupConfig step to
set the order back to "recency" so that I don't have to change what the test
does (e.g. how many SelectNextItem() calls are needed to get to a certain
branch).
This commit is contained in:
Stefan Haller
2025-07-07 15:37:05 +02:00
parent d79283656d
commit 703256e92d
35 changed files with 161 additions and 66 deletions

View File

@ -399,6 +399,16 @@ git:
# displays the whole git graph by default in the commits view (equivalent to passing the `--all` argument to `git log`) # displays the whole git graph by default in the commits view (equivalent to passing the `--all` argument to `git log`)
showWholeGraph: false showWholeGraph: false
# How branches are sorted in the local branches view.
# One of: 'date' (default) | 'recency' | 'alphabetical'
# Can be changed from within Lazygit with the Sort Order menu (`s`) in the branches panel.
localBranchSortOrder: date
# How branches are sorted in the remote branches view.
# One of: 'date' (default) | 'alphabetical'
# Can be changed from within Lazygit with the Sort Order menu (`s`) in the remote branches panel.
remoteBranchSortOrder: date
# When copying commit hashes to the clipboard, truncate them to this # When copying commit hashes to the clipboard, truncate them to this
# length. Set to 40 to disable truncation. # length. Set to 40 to disable truncation.
truncateCopiedCommitHashesTo: 12 truncateCopiedCommitHashesTo: 12

View File

@ -74,7 +74,7 @@ func (self *BranchLoader) Load(reflogCommits []*models.Commit,
) ([]*models.Branch, error) { ) ([]*models.Branch, error) {
branches := self.obtainBranches() branches := self.obtainBranches()
if self.AppState.LocalBranchSortOrder == "recency" { if self.UserConfig().Git.LocalBranchSortOrder == "recency" {
reflogBranches := self.obtainReflogBranches(reflogCommits) reflogBranches := self.obtainReflogBranches(reflogCommits)
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches // loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
branchesWithRecency := make([]*models.Branch, 0) branchesWithRecency := make([]*models.Branch, 0)
@ -254,7 +254,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
return nil, false return nil, false
} }
storeCommitDateAsRecency := self.AppState.LocalBranchSortOrder != "recency" storeCommitDateAsRecency := self.UserConfig().Git.LocalBranchSortOrder != "recency"
return obtainBranch(split, storeCommitDateAsRecency), true return obtainBranch(split, storeCommitDateAsRecency), true
}) })
} }
@ -268,7 +268,7 @@ func (self *BranchLoader) getRawBranches() (string, error) {
) )
var sortOrder string var sortOrder string
switch strings.ToLower(self.AppState.LocalBranchSortOrder) { switch strings.ToLower(self.UserConfig().Git.LocalBranchSortOrder) {
case "recency", "date": case "recency", "date":
sortOrder = "-committerdate" sortOrder = "-committerdate"
case "alphabetical": case "alphabetical":

View File

@ -85,7 +85,7 @@ func (self *RemoteLoader) getRemoteBranchesByRemoteName() (map[string][]*models.
remoteBranchesByRemoteName := make(map[string][]*models.RemoteBranch) remoteBranchesByRemoteName := make(map[string][]*models.RemoteBranch)
var sortOrder string var sortOrder string
switch strings.ToLower(self.AppState.RemoteBranchSortOrder) { switch strings.ToLower(self.UserConfig().Git.RemoteBranchSortOrder) {
case "alphabetical": case "alphabetical":
sortOrder = "refname" sortOrder = "refname"
case "date": case "date":

View File

@ -676,9 +676,7 @@ type AppState struct {
// For backwards compatibility we keep the old name in yaml files. // For backwards compatibility we keep the old name in yaml files.
ShellCommandsHistory []string `yaml:"customcommandshistory"` ShellCommandsHistory []string `yaml:"customcommandshistory"`
HideCommandLog bool HideCommandLog bool
LocalBranchSortOrder string
RemoteBranchSortOrder string
// One of: 'date-order' | 'author-date-order' | 'topo-order' | 'default' // One of: 'date-order' | 'author-date-order' | 'topo-order' | 'default'
// 'topo-order' makes it easier to read the git log graph, but commits may not // 'topo-order' makes it easier to read the git log graph, but commits may not
@ -692,14 +690,12 @@ type AppState struct {
func getDefaultAppState() *AppState { func getDefaultAppState() *AppState {
return &AppState{ return &AppState{
LastUpdateCheck: 0, LastUpdateCheck: 0,
RecentRepos: []string{}, RecentRepos: []string{},
StartupPopupVersion: 0, StartupPopupVersion: 0,
LastVersion: "", LastVersion: "",
LocalBranchSortOrder: "recency", GitLogOrder: "", // should be "topo-order" eventually
RemoteBranchSortOrder: "alphabetical", GitLogShowGraph: "", // should be "always" eventually
GitLogOrder: "", // should be "topo-order" eventually
GitLogShowGraph: "", // should be "always" eventually
} }
} }

View File

@ -285,6 +285,14 @@ type GitConfig struct {
ParseEmoji bool `yaml:"parseEmoji"` ParseEmoji bool `yaml:"parseEmoji"`
// Config for showing the log in the commits view // Config for showing the log in the commits view
Log LogConfig `yaml:"log"` Log LogConfig `yaml:"log"`
// How branches are sorted in the local branches view.
// One of: 'date' (default) | 'recency' | 'alphabetical'
// Can be changed from within Lazygit with the Sort Order menu (`s`) in the branches panel.
LocalBranchSortOrder string `yaml:"localBranchSortOrder" jsonschema:"enum=date,enum=recency,enum=alphabetical"`
// How branches are sorted in the remote branches view.
// One of: 'date' (default) | 'alphabetical'
// Can be changed from within Lazygit with the Sort Order menu (`s`) in the remote branches panel.
RemoteBranchSortOrder string `yaml:"remoteBranchSortOrder" jsonschema:"enum=date,enum=alphabetical"`
// When copying commit hashes to the clipboard, truncate them to this // When copying commit hashes to the clipboard, truncate them to this
// length. Set to 40 to disable truncation. // length. Set to 40 to disable truncation.
TruncateCopiedCommitHashesTo int `yaml:"truncateCopiedCommitHashesTo"` TruncateCopiedCommitHashesTo int `yaml:"truncateCopiedCommitHashesTo"`
@ -805,6 +813,8 @@ func GetDefaultConfig() *UserConfig {
ShowGraph: "always", ShowGraph: "always",
ShowWholeGraph: false, ShowWholeGraph: false,
}, },
LocalBranchSortOrder: "date",
RemoteBranchSortOrder: "date",
SkipHookPrefix: "WIP", SkipHookPrefix: "WIP",
MainBranches: []string{"master", "main"}, MainBranches: []string{"master", "main"},
AutoFetch: true, AutoFetch: true,

View File

@ -23,6 +23,14 @@ func (config *UserConfig) Validate() error {
[]string{"none", "onlyMainBranches", "allBranches"}); err != nil { []string{"none", "onlyMainBranches", "allBranches"}); err != nil {
return err return err
} }
if err := validateEnum("git.localBranchSortOrder", config.Git.LocalBranchSortOrder,
[]string{"date", "recency", "alphabetical"}); err != nil {
return err
}
if err := validateEnum("git.remoteBranchSortOrder", config.Git.RemoteBranchSortOrder,
[]string{"date", "alphabetical"}); err != nil {
return err
}
if err := validateKeybindings(config.Keybinding); err != nil { if err := validateKeybindings(config.Keybinding); err != nil {
return err return err
} }

View File

@ -56,6 +56,32 @@ func TestUserConfigValidate_enums(t *testing.T) {
{value: "invalid_value", valid: false}, {value: "invalid_value", valid: false},
}, },
}, },
{
name: "Git.LocalBranchSortOrder",
setup: func(config *UserConfig, value string) {
config.Git.LocalBranchSortOrder = value
},
testCases: []testCase{
{value: "date", valid: true},
{value: "recency", valid: true},
{value: "alphabetical", valid: true},
{value: "", valid: false},
{value: "invalid_value", valid: false},
},
},
{
name: "Git.RemoteBranchSortOrder",
setup: func(config *UserConfig, value string) {
config.Git.RemoteBranchSortOrder = value
},
testCases: []testCase{
{value: "date", valid: true},
{value: "recency", valid: false},
{value: "alphabetical", valid: true},
{value: "", valid: false},
{value: "invalid_value", valid: false},
},
},
{ {
name: "Keybindings", name: "Keybindings",
setup: func(config *UserConfig, value string) { setup: func(config *UserConfig, value string) {

View File

@ -674,16 +674,15 @@ func (self *BranchesController) createTag(branch *models.Branch) error {
func (self *BranchesController) createSortMenu() error { func (self *BranchesController) createSortMenu() error {
return self.c.Helpers().Refs.CreateSortOrderMenu([]string{"recency", "alphabetical", "date"}, func(sortOrder string) error { return self.c.Helpers().Refs.CreateSortOrderMenu([]string{"recency", "alphabetical", "date"}, func(sortOrder string) error {
if self.c.GetAppState().LocalBranchSortOrder != sortOrder { if self.c.UserConfig().Git.LocalBranchSortOrder != sortOrder {
self.c.GetAppState().LocalBranchSortOrder = sortOrder self.c.UserConfig().Git.LocalBranchSortOrder = sortOrder
self.c.SaveAppStateAndLogError()
self.c.Contexts().Branches.SetSelection(0) self.c.Contexts().Branches.SetSelection(0)
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
return nil return nil
} }
return nil return nil
}, },
self.c.GetAppState().LocalBranchSortOrder) self.c.UserConfig().Git.LocalBranchSortOrder)
} }
func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error { func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error {

View File

@ -125,7 +125,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) {
refresh("commits and commit files", self.refreshCommitsAndCommitFiles) refresh("commits and commit files", self.refreshCommitsAndCommitFiles)
includeWorktreesWithBranches = scopeSet.Includes(types.WORKTREES) includeWorktreesWithBranches = scopeSet.Includes(types.WORKTREES)
if self.c.AppState.LocalBranchSortOrder == "recency" { if self.c.UserConfig().Git.LocalBranchSortOrder == "recency" {
refresh("reflog and branches", func() { self.refreshReflogAndBranches(includeWorktreesWithBranches, options.KeepBranchSelectionIndex) }) refresh("reflog and branches", func() { self.refreshReflogAndBranches(includeWorktreesWithBranches, options.KeepBranchSelectionIndex) })
} else { } else {
refresh("branches", func() { self.refreshBranches(includeWorktreesWithBranches, options.KeepBranchSelectionIndex, true) }) refresh("branches", func() { self.refreshBranches(includeWorktreesWithBranches, options.KeepBranchSelectionIndex, true) })
@ -446,7 +446,7 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
defer self.c.Mutexes().RefreshingBranchesMutex.Unlock() defer self.c.Mutexes().RefreshingBranchesMutex.Unlock()
reflogCommits := self.c.Model().FilteredReflogCommits reflogCommits := self.c.Model().FilteredReflogCommits
if self.c.Modes().Filtering.Active() && self.c.AppState.LocalBranchSortOrder == "recency" { if self.c.Modes().Filtering.Active() && self.c.UserConfig().Git.LocalBranchSortOrder == "recency" {
// in filter mode we filter our reflog commits to just those containing the path // in filter mode we filter our reflog commits to just those containing the path
// however we need all the reflog entries to populate the recencies of our branches // however we need all the reflog entries to populate the recencies of our branches
// which allows us to order them correctly. So if we're filtering we'll just // which allows us to order them correctly. So if we're filtering we'll just

View File

@ -146,15 +146,14 @@ func (self *RemoteBranchesController) rebase(selectedBranch *models.RemoteBranch
func (self *RemoteBranchesController) createSortMenu() error { func (self *RemoteBranchesController) createSortMenu() error {
return self.c.Helpers().Refs.CreateSortOrderMenu([]string{"alphabetical", "date"}, func(sortOrder string) error { return self.c.Helpers().Refs.CreateSortOrderMenu([]string{"alphabetical", "date"}, func(sortOrder string) error {
if self.c.GetAppState().RemoteBranchSortOrder != sortOrder { if self.c.UserConfig().Git.RemoteBranchSortOrder != sortOrder {
self.c.GetAppState().RemoteBranchSortOrder = sortOrder self.c.UserConfig().Git.RemoteBranchSortOrder = sortOrder
self.c.SaveAppStateAndLogError()
self.c.Contexts().RemoteBranches.SetSelection(0) self.c.Contexts().RemoteBranches.SetSelection(0)
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.REMOTES}}) self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.REMOTES}})
} }
return nil return nil
}, },
self.c.GetAppState().RemoteBranchSortOrder) self.c.UserConfig().Git.RemoteBranchSortOrder)
} }
func (self *RemoteBranchesController) createResetMenu(selectedBranch *models.RemoteBranch) error { func (self *RemoteBranchesController) createResetMenu(selectedBranch *models.RemoteBranch) error {

View File

@ -33,8 +33,8 @@ var CheckoutByName = NewIntegrationTest(NewIntegrationTestArgs{
}). }).
Lines( Lines(
MatchesRegexp(`\*.*new-branch`).IsSelected(), MatchesRegexp(`\*.*new-branch`).IsSelected(),
Contains("master"),
Contains("@"), Contains("@"),
Contains("master"),
) )
}, },
}) })

View File

@ -9,7 +9,9 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Try all combination of local and remote branch deletions", Description: "Try all combination of local and remote branch deletions",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.
CloneIntoRemote("origin"). CloneIntoRemote("origin").

View File

@ -10,7 +10,8 @@ var DeleteMultiple = NewIntegrationTest(NewIntegrationTestArgs{
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) { SetupConfig: func(config *config.AppConfig) {
config.GetAppState().LocalBranchSortOrder = "alphabetic" config.GetUserConfig().Git.LocalBranchSortOrder = "alphabetical"
config.GetUserConfig().Git.RemoteBranchSortOrder = "alphabetical"
}, },
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.

View File

@ -12,7 +12,7 @@ var DeleteWhileFiltering = NewIntegrationTest(NewIntegrationTestArgs{
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) { SetupConfig: func(config *config.AppConfig) {
config.GetAppState().LocalBranchSortOrder = "alphabetic" config.GetUserConfig().Git.LocalBranchSortOrder = "alphabetical"
}, },
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell.EmptyCommit("one") shell.EmptyCommit("one")

View File

@ -10,7 +10,9 @@ var Rebase = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Rebase onto another branch, deal with the conflicts.", Description: "Rebase onto another branch, deal with the conflicts.",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shared.MergeConflictsSetup(shell) shared.MergeConflictsSetup(shell)
}, },

View File

@ -10,7 +10,9 @@ var RebaseAbortOnConflict = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Rebase onto another branch, abort when there are conflicts.", Description: "Rebase onto another branch, abort when there are conflicts.",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shared.MergeConflictsSetup(shell) shared.MergeConflictsSetup(shell)
}, },

View File

@ -10,7 +10,9 @@ var RebaseAndDrop = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Rebase onto another branch, deal with the conflicts. Also mark a commit to be dropped before continuing.", Description: "Rebase onto another branch, deal with the conflicts. Also mark a commit to be dropped before continuing.",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shared.MergeConflictsSetup(shell) shared.MergeConflictsSetup(shell)
// adding a couple additional commits so that we can drop one // adding a couple additional commits so that we can drop one

View File

@ -10,7 +10,9 @@ var RebaseCancelOnConflict = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Rebase onto another branch, cancel when there are conflicts.", Description: "Rebase onto another branch, cancel when there are conflicts.",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shared.MergeConflictsSetup(shell) shared.MergeConflictsSetup(shell)
}, },

View File

@ -10,7 +10,9 @@ var RebaseConflictsFixBuildErrors = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Rebase onto another branch, deal with the conflicts. While continue prompt is showing, fix build errors; get another prompt when continuing.", Description: "Rebase onto another branch, deal with the conflicts. While continue prompt is showing, fix build errors; get another prompt when continuing.",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shared.MergeConflictsSetup(shell) shared.MergeConflictsSetup(shell)
}, },

View File

@ -9,7 +9,9 @@ var RebaseFromMarkedBase = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Rebase onto another branch from a marked base commit", Description: "Rebase onto another branch from a marked base commit",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.
NewBranch("base-branch"). NewBranch("base-branch").

View File

@ -9,7 +9,9 @@ var ResetToUpstream = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Hard reset the current branch to the selected branch upstream", Description: "Hard reset the current branch to the selected branch upstream",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.
CloneIntoRemote("origin"). CloneIntoRemote("origin").

View File

@ -22,13 +22,13 @@ var SortLocalBranches = NewIntegrationTest(NewIntegrationTestArgs{
Checkout("master") Checkout("master")
}, },
Run: func(t *TestDriver, keys config.KeybindingConfig) { Run: func(t *TestDriver, keys config.KeybindingConfig) {
// sorted by recency by default // sorted by date by default
t.Views().Branches(). t.Views().Branches().
Focus(). Focus().
Lines( Lines(
Contains("master").IsSelected(), Contains("master").IsSelected(),
Contains("third"),
Contains("second"), Contains("second"),
Contains("third"),
Contains("first"), Contains("first"),
). ).
SelectNextItem() // to test that the selection jumps back to the top when sorting SelectNextItem() // to test that the selection jumps back to the top when sorting
@ -38,20 +38,20 @@ var SortLocalBranches = NewIntegrationTest(NewIntegrationTestArgs{
t.ExpectPopup().Menu().Title(Equals("Sort order")). t.ExpectPopup().Menu().Title(Equals("Sort order")).
Lines( Lines(
Contains("r () Recency").IsSelected(), Contains("r ( ) Recency").IsSelected(),
Contains("a ( ) Alphabetical"), Contains("a ( ) Alphabetical"),
Contains("d ( ) Date"), Contains("d () Date"),
Contains(" Cancel"), Contains(" Cancel"),
). ).
Select(Contains("-committerdate")). Select(Contains("Recency")).
Confirm() Confirm()
t.Views().Branches(). t.Views().Branches().
IsFocused(). IsFocused().
Lines( Lines(
Contains("master").IsSelected(), Contains("master").IsSelected(),
Contains("second"),
Contains("third"), Contains("third"),
Contains("second"),
Contains("first"), Contains("first"),
) )
@ -60,9 +60,9 @@ var SortLocalBranches = NewIntegrationTest(NewIntegrationTestArgs{
t.ExpectPopup().Menu().Title(Equals("Sort order")). t.ExpectPopup().Menu().Title(Equals("Sort order")).
Lines( Lines(
Contains("r ( ) Recency").IsSelected(), Contains("r () Recency").IsSelected(),
Contains("a ( ) Alphabetical"), Contains("a ( ) Alphabetical"),
Contains("d () Date"), Contains("d ( ) Date"),
Contains(" Cancel"), Contains(" Cancel"),
). ).
Select(Contains("refname")). Select(Contains("refname")).

View File

@ -27,13 +27,13 @@ var SortRemoteBranches = NewIntegrationTest(NewIntegrationTestArgs{
). ).
PressEnter() PressEnter()
// sorted alphabetically by default // sorted by date by default
t.Views().RemoteBranches(). t.Views().RemoteBranches().
IsFocused(). IsFocused().
Lines( Lines(
Contains("first").IsSelected(), Contains("second").IsSelected(),
Contains("second"),
Contains("third"), Contains("third"),
Contains("first"),
). ).
SelectNextItem() // to test that the selection jumps back to the first when sorting SelectNextItem() // to test that the selection jumps back to the first when sorting
@ -42,19 +42,19 @@ var SortRemoteBranches = NewIntegrationTest(NewIntegrationTestArgs{
t.ExpectPopup().Menu().Title(Equals("Sort order")). t.ExpectPopup().Menu().Title(Equals("Sort order")).
Lines( Lines(
Contains("a () Alphabetical").IsSelected(), Contains("a ( ) Alphabetical").IsSelected(),
Contains("d ( ) Date"), Contains("d () Date"),
Contains(" Cancel"), Contains(" Cancel"),
). ).
Select(Contains("-committerdate")). Select(Contains("Alphabetical")).
Confirm() Confirm()
t.Views().RemoteBranches(). t.Views().RemoteBranches().
IsFocused(). IsFocused().
Lines( Lines(
Contains("second").IsSelected(), Contains("first").IsSelected(),
Contains("second"),
Contains("third"), Contains("third"),
Contains("first"),
) )
}, },
}) })

View File

@ -9,7 +9,9 @@ var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Cherry pick commits from the subcommits view, without conflicts", Description: "Cherry pick commits from the subcommits view, without conflicts",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.
EmptyCommit("base"). EmptyCommit("base").

View File

@ -10,7 +10,9 @@ var CherryPickConflicts = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Cherry pick commits from the subcommits view, with conflicts", Description: "Cherry pick commits from the subcommits view, with conflicts",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shared.MergeConflictsSetup(shell) shared.MergeConflictsSetup(shell)
}, },

View File

@ -11,6 +11,7 @@ var CherryPickDuringRebase = NewIntegrationTest(NewIntegrationTestArgs{
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) { SetupConfig: func(config *config.AppConfig) {
config.GetAppState().GitLogShowGraph = "never" config.GetAppState().GitLogShowGraph = "never"
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
}, },
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.

View File

@ -9,7 +9,9 @@ var CherryPickMerge = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Cherry pick a merge commit", Description: "Cherry pick a merge commit",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.
EmptyCommit("base"). EmptyCommit("base").

View File

@ -9,7 +9,9 @@ var CherryPickRange = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Cherry pick range of commits from the subcommits view, without conflicts", Description: "Cherry pick range of commits from the subcommits view, without conflicts",
ExtraCmdArgs: []string{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Git.LocalBranchSortOrder = "recency"
},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.
EmptyCommit("base"). EmptyCommit("base").

View File

@ -42,8 +42,8 @@ var Checkout = NewIntegrationTest(NewIntegrationTestArgs{
Confirm() Confirm()
t.Views().Branches().Lines( t.Views().Branches().Lines(
Contains("* (HEAD detached at"), Contains("* (HEAD detached at"),
Contains("branch2"),
Contains("branch1"), Contains("branch1"),
Contains("branch2"),
Contains("master"), Contains("master"),
) )
@ -63,8 +63,8 @@ var Checkout = NewIntegrationTest(NewIntegrationTestArgs{
Confirm() Confirm()
t.Views().Branches().Lines( t.Views().Branches().Lines(
Contains("master"), Contains("master"),
Contains("branch2"),
Contains("branch1"), Contains("branch1"),
Contains("branch2"),
) )
}, },
}) })

View File

@ -24,6 +24,8 @@ var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{
}, },
}, },
} }
cfg.GetUserConfig().Git.LocalBranchSortOrder = "recency"
}, },
Run: func(t *TestDriver, keys config.KeybindingConfig) { Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Branches(). t.Views().Branches().

View File

@ -43,9 +43,9 @@ var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{
Focus(). Focus().
Lines( Lines(
Contains("branch-four").IsSelected(), Contains("branch-four").IsSelected(),
Contains("branch-one"),
Contains("branch-three"), Contains("branch-three"),
Contains("branch-two"), Contains("branch-two"),
Contains("branch-one"),
). ).
Press("a") Press("a")
@ -59,8 +59,8 @@ var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{
Lines( Lines(
Contains("branch-three"), Contains("branch-three"),
Contains("branch-four").IsSelected(), Contains("branch-four").IsSelected(),
Contains("branch-two"),
Contains("branch-one"), Contains("branch-one"),
Contains("branch-two"),
) )
}, },
}) })

View File

@ -43,9 +43,9 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{
Focus(). Focus().
Lines( Lines(
Contains("branch-four").IsSelected(), Contains("branch-four").IsSelected(),
Contains("branch-one"),
Contains("branch-three"), Contains("branch-three"),
Contains("branch-two"), Contains("branch-two"),
Contains("branch-one"),
). ).
Press("a") Press("a")
@ -59,8 +59,8 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{
Lines( Lines(
Contains("branch-three"), Contains("branch-three"),
Contains("branch-four").IsSelected(), Contains("branch-four").IsSelected(),
Contains("branch-two"),
Contains("branch-one"), Contains("branch-one"),
Contains("branch-two"),
) )
}, },
}) })

View File

@ -21,9 +21,9 @@ var FilterUpdatesWhenModelChanges = NewIntegrationTest(NewIntegrationTestArgs{
Focus(). Focus().
Lines( Lines(
Contains("checked-out-branch").IsSelected(), Contains("checked-out-branch").IsSelected(),
Contains("other"),
Contains("branch-to-delete"), Contains("branch-to-delete"),
Contains("master"), Contains("master"),
Contains("other"),
). ).
FilterOrSearch("branch"). FilterOrSearch("branch").
Lines( Lines(
@ -65,9 +65,9 @@ var FilterUpdatesWhenModelChanges = NewIntegrationTest(NewIntegrationTestArgs{
PressEscape(). PressEscape().
Lines( Lines(
Contains("checked-out-branch").IsSelected(), Contains("checked-out-branch").IsSelected(),
Contains("other"),
Contains("master"), Contains("master"),
Contains("new-branch"), Contains("new-branch"),
Contains("other"),
) )
}, },
}) })

View File

@ -35,8 +35,8 @@ var NestedFilter = NewIntegrationTest(NewIntegrationTestArgs{
Focus(). Focus().
Lines( Lines(
Contains(`branch-bronze`).IsSelected(), Contains(`branch-bronze`).IsSelected(),
Contains(`branch-silver`),
Contains(`branch-gold`), Contains(`branch-gold`),
Contains(`branch-silver`),
). ).
FilterOrSearch("sil"). FilterOrSearch("sil").
Lines( Lines(
@ -148,8 +148,8 @@ var NestedFilter = NewIntegrationTest(NewIntegrationTestArgs{
}). }).
Lines( Lines(
Contains(`branch-bronze`), Contains(`branch-bronze`),
Contains(`branch-silver`).IsSelected(),
Contains(`branch-gold`), Contains(`branch-gold`),
Contains(`branch-silver`).IsSelected(),
) )
}, },
}) })

View File

@ -416,6 +416,25 @@
"$ref": "#/$defs/LogConfig", "$ref": "#/$defs/LogConfig",
"description": "Config for showing the log in the commits view" "description": "Config for showing the log in the commits view"
}, },
"localBranchSortOrder": {
"type": "string",
"enum": [
"date",
"recency",
"alphabetical"
],
"description": "How branches are sorted in the local branches view.\nOne of: 'date' (default) | 'recency' | 'alphabetical'\nCan be changed from within Lazygit with the Sort Order menu (`s`) in the branches panel.",
"default": "date"
},
"remoteBranchSortOrder": {
"type": "string",
"enum": [
"date",
"alphabetical"
],
"description": "How branches are sorted in the remote branches view.\nOne of: 'date' (default) | 'alphabetical'\nCan be changed from within Lazygit with the Sort Order menu (`s`) in the remote branches panel.",
"default": "date"
},
"truncateCopiedCommitHashesTo": { "truncateCopiedCommitHashesTo": {
"type": "integer", "type": "integer",
"description": "When copying commit hashes to the clipboard, truncate them to this\nlength. Set to 40 to disable truncation.", "description": "When copying commit hashes to the clipboard, truncate them to this\nlength. Set to 40 to disable truncation.",