mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-01 00:54:58 +02:00
Fix resetting to a branch when a tag shares the same name, or vice versa (#4571)
- **PR Description** Allows the reset menu to have a different name that is displayed, and a fully qualified name that git will unambiguously know what it refers about. We could totally squash this back down to 1 input, and display to the user the _precise_ full ref name that we are resetting to, but I think the context they are in (branches tab versus tag tab), means that we don't need to do that, and can continue to just show the branch name and the tag name to the end users. Fixes https://github.com/jesseduffield/lazygit/issues/4569
This commit is contained in:
@ -96,19 +96,23 @@ func (self *RemoteLoader) getRemoteBranchesByRemoteName() (map[string][]*models.
|
|||||||
|
|
||||||
cmdArgs := NewGitCmd("for-each-ref").
|
cmdArgs := NewGitCmd("for-each-ref").
|
||||||
Arg(fmt.Sprintf("--sort=%s", sortOrder)).
|
Arg(fmt.Sprintf("--sort=%s", sortOrder)).
|
||||||
Arg("--format=%(refname:short)").
|
Arg("--format=%(refname)").
|
||||||
Arg("refs/remotes").
|
Arg("refs/remotes").
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
err := self.cmd.New(cmdArgs).DontLog().RunAndProcessLines(func(line string) (bool, error) {
|
err := self.cmd.New(cmdArgs).DontLog().RunAndProcessLines(func(line string) (bool, error) {
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
split := strings.SplitN(line, "/", 2)
|
split := strings.SplitN(line, "/", 4)
|
||||||
if len(split) != 2 {
|
if len(split) != 4 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
remoteName := split[2]
|
||||||
|
name := split[3]
|
||||||
|
|
||||||
|
if name == "HEAD" {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
remoteName := split[0]
|
|
||||||
name := split[1]
|
|
||||||
|
|
||||||
_, ok := remoteBranchesByRemoteName[remoteName]
|
_, ok := remoteBranchesByRemoteName[remoteName]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -361,7 +361,7 @@ func (self *BasicCommitsController) newBranch(commit *models.Commit) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *BasicCommitsController) createResetMenu(commit *models.Commit) error {
|
func (self *BasicCommitsController) createResetMenu(commit *models.Commit) error {
|
||||||
return self.c.Helpers().Refs.CreateGitResetMenu(commit.Hash())
|
return self.c.Helpers().Refs.CreateGitResetMenu(commit.Hash(), commit.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BasicCommitsController) checkout(commit *models.Commit) error {
|
func (self *BasicCommitsController) checkout(commit *models.Commit) error {
|
||||||
|
@ -326,7 +326,8 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||||||
LabelColumns: []string{upstreamResetOptions},
|
LabelColumns: []string{upstreamResetOptions},
|
||||||
OpensMenu: true,
|
OpensMenu: true,
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
err := self.c.Helpers().Refs.CreateGitResetMenu(upstream)
|
// We only can invoke this when the remote branch is stored locally, so using the selectedBranch here is fine.
|
||||||
|
err := self.c.Helpers().Refs.CreateGitResetMenu(upstream, selectedBranch.FullUpstreamRefName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -686,7 +687,7 @@ func (self *BranchesController) createSortMenu() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error {
|
func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error {
|
||||||
return self.c.Helpers().Refs.CreateGitResetMenu(selectedBranch.Name)
|
return self.c.Helpers().Refs.CreateGitResetMenu(selectedBranch.Name, selectedBranch.FullRefName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchesController) rename(branch *models.Branch) error {
|
func (self *BranchesController) rename(branch *models.Branch) error {
|
||||||
|
@ -1144,7 +1144,7 @@ func (self *FilesController) stash() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilesController) createResetToUpstreamMenu() error {
|
func (self *FilesController) createResetToUpstreamMenu() error {
|
||||||
return self.c.Helpers().Refs.CreateGitResetMenu("@{upstream}")
|
return self.c.Helpers().Refs.CreateGitResetMenu("@{upstream}", "@{upstream}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilesController) handleToggleDirCollapsed() error {
|
func (self *FilesController) handleToggleDirCollapsed() error {
|
||||||
|
@ -231,7 +231,7 @@ func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, onSelecte
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RefsHelper) CreateGitResetMenu(ref string) error {
|
func (self *RefsHelper) CreateGitResetMenu(name string, ref string) error {
|
||||||
type strengthWithKey struct {
|
type strengthWithKey struct {
|
||||||
strength string
|
strength string
|
||||||
label string
|
label string
|
||||||
@ -249,7 +249,7 @@ func (self *RefsHelper) CreateGitResetMenu(ref string) error {
|
|||||||
return &types.MenuItem{
|
return &types.MenuItem{
|
||||||
LabelColumns: []string{
|
LabelColumns: []string{
|
||||||
row.label,
|
row.label,
|
||||||
style.FgRed.Sprintf("reset --%s %s", row.strength, ref),
|
style.FgRed.Sprintf("reset --%s %s", row.strength, name),
|
||||||
},
|
},
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
self.c.LogAction("Reset")
|
self.c.LogAction("Reset")
|
||||||
@ -261,7 +261,7 @@ func (self *RefsHelper) CreateGitResetMenu(ref string) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return self.c.Menu(types.CreateMenuOptions{
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
Title: fmt.Sprintf("%s %s", self.c.Tr.ResetTo, ref),
|
Title: fmt.Sprintf("%s %s", self.c.Tr.ResetTo, name),
|
||||||
Items: menuItems,
|
Items: menuItems,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ func (self *RemoteBranchesController) createSortMenu() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *RemoteBranchesController) createResetMenu(selectedBranch *models.RemoteBranch) error {
|
func (self *RemoteBranchesController) createResetMenu(selectedBranch *models.RemoteBranch) error {
|
||||||
return self.c.Helpers().Refs.CreateGitResetMenu(selectedBranch.FullName())
|
return self.c.Helpers().Refs.CreateGitResetMenu(selectedBranch.FullName(), selectedBranch.FullRefName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RemoteBranchesController) setAsUpstream(selectedBranch *models.RemoteBranch) error {
|
func (self *RemoteBranchesController) setAsUpstream(selectedBranch *models.RemoteBranch) error {
|
||||||
|
@ -302,7 +302,7 @@ func (self *TagsController) push(tag *models.Tag) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagsController) createResetMenu(tag *models.Tag) error {
|
func (self *TagsController) createResetMenu(tag *models.Tag) error {
|
||||||
return self.c.Helpers().Refs.CreateGitResetMenu(tag.Name)
|
return self.c.Helpers().Refs.CreateGitResetMenu(tag.Name, tag.FullRefName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagsController) create() error {
|
func (self *TagsController) create() error {
|
||||||
|
52
pkg/integration/tests/branch/reset_to_duplicate_named_tag.go
Normal file
52
pkg/integration/tests/branch/reset_to_duplicate_named_tag.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package branch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ResetToDuplicateNamedTag = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Hard reset to a branch when a tag shares the same name",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.NewBranch("current-branch")
|
||||||
|
|
||||||
|
shell.EmptyCommit("other-branch-tag commit")
|
||||||
|
shell.CreateLightweightTag("other-branch", "HEAD")
|
||||||
|
|
||||||
|
shell.EmptyCommit("other-branch commit")
|
||||||
|
shell.NewBranch("other-branch")
|
||||||
|
|
||||||
|
shell.Checkout("current-branch")
|
||||||
|
shell.EmptyCommit("current-branch commit")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().Lines(
|
||||||
|
Contains("current-branch commit"),
|
||||||
|
Contains("other-branch commit"),
|
||||||
|
Contains("other-branch-tag commit"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Branches().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains("current-branch").IsSelected(),
|
||||||
|
Contains("other-branch"),
|
||||||
|
).
|
||||||
|
SelectNextItem().
|
||||||
|
Press(keys.Commits.ViewResetOptions)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Contains("Reset to other-branch")).
|
||||||
|
Select(Contains("Hard reset")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
Lines(
|
||||||
|
Contains("other-branch commit"),
|
||||||
|
Contains("other-branch-tag commit"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -0,0 +1,57 @@
|
|||||||
|
package branch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ResetToDuplicateNamedUpstream = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Hard reset the current branch to an upstream branch when there is a competing tag name",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.
|
||||||
|
CloneIntoRemote("origin").
|
||||||
|
NewBranch("foo").
|
||||||
|
EmptyCommit("commit 1").
|
||||||
|
PushBranchAndSetUpstream("origin", "foo").
|
||||||
|
EmptyCommit("commit 2").
|
||||||
|
CreateLightweightTag("origin/foo", "HEAD")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().Lines(
|
||||||
|
Contains("commit 2"),
|
||||||
|
Contains("commit 1"),
|
||||||
|
)
|
||||||
|
t.Views().Tags().Focus().Lines(Contains("origin/foo"))
|
||||||
|
|
||||||
|
t.Views().Remotes().Focus().
|
||||||
|
Lines(Contains("origin")).
|
||||||
|
PressEnter()
|
||||||
|
t.Views().RemoteBranches().IsFocused().
|
||||||
|
Lines(Contains("foo")).
|
||||||
|
Press(keys.Commits.ViewResetOptions)
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Contains("Reset to origin/foo")).
|
||||||
|
Select(Contains("Hard reset")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().Lines(
|
||||||
|
Contains("commit 1"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Tags().Focus().
|
||||||
|
Lines(Contains("origin/foo")).
|
||||||
|
Press(keys.Commits.ViewResetOptions)
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Contains("Reset to origin/foo")).
|
||||||
|
Select(Contains("Hard reset")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().Lines(
|
||||||
|
Contains("commit 2"),
|
||||||
|
Contains("commit 1"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
48
pkg/integration/tests/tag/reset_to_duplicate_named_branch.go
Normal file
48
pkg/integration/tests/tag/reset_to_duplicate_named_branch.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package tag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ResetToDuplicateNamedBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Hard reset to a tag when a branch shares the same name",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.NewBranch("current-branch")
|
||||||
|
|
||||||
|
shell.EmptyCommit("other-branch-tag commit")
|
||||||
|
shell.CreateLightweightTag("other-branch", "HEAD")
|
||||||
|
|
||||||
|
shell.EmptyCommit("other-branch commit")
|
||||||
|
shell.NewBranch("other-branch")
|
||||||
|
|
||||||
|
shell.Checkout("current-branch")
|
||||||
|
shell.EmptyCommit("current-branch commit")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().Lines(
|
||||||
|
Contains("current-branch commit"),
|
||||||
|
Contains("other-branch commit"),
|
||||||
|
Contains("other-branch-tag commit"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Tags().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains("other-branch").IsSelected(),
|
||||||
|
).
|
||||||
|
Press(keys.Commits.ViewResetOptions)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Contains("Reset to other-branch")).
|
||||||
|
Select(Contains("Hard reset")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().Lines(
|
||||||
|
Contains("other-branch-tag commit"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -71,6 +71,8 @@ var tests = []*components.IntegrationTest{
|
|||||||
branch.RebaseToUpstream,
|
branch.RebaseToUpstream,
|
||||||
branch.Rename,
|
branch.Rename,
|
||||||
branch.Reset,
|
branch.Reset,
|
||||||
|
branch.ResetToDuplicateNamedTag,
|
||||||
|
branch.ResetToDuplicateNamedUpstream,
|
||||||
branch.ResetToUpstream,
|
branch.ResetToUpstream,
|
||||||
branch.SelectCommitsOfCurrentBranch,
|
branch.SelectCommitsOfCurrentBranch,
|
||||||
branch.SetUpstream,
|
branch.SetUpstream,
|
||||||
@ -406,6 +408,7 @@ var tests = []*components.IntegrationTest{
|
|||||||
tag.ForceTagAnnotated,
|
tag.ForceTagAnnotated,
|
||||||
tag.ForceTagLightweight,
|
tag.ForceTagLightweight,
|
||||||
tag.Reset,
|
tag.Reset,
|
||||||
|
tag.ResetToDuplicateNamedBranch,
|
||||||
ui.Accordion,
|
ui.Accordion,
|
||||||
ui.DisableSwitchTabWithPanelJumpKeys,
|
ui.DisableSwitchTabWithPanelJumpKeys,
|
||||||
ui.EmptyMenu,
|
ui.EmptyMenu,
|
||||||
|
Reference in New Issue
Block a user