mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-19 21:28:28 +02:00
Keep same branch selected when fetching a branch while sorted by date (#3186)
- **PR Description** Now that branches can be sorted by date, there's a new situation that we didn't have before: when fetching a branch, its committer date can change, so it will move up in the list; we need to update the selection index to follow. This is important for the case that master is behind its upstream and you want to rebase your checked-out branch onto master: in that case you would select master, press "f" to fetch, and then press "r" to rebase onto it. It's very bad if master doesn't stay selected after fetching. - **Please check if the PR fulfills these requirements** * [x] Cheatsheets are up-to-date (run `go generate ./...`) * [x] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting)) * [x] Tests have been added/updated (see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md) for the integration test guide) * [ ] Text is internationalised (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation)) * [ ] Docs (specifically `docs/Config.md`) have been updated if necessary * [x] You've read through your own file changes for silly mistakes etc <!-- Be sure to name your PR with an imperative e.g. 'Add worktrees view' see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for examples -->
This commit is contained in:
commit
221ebdc1fb
@ -447,7 +447,7 @@ func (self *BranchesController) createNewBranchWithName(newBranchName string) er
|
||||
}
|
||||
|
||||
self.context().SetSelection(0)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, KeepBranchSelectionIndex: true})
|
||||
}
|
||||
|
||||
func (self *BranchesController) checkedOutByOtherWorktree(branch *models.Branch) bool {
|
||||
|
@ -126,7 +126,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
refresh("commits and commit files", self.refreshCommitsAndCommitFiles)
|
||||
|
||||
includeWorktreesWithBranches = scopeSet.Includes(types.WORKTREES)
|
||||
refresh("reflog and branches", func() { self.refreshReflogAndBranches(includeWorktreesWithBranches) })
|
||||
refresh("reflog and branches", func() { self.refreshReflogAndBranches(includeWorktreesWithBranches, options.KeepBranchSelectionIndex) })
|
||||
} 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
|
||||
@ -248,7 +248,7 @@ func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
|
||||
case types.INITIAL:
|
||||
self.c.OnWorker(func(_ gocui.Task) {
|
||||
_ = self.refreshReflogCommits()
|
||||
self.refreshBranches(false)
|
||||
self.refreshBranches(false, true)
|
||||
self.c.State().GetRepoState().SetStartupStage(types.COMPLETE)
|
||||
})
|
||||
|
||||
@ -257,10 +257,10 @@ func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshReflogAndBranches(refreshWorktrees bool) {
|
||||
func (self *RefreshHelper) refreshReflogAndBranches(refreshWorktrees bool, keepBranchSelectionIndex bool) {
|
||||
self.refreshReflogCommitsConsideringStartup()
|
||||
|
||||
self.refreshBranches(refreshWorktrees)
|
||||
self.refreshBranches(refreshWorktrees, keepBranchSelectionIndex)
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshCommitsAndCommitFiles() {
|
||||
@ -425,10 +425,12 @@ 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(refreshWorktrees bool) {
|
||||
func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSelectionIndex bool) {
|
||||
self.c.Mutexes().RefreshingBranchesMutex.Lock()
|
||||
defer self.c.Mutexes().RefreshingBranchesMutex.Unlock()
|
||||
|
||||
prevSelectedBranch := self.c.Contexts().Branches.GetSelected()
|
||||
|
||||
reflogCommits := self.c.Model().FilteredReflogCommits
|
||||
if self.c.Modes().Filtering.Active() && self.c.AppState.LocalBranchSortOrder == "recency" {
|
||||
// in filter mode we filter our reflog commits to just those containing the path
|
||||
@ -456,6 +458,14 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if !keepBranchSelectionIndex && prevSelectedBranch != nil {
|
||||
_, idx, found := lo.FindIndexOf(self.c.Contexts().Branches.GetItems(),
|
||||
func(b *models.Branch) bool { return b.Name == prevSelectedBranch.Name })
|
||||
if found {
|
||||
self.c.Contexts().Branches.SetSelectedLineIdx(idx)
|
||||
}
|
||||
}
|
||||
|
||||
if err := self.refreshView(self.c.Contexts().Branches); err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
|
||||
self.c.Contexts().LocalCommits.SetLimitCommits(true)
|
||||
}
|
||||
|
||||
refreshOptions := types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true}
|
||||
|
||||
return self.c.WithWaitingStatus(waitingStatus, 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
|
||||
@ -74,12 +76,12 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
|
||||
|
||||
onSuccess()
|
||||
if err := self.c.Git().Stash.Pop(0); err != nil {
|
||||
if err := self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}); err != nil {
|
||||
if err := self.c.Refresh(refreshOptions); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Error(err)
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI})
|
||||
return self.c.Refresh(refreshOptions)
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -90,7 +92,7 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
|
||||
}
|
||||
onSuccess()
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI})
|
||||
return self.c.Refresh(refreshOptions)
|
||||
})
|
||||
}
|
||||
|
||||
@ -218,7 +220,7 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest
|
||||
self.c.Contexts().LocalCommits.SetSelection(0)
|
||||
self.c.Contexts().Branches.SetSelection(0)
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -36,4 +36,11 @@ type RefreshOptions struct {
|
||||
Then func()
|
||||
Scope []RefreshableView // e.g. []RefreshableView{COMMITS, BRANCHES}. Leave empty to refresh everything
|
||||
Mode RefreshMode // one of SYNC (default), ASYNC, and BLOCK_UI
|
||||
|
||||
// Normally a refresh of the branches tries to keep the same branch selected
|
||||
// (by name); this is usually important in case the order of branches
|
||||
// changes. Passing true for KeepBranchSelectionIndex suppresses this and
|
||||
// keeps the selection index the same. Useful after checking out a detached
|
||||
// head, and selecting index 0.
|
||||
KeepBranchSelectionIndex bool
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Branches().
|
||||
Lines(
|
||||
Contains("branch-three").IsSelected(),
|
||||
Contains("branch-four"),
|
||||
Contains("branch-three"),
|
||||
Contains("branch-four").IsSelected(),
|
||||
Contains("branch-two"),
|
||||
Contains("branch-one"),
|
||||
)
|
||||
|
@ -57,8 +57,8 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Branches().
|
||||
Lines(
|
||||
Contains("branch-three").IsSelected(),
|
||||
Contains("branch-four"),
|
||||
Contains("branch-three"),
|
||||
Contains("branch-four").IsSelected(),
|
||||
Contains("branch-two"),
|
||||
Contains("branch-one"),
|
||||
)
|
||||
|
49
pkg/integration/tests/sync/fetch_when_sorted_by_date.go
Normal file
49
pkg/integration/tests/sync/fetch_when_sorted_by_date.go
Normal file
@ -0,0 +1,49 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var FetchWhenSortedByDate = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Fetch a branch while sort order is by date; verify that branch stays selected",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
EmptyCommitWithDate("commit", "2023-04-07 10:00:00"). // first master commit, older than branch2
|
||||
EmptyCommitWithDate("commit", "2023-04-07 12:00:00"). // second master commit, newer than branch2
|
||||
NewBranch("branch1"). // branch1 will be checked out, so its date doesn't matter
|
||||
EmptyCommitWithDate("commit", "2023-04-07 11:00:00"). // branch2 commit, date is between the two master commits
|
||||
NewBranch("branch2").
|
||||
Checkout("master").
|
||||
CloneIntoRemote("origin").
|
||||
SetBranchUpstream("master", "origin/master"). // upstream points to second master commit
|
||||
HardReset("HEAD^"). // rewind to first master commit
|
||||
Checkout("branch1")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Press(keys.Branches.SortOrder)
|
||||
|
||||
t.ExpectPopup().Menu().Title(Equals("Sort order")).
|
||||
Select(Contains("-committerdate")).
|
||||
Confirm()
|
||||
|
||||
t.Views().Branches().
|
||||
Lines(
|
||||
Contains("* branch1").IsSelected(),
|
||||
Contains("branch2"),
|
||||
Contains("master ↓1"),
|
||||
).
|
||||
NavigateToLine(Contains("master")).
|
||||
Press(keys.Branches.FetchRemote).
|
||||
Lines(
|
||||
Contains("* branch1"),
|
||||
Contains("master").IsSelected(),
|
||||
Contains("branch2"),
|
||||
)
|
||||
},
|
||||
})
|
@ -230,6 +230,7 @@ var tests = []*components.IntegrationTest{
|
||||
submodule.Remove,
|
||||
submodule.Reset,
|
||||
sync.FetchPrune,
|
||||
sync.FetchWhenSortedByDate,
|
||||
sync.ForcePush,
|
||||
sync.ForcePushMultipleMatching,
|
||||
sync.ForcePushMultipleUpstream,
|
||||
|
Loading…
x
Reference in New Issue
Block a user