mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-10 20:05:50 +02:00
Continue/abort a conflicted cherry-pick or revert (#4441)
- **PR Description** This is part one of a four part series of PRs that improve the cherry-pick and revert experience. With this first PR we make it possible to continue or abort a cherry-pick or revert operation, in the same way you can continue or abort a rebase or merge. Currently this is only relevant for revert, because lazygit doesn't use git cherry-pick for copying/pasting commits. This will change in a later PR in this series though, so here we are already preparing for that. Fixes #1807
This commit is contained in:
commit
3dc045b69c
48 changed files with 421 additions and 255 deletions
|
@ -136,7 +136,7 @@ func NewGitCommandAux(
|
||||||
|
|
||||||
branchLoader := git_commands.NewBranchLoader(cmn, gitCommon, cmd, branchCommands.CurrentBranchInfo, configCommands)
|
branchLoader := git_commands.NewBranchLoader(cmn, gitCommon, cmd, branchCommands.CurrentBranchInfo, configCommands)
|
||||||
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
|
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
|
||||||
commitLoader := git_commands.NewCommitLoader(cmn, cmd, statusCommands.RebaseMode, gitCommon)
|
commitLoader := git_commands.NewCommitLoader(cmn, cmd, statusCommands.WorkingTreeState, gitCommon)
|
||||||
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
||||||
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd, repo.Remotes)
|
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd, repo.Remotes)
|
||||||
worktreeLoader := git_commands.NewWorktreeLoader(gitCommon)
|
worktreeLoader := git_commands.NewWorktreeLoader(gitCommon)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
@ -31,10 +30,10 @@ type CommitLoader struct {
|
||||||
*common.Common
|
*common.Common
|
||||||
cmd oscommands.ICmdObjBuilder
|
cmd oscommands.ICmdObjBuilder
|
||||||
|
|
||||||
getRebaseMode func() (enums.RebaseMode, error)
|
getWorkingTreeState func() models.WorkingTreeState
|
||||||
readFile func(filename string) ([]byte, error)
|
readFile func(filename string) ([]byte, error)
|
||||||
walkFiles func(root string, fn filepath.WalkFunc) error
|
walkFiles func(root string, fn filepath.WalkFunc) error
|
||||||
dotGitDir string
|
dotGitDir string
|
||||||
*GitCommon
|
*GitCommon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,16 +41,16 @@ type CommitLoader struct {
|
||||||
func NewCommitLoader(
|
func NewCommitLoader(
|
||||||
cmn *common.Common,
|
cmn *common.Common,
|
||||||
cmd oscommands.ICmdObjBuilder,
|
cmd oscommands.ICmdObjBuilder,
|
||||||
getRebaseMode func() (enums.RebaseMode, error),
|
getWorkingTreeState func() models.WorkingTreeState,
|
||||||
gitCommon *GitCommon,
|
gitCommon *GitCommon,
|
||||||
) *CommitLoader {
|
) *CommitLoader {
|
||||||
return &CommitLoader{
|
return &CommitLoader{
|
||||||
Common: cmn,
|
Common: cmn,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
getRebaseMode: getRebaseMode,
|
getWorkingTreeState: getWorkingTreeState,
|
||||||
readFile: os.ReadFile,
|
readFile: os.ReadFile,
|
||||||
walkFiles: filepath.Walk,
|
walkFiles: filepath.Walk,
|
||||||
GitCommon: gitCommon,
|
GitCommon: gitCommon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,17 +171,12 @@ func (self *CommitLoader) MergeRebasingCommits(commits []*models.Commit) ([]*mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rebaseMode, err := self.getRebaseMode()
|
if !self.getWorkingTreeState().Rebasing {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rebaseMode == enums.REBASE_MODE_NONE {
|
|
||||||
// not in rebase mode so return original commits
|
// not in rebase mode so return original commits
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rebasingCommits, err := self.getHydratedRebasingCommits(rebaseMode)
|
rebasingCommits, err := self.getHydratedRebasingCommits()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -248,8 +242,8 @@ func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode) ([]*models.Commit, error) {
|
func (self *CommitLoader) getHydratedRebasingCommits() ([]*models.Commit, error) {
|
||||||
commits := self.getRebasingCommits(rebaseMode)
|
commits := self.getRebasingCommits()
|
||||||
|
|
||||||
if len(commits) == 0 {
|
if len(commits) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -310,11 +304,7 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
|
||||||
// git-rebase-todo example:
|
// git-rebase-todo example:
|
||||||
// pick ac446ae94ee560bdb8d1d057278657b251aaef17 ac446ae
|
// pick ac446ae94ee560bdb8d1d057278657b251aaef17 ac446ae
|
||||||
// pick afb893148791a2fbd8091aeb81deba4930c73031 afb8931
|
// pick afb893148791a2fbd8091aeb81deba4930c73031 afb8931
|
||||||
func (self *CommitLoader) getRebasingCommits(rebaseMode enums.RebaseMode) []*models.Commit {
|
func (self *CommitLoader) getRebasingCommits() []*models.Commit {
|
||||||
if rebaseMode != enums.REBASE_MODE_INTERACTIVE {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"))
|
bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Error(fmt.Sprintf("error occurred reading git-rebase-todo: %s", err.Error()))
|
self.Log.Error(fmt.Sprintf("error occurred reading git-rebase-todo: %s", err.Error()))
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/stefanhaller/git-todo-parser/todo"
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
|
@ -33,17 +32,15 @@ func TestGetCommits(t *testing.T) {
|
||||||
expectedCommits []*models.Commit
|
expectedCommits []*models.Commit
|
||||||
expectedError error
|
expectedError error
|
||||||
logOrder string
|
logOrder string
|
||||||
rebaseMode enums.RebaseMode
|
|
||||||
opts GetCommitsOptions
|
opts GetCommitsOptions
|
||||||
mainBranches []string
|
mainBranches []string
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "should return no commits if there are none",
|
testName: "should return no commits if there are none",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
||||||
|
@ -52,10 +49,9 @@ func TestGetCommits(t *testing.T) {
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "should use proper upstream name for branch",
|
testName: "should use proper upstream name for branch",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", RefForPushedStatus: "refs/heads/mybranch", IncludeRebaseCommits: false},
|
||||||
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", RefForPushedStatus: "refs/heads/mybranch", IncludeRebaseCommits: false},
|
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "refs/heads/mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "refs/heads/mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
||||||
|
@ -66,7 +62,6 @@ func TestGetCommits(t *testing.T) {
|
||||||
{
|
{
|
||||||
testName: "should return commits if they are present",
|
testName: "should return commits if they are present",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
mainBranches: []string{"master", "main", "develop"},
|
mainBranches: []string{"master", "main", "develop"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
@ -203,7 +198,6 @@ func TestGetCommits(t *testing.T) {
|
||||||
{
|
{
|
||||||
testName: "should not call merge-base for mainBranches if none exist",
|
testName: "should not call merge-base for mainBranches if none exist",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
mainBranches: []string{"master", "main"},
|
mainBranches: []string{"master", "main"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
@ -240,7 +234,6 @@ func TestGetCommits(t *testing.T) {
|
||||||
{
|
{
|
||||||
testName: "should call merge-base for all main branches that exist",
|
testName: "should call merge-base for all main branches that exist",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
mainBranches: []string{"master", "main", "develop", "1.0-hotfixes"},
|
mainBranches: []string{"master", "main", "develop", "1.0-hotfixes"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
@ -277,10 +270,9 @@ func TestGetCommits(t *testing.T) {
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "should not specify order if `log.order` is `default`",
|
testName: "should not specify order if `log.order` is `default`",
|
||||||
logOrder: "default",
|
logOrder: "default",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
||||||
|
@ -289,10 +281,9 @@ func TestGetCommits(t *testing.T) {
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "should set filter path",
|
testName: "should set filter path",
|
||||||
logOrder: "default",
|
logOrder: "default",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", FilterPath: "src"},
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", FilterPath: "src"},
|
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
|
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
|
||||||
|
@ -310,10 +301,10 @@ func TestGetCommits(t *testing.T) {
|
||||||
cmd := oscommands.NewDummyCmdObjBuilder(scenario.runner)
|
cmd := oscommands.NewDummyCmdObjBuilder(scenario.runner)
|
||||||
|
|
||||||
builder := &CommitLoader{
|
builder := &CommitLoader{
|
||||||
Common: common,
|
Common: common,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
getRebaseMode: func() (enums.RebaseMode, error) { return scenario.rebaseMode, nil },
|
getWorkingTreeState: func() models.WorkingTreeState { return models.WorkingTreeState{} },
|
||||||
dotGitDir: ".git",
|
dotGitDir: ".git",
|
||||||
readFile: func(filename string) ([]byte, error) {
|
readFile: func(filename string) ([]byte, error) {
|
||||||
return []byte(""), nil
|
return []byte(""), nil
|
||||||
},
|
},
|
||||||
|
@ -493,10 +484,10 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
||||||
common := utils.NewDummyCommon()
|
common := utils.NewDummyCommon()
|
||||||
|
|
||||||
builder := &CommitLoader{
|
builder := &CommitLoader{
|
||||||
Common: common,
|
Common: common,
|
||||||
cmd: oscommands.NewDummyCmdObjBuilder(oscommands.NewFakeRunner(t)),
|
cmd: oscommands.NewDummyCmdObjBuilder(oscommands.NewFakeRunner(t)),
|
||||||
getRebaseMode: func() (enums.RebaseMode, error) { return enums.REBASE_MODE_INTERACTIVE, nil },
|
getWorkingTreeState: func() models.WorkingTreeState { return models.WorkingTreeState{Rebasing: true} },
|
||||||
dotGitDir: ".git",
|
dotGitDir: ".git",
|
||||||
readFile: func(filename string) ([]byte, error) {
|
readFile: func(filename string) ([]byte, error) {
|
||||||
return []byte(""), nil
|
return []byte(""), nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/jesseduffield/lazygit/pkg/app/daemon"
|
"github.com/jesseduffield/lazygit/pkg/app/daemon"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/stefanhaller/git-todo-parser/todo"
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -229,7 +228,7 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := self.ApplyCustomPatch(true, true); err != nil {
|
if err := self.ApplyCustomPatch(true, true); err != nil {
|
||||||
if self.status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
if self.status.WorkingTreeState().Rebasing {
|
||||||
_ = self.rebase.AbortRebase()
|
_ = self.rebase.AbortRebase()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -253,7 +252,7 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
|
||||||
self.rebase.onSuccessfulContinue = func() error {
|
self.rebase.onSuccessfulContinue = func() error {
|
||||||
// add patches to index
|
// add patches to index
|
||||||
if err := self.ApplyPatch(patch, ApplyPatchOpts{Index: true, ThreeWay: true}); err != nil {
|
if err := self.ApplyPatch(patch, ApplyPatchOpts{Index: true, ThreeWay: true}); err != nil {
|
||||||
if self.status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
if self.status.WorkingTreeState().Rebasing {
|
||||||
_ = self.rebase.AbortRebase()
|
_ = self.rebase.AbortRebase()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatusCommands struct {
|
type StatusCommands struct {
|
||||||
|
@ -20,50 +20,68 @@ func NewStatusCommands(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
|
func (self *StatusCommands) WorkingTreeState() models.WorkingTreeState {
|
||||||
// and "interactive" for interactive rebase
|
result := models.WorkingTreeState{}
|
||||||
func (self *StatusCommands) RebaseMode() (enums.RebaseMode, error) {
|
result.Rebasing, _ = self.IsInRebase()
|
||||||
ok, err := self.IsInNormalRebase()
|
result.Merging, _ = self.IsInMergeState()
|
||||||
if err == nil && ok {
|
result.CherryPicking, _ = self.IsInCherryPick()
|
||||||
return enums.REBASE_MODE_NORMAL, nil
|
result.Reverting, _ = self.IsInRevert()
|
||||||
}
|
return result
|
||||||
ok, err = self.IsInInteractiveRebase()
|
|
||||||
if err == nil && ok {
|
|
||||||
return enums.REBASE_MODE_INTERACTIVE, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return enums.REBASE_MODE_NONE, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StatusCommands) WorkingTreeState() enums.RebaseMode {
|
|
||||||
rebaseMode, _ := self.RebaseMode()
|
|
||||||
if rebaseMode != enums.REBASE_MODE_NONE {
|
|
||||||
return enums.REBASE_MODE_REBASING
|
|
||||||
}
|
|
||||||
merging, _ := self.IsInMergeState()
|
|
||||||
if merging {
|
|
||||||
return enums.REBASE_MODE_MERGING
|
|
||||||
}
|
|
||||||
return enums.REBASE_MODE_NONE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusCommands) IsBareRepo() bool {
|
func (self *StatusCommands) IsBareRepo() bool {
|
||||||
return self.repoPaths.isBareRepo
|
return self.repoPaths.isBareRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusCommands) IsInNormalRebase() (bool, error) {
|
func (self *StatusCommands) IsInRebase() (bool, error) {
|
||||||
|
exists, err := self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge"))
|
||||||
|
if err == nil && exists {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-apply"))
|
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-apply"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusCommands) IsInInteractiveRebase() (bool, error) {
|
|
||||||
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsInMergeState states whether we are still mid-merge
|
// IsInMergeState states whether we are still mid-merge
|
||||||
func (self *StatusCommands) IsInMergeState() (bool, error) {
|
func (self *StatusCommands) IsInMergeState() (bool, error) {
|
||||||
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "MERGE_HEAD"))
|
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "MERGE_HEAD"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *StatusCommands) IsInCherryPick() (bool, error) {
|
||||||
|
exists, err := self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "CHERRY_PICK_HEAD"))
|
||||||
|
if err != nil || !exists {
|
||||||
|
return exists, err
|
||||||
|
}
|
||||||
|
// Sometimes, CHERRY_PICK_HEAD is present during rebases even if no
|
||||||
|
// cherry-pick is in progress. I suppose this is because rebase used to be
|
||||||
|
// implemented as a series of cherry-picks, so this could be remnants of
|
||||||
|
// code that is shared between cherry-pick and rebase, or something. The way
|
||||||
|
// to tell if this is the case is to check for the presence of the
|
||||||
|
// stopped-sha file, which records the sha of the last pick that was
|
||||||
|
// executed before the rebase stopped, and seeing if the sha in that file is
|
||||||
|
// the same as the one in CHERRY_PICK_HEAD.
|
||||||
|
cherryPickHead, err := os.ReadFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "CHERRY_PICK_HEAD"))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
stoppedSha, err := os.ReadFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge", "stopped-sha"))
|
||||||
|
if err != nil {
|
||||||
|
// If we get an error we assume the file doesn't exist
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
cherryPickHeadStr := strings.TrimSpace(string(cherryPickHead))
|
||||||
|
stoppedShaStr := strings.TrimSpace(string(stoppedSha))
|
||||||
|
// Need to use HasPrefix here because the cherry-pick HEAD is a full sha1,
|
||||||
|
// but stopped-sha is an abbreviated sha1
|
||||||
|
if strings.HasPrefix(cherryPickHeadStr, stoppedShaStr) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *StatusCommands) IsInRevert() (bool, error) {
|
||||||
|
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "REVERT_HEAD"))
|
||||||
|
}
|
||||||
|
|
||||||
// Full ref (e.g. "refs/heads/mybranch") of the branch that is currently
|
// Full ref (e.g. "refs/heads/mybranch") of the branch that is currently
|
||||||
// being rebased, or empty string when we're not in a rebase
|
// being rebased, or empty string when we're not in a rebase
|
||||||
func (self *StatusCommands) BranchBeingRebased() string {
|
func (self *StatusCommands) BranchBeingRebased() string {
|
||||||
|
|
112
pkg/commands/models/working_tree_state.go
Normal file
112
pkg/commands/models/working_tree_state.go
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import "github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
|
|
||||||
|
// The state of the working tree. Several of these can be true at once.
|
||||||
|
// In particular, the concrete multi-state combinations that can occur in
|
||||||
|
// practice are Rebasing+CherryPicking, and Rebasing+Reverting. Theoretically, I
|
||||||
|
// guess Rebasing+Merging could also happen, but it probably won't in practice.
|
||||||
|
type WorkingTreeState struct {
|
||||||
|
Rebasing bool
|
||||||
|
Merging bool
|
||||||
|
CherryPicking bool
|
||||||
|
Reverting bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) Any() bool {
|
||||||
|
return self.Rebasing || self.Merging || self.CherryPicking || self.Reverting
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) None() bool {
|
||||||
|
return !self.Any()
|
||||||
|
}
|
||||||
|
|
||||||
|
type EffectiveWorkingTreeState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// this means we're neither rebasing nor merging, cherry-picking, or reverting
|
||||||
|
WORKING_TREE_STATE_NONE EffectiveWorkingTreeState = iota
|
||||||
|
WORKING_TREE_STATE_REBASING
|
||||||
|
WORKING_TREE_STATE_MERGING
|
||||||
|
WORKING_TREE_STATE_CHERRY_PICKING
|
||||||
|
WORKING_TREE_STATE_REVERTING
|
||||||
|
)
|
||||||
|
|
||||||
|
// Effective returns the "current" state; if several states are true at once,
|
||||||
|
// this is the one that should be displayed in status views, and it's the one
|
||||||
|
// that the user can continue or abort.
|
||||||
|
//
|
||||||
|
// As an example, if you are stopped in an interactive rebase, and then you
|
||||||
|
// perform a cherry-pick, and the cherry-pick conflicts, then both
|
||||||
|
// WorkingTreeState.Rebasing and WorkingTreeState.CherryPicking are true.
|
||||||
|
// The effective state is cherry-picking, because that's the one you can
|
||||||
|
// continue or abort. It is not possible to continue the rebase without first
|
||||||
|
// aborting the cherry-pick.
|
||||||
|
func (self WorkingTreeState) Effective() EffectiveWorkingTreeState {
|
||||||
|
if self.Reverting {
|
||||||
|
return WORKING_TREE_STATE_REVERTING
|
||||||
|
}
|
||||||
|
if self.CherryPicking {
|
||||||
|
return WORKING_TREE_STATE_CHERRY_PICKING
|
||||||
|
}
|
||||||
|
if self.Merging {
|
||||||
|
return WORKING_TREE_STATE_MERGING
|
||||||
|
}
|
||||||
|
if self.Rebasing {
|
||||||
|
return WORKING_TREE_STATE_REBASING
|
||||||
|
}
|
||||||
|
return WORKING_TREE_STATE_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) Title(tr *i18n.TranslationSet) string {
|
||||||
|
return map[EffectiveWorkingTreeState]string{
|
||||||
|
WORKING_TREE_STATE_REBASING: tr.RebasingStatus,
|
||||||
|
WORKING_TREE_STATE_MERGING: tr.MergingStatus,
|
||||||
|
WORKING_TREE_STATE_CHERRY_PICKING: tr.CherryPickingStatus,
|
||||||
|
WORKING_TREE_STATE_REVERTING: tr.RevertingStatus,
|
||||||
|
}[self.Effective()]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) LowerCaseTitle(tr *i18n.TranslationSet) string {
|
||||||
|
return map[EffectiveWorkingTreeState]string{
|
||||||
|
WORKING_TREE_STATE_REBASING: tr.LowercaseRebasingStatus,
|
||||||
|
WORKING_TREE_STATE_MERGING: tr.LowercaseMergingStatus,
|
||||||
|
WORKING_TREE_STATE_CHERRY_PICKING: tr.LowercaseCherryPickingStatus,
|
||||||
|
WORKING_TREE_STATE_REVERTING: tr.LowercaseRevertingStatus,
|
||||||
|
}[self.Effective()]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) OptionsMenuTitle(tr *i18n.TranslationSet) string {
|
||||||
|
return map[EffectiveWorkingTreeState]string{
|
||||||
|
WORKING_TREE_STATE_REBASING: tr.RebaseOptionsTitle,
|
||||||
|
WORKING_TREE_STATE_MERGING: tr.MergeOptionsTitle,
|
||||||
|
WORKING_TREE_STATE_CHERRY_PICKING: tr.CherryPickOptionsTitle,
|
||||||
|
WORKING_TREE_STATE_REVERTING: tr.RevertOptionsTitle,
|
||||||
|
}[self.Effective()]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) OptionsMapTitle(tr *i18n.TranslationSet) string {
|
||||||
|
return map[EffectiveWorkingTreeState]string{
|
||||||
|
WORKING_TREE_STATE_REBASING: tr.ViewRebaseOptions,
|
||||||
|
WORKING_TREE_STATE_MERGING: tr.ViewMergeOptions,
|
||||||
|
WORKING_TREE_STATE_CHERRY_PICKING: tr.ViewCherryPickOptions,
|
||||||
|
WORKING_TREE_STATE_REVERTING: tr.ViewRevertOptions,
|
||||||
|
}[self.Effective()]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) CommandName() string {
|
||||||
|
return map[EffectiveWorkingTreeState]string{
|
||||||
|
WORKING_TREE_STATE_REBASING: "rebase",
|
||||||
|
WORKING_TREE_STATE_MERGING: "merge",
|
||||||
|
WORKING_TREE_STATE_CHERRY_PICKING: "cherry-pick",
|
||||||
|
WORKING_TREE_STATE_REVERTING: "revert",
|
||||||
|
}[self.Effective()]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) CanShowTodos() bool {
|
||||||
|
return self.Rebasing || self.CherryPicking || self.Reverting
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self WorkingTreeState) CanSkip() bool {
|
||||||
|
return self.Rebasing || self.CherryPicking || self.Reverting
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
package enums
|
|
||||||
|
|
||||||
type RebaseMode int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// this means we're neither rebasing nor merging
|
|
||||||
REBASE_MODE_NONE RebaseMode = iota
|
|
||||||
// this means normal rebase as opposed to interactive rebase
|
|
||||||
REBASE_MODE_NORMAL
|
|
||||||
REBASE_MODE_INTERACTIVE
|
|
||||||
// REBASE_MODE_REBASING is a general state that captures both REBASE_MODE_NORMAL and REBASE_MODE_INTERACTIVE
|
|
||||||
REBASE_MODE_REBASING
|
|
||||||
REBASE_MODE_MERGING
|
|
||||||
)
|
|
||||||
|
|
||||||
func (self RebaseMode) IsMerging() bool {
|
|
||||||
return self == REBASE_MODE_MERGING
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self RebaseMode) IsRebasing() bool {
|
|
||||||
return self == REBASE_MODE_INTERACTIVE || self == REBASE_MODE_NORMAL || self == REBASE_MODE_REBASING
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
@ -41,7 +40,7 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showYouAreHereLabel := c.Model().WorkingTreeStateAtLastCommitRefresh == enums.REBASE_MODE_REBASING
|
showYouAreHereLabel := c.Model().WorkingTreeStateAtLastCommitRefresh.CanShowTodos()
|
||||||
hasRebaseUpdateRefsConfig := c.Git().Config.GetRebaseUpdateRefs()
|
hasRebaseUpdateRefsConfig := c.Git().Config.GetRebaseUpdateRefs()
|
||||||
|
|
||||||
return presentation.GetCommitListDisplayStrings(
|
return presentation.GetCommitListDisplayStrings(
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
)
|
)
|
||||||
|
@ -44,7 +43,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Git().Patch.PatchBuilder.CanRebase && self.c.Git().Status.WorkingTreeState() == enums.REBASE_MODE_NONE {
|
if self.c.Git().Patch.PatchBuilder.CanRebase && self.c.Git().Status.WorkingTreeState().None() {
|
||||||
menuItems = append(menuItems, []*types.MenuItem{
|
menuItems = append(menuItems, []*types.MenuItem{
|
||||||
{
|
{
|
||||||
Label: fmt.Sprintf(self.c.Tr.RemovePatchFromOriginalCommit, self.c.Git().Patch.PatchBuilder.To),
|
Label: fmt.Sprintf(self.c.Tr.RemovePatchFromOriginalCommit, self.c.Git().Patch.PatchBuilder.To),
|
||||||
|
@ -115,7 +114,7 @@ func (self *CustomPatchOptionsMenuAction) getPatchCommitIndex() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CustomPatchOptionsMenuAction) validateNormalWorkingTreeState() (bool, error) {
|
func (self *CustomPatchOptionsMenuAction) validateNormalWorkingTreeState() (bool, error) {
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
if self.c.Git().Status.WorkingTreeState().Any() {
|
||||||
return false, errors.New(self.c.Tr.CantPatchWhileRebasingError)
|
return false, errors.New(self.c.Tr.CantPatchWhileRebasingError)
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|
|
@ -35,11 +35,12 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type
|
||||||
OpensMenu: true,
|
OpensMenu: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.CreateRebaseOptionsMenu),
|
Key: opts.GetKey(opts.Config.Universal.CreateRebaseOptionsMenu),
|
||||||
Handler: opts.Guards.NoPopupPanel(self.c.Helpers().MergeAndRebase.CreateRebaseOptionsMenu),
|
Handler: opts.Guards.NoPopupPanel(self.c.Helpers().MergeAndRebase.CreateRebaseOptionsMenu),
|
||||||
Description: self.c.Tr.ViewMergeRebaseOptions,
|
Description: self.c.Tr.ViewMergeRebaseOptions,
|
||||||
Tooltip: self.c.Tr.ViewMergeRebaseOptionsTooltip,
|
Tooltip: self.c.Tr.ViewMergeRebaseOptionsTooltip,
|
||||||
OpensMenu: true,
|
OpensMenu: true,
|
||||||
|
GetDisabledReason: self.canShowRebaseOptions,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.Refresh),
|
Key: opts.GetKey(opts.Config.Universal.Refresh),
|
||||||
|
@ -191,3 +192,12 @@ func (self *GlobalController) escape() error {
|
||||||
func (self *GlobalController) toggleWhitespace() error {
|
func (self *GlobalController) toggleWhitespace() error {
|
||||||
return (&ToggleWhitespaceAction{c: self.c}).Call()
|
return (&ToggleWhitespaceAction{c: self.c}).Call()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *GlobalController) canShowRebaseOptions() *types.DisabledReason {
|
||||||
|
if self.c.Model().WorkingTreeStateAtLastCommitRefresh.None() {
|
||||||
|
return &types.DisabledReason{
|
||||||
|
Text: self.c.Tr.NotMergingOrRebasing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (self *CherryPickHelper) Paste() error {
|
||||||
"numCommits": strconv.Itoa(len(self.getData().CherryPickedCommits)),
|
"numCommits": strconv.Itoa(len(self.getData().CherryPickedCommits)),
|
||||||
}),
|
}),
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
isInRebase, err := self.c.Git().Status.IsInInteractiveRebase()
|
isInRebase, err := self.c.Git().Status.IsInRebase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func (self *CherryPickHelper) Paste() error {
|
||||||
// be because there were conflicts. Don't clear the copied
|
// be because there were conflicts. Don't clear the copied
|
||||||
// commits in this case, since we might want to abort and
|
// commits in this case, since we might want to abort and
|
||||||
// try pasting them again.
|
// try pasting them again.
|
||||||
isInRebase, err = self.c.Git().Status.IsInInteractiveRebase()
|
isInRebase, err = self.c.Git().Status.IsInRebase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
@ -51,7 +50,7 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
|
||||||
{option: REBASE_OPTION_ABORT, key: 'a'},
|
{option: REBASE_OPTION_ABORT, key: 'a'},
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
if self.c.Git().Status.WorkingTreeState().CanSkip() {
|
||||||
options = append(options, optionAndKey{
|
options = append(options, optionAndKey{
|
||||||
option: REBASE_OPTION_SKIP, key: 's',
|
option: REBASE_OPTION_SKIP, key: 's',
|
||||||
})
|
})
|
||||||
|
@ -67,13 +66,7 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
var title string
|
title := self.c.Git().Status.WorkingTreeState().OptionsMenuTitle(self.c.Tr)
|
||||||
if self.c.Git().Status.WorkingTreeState() == enums.REBASE_MODE_MERGING {
|
|
||||||
title = self.c.Tr.MergeOptionsTitle
|
|
||||||
} else {
|
|
||||||
title = self.c.Tr.RebaseOptionsTitle
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
|
return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,12 +77,13 @@ func (self *MergeAndRebaseHelper) ContinueRebase() error {
|
||||||
func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
|
func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
|
||||||
status := self.c.Git().Status.WorkingTreeState()
|
status := self.c.Git().Status.WorkingTreeState()
|
||||||
|
|
||||||
if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING {
|
if status.None() {
|
||||||
return errors.New(self.c.Tr.NotMergingOrRebasing)
|
return errors.New(self.c.Tr.NotMergingOrRebasing)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
|
self.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
|
||||||
if status == enums.REBASE_MODE_REBASING {
|
effectiveStatus := status.Effective()
|
||||||
|
if effectiveStatus == models.WORKING_TREE_STATE_REBASING {
|
||||||
todoFile, err := os.ReadFile(
|
todoFile, err := os.ReadFile(
|
||||||
filepath.Join(self.c.Git().RepoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
filepath.Join(self.c.Git().RepoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
||||||
)
|
)
|
||||||
|
@ -103,23 +97,15 @@ func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commandType := ""
|
commandType := status.CommandName()
|
||||||
switch status {
|
|
||||||
case enums.REBASE_MODE_MERGING:
|
|
||||||
commandType = "merge"
|
|
||||||
case enums.REBASE_MODE_REBASING:
|
|
||||||
commandType = "rebase"
|
|
||||||
default:
|
|
||||||
// shouldn't be possible to land here
|
|
||||||
}
|
|
||||||
|
|
||||||
// we should end up with a command like 'git merge --continue'
|
// we should end up with a command like 'git merge --continue'
|
||||||
|
|
||||||
// it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge
|
// it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge
|
||||||
needsSubprocess := (status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && self.c.UserConfig().Git.Merging.ManualCommit) ||
|
needsSubprocess := (effectiveStatus == models.WORKING_TREE_STATE_MERGING && command != REBASE_OPTION_ABORT && self.c.UserConfig().Git.Merging.ManualCommit) ||
|
||||||
// but we'll also use a subprocess if we have exec todos; those are likely to be lengthy build
|
// but we'll also use a subprocess if we have exec todos; those are likely to be lengthy build
|
||||||
// tasks whose output the user will want to see in the terminal
|
// tasks whose output the user will want to see in the terminal
|
||||||
(status == enums.REBASE_MODE_REBASING && command != REBASE_OPTION_ABORT && self.hasExecTodos())
|
(effectiveStatus == models.WORKING_TREE_STATE_REBASING && command != REBASE_OPTION_ABORT && self.hasExecTodos())
|
||||||
|
|
||||||
if needsSubprocess {
|
if needsSubprocess {
|
||||||
// TODO: see if we should be calling more of the code from self.Git.Rebase.GenericMergeOrRebaseAction
|
// TODO: see if we should be calling more of the code from self.Git.Rebase.GenericMergeOrRebaseAction
|
||||||
|
@ -152,6 +138,8 @@ var conflictStrings = []string{
|
||||||
"fix conflicts",
|
"fix conflicts",
|
||||||
"Resolve all conflicts manually",
|
"Resolve all conflicts manually",
|
||||||
"Merge conflict in file",
|
"Merge conflict in file",
|
||||||
|
"hint: after resolving the conflicts",
|
||||||
|
"CONFLICT (content):",
|
||||||
}
|
}
|
||||||
|
|
||||||
func isMergeConflictErr(errStr string) bool {
|
func isMergeConflictErr(errStr string) bool {
|
||||||
|
@ -199,7 +187,7 @@ func (self *MergeAndRebaseHelper) CheckForConflicts(result error) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MergeAndRebaseHelper) PromptForConflictHandling() error {
|
func (self *MergeAndRebaseHelper) PromptForConflictHandling() error {
|
||||||
mode := self.workingTreeStateNoun()
|
mode := self.c.Git().Status.WorkingTreeState().CommandName()
|
||||||
return self.c.Menu(types.CreateMenuOptions{
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
Title: self.c.Tr.FoundConflictsTitle,
|
Title: self.c.Tr.FoundConflictsTitle,
|
||||||
Items: []*types.MenuItem{
|
Items: []*types.MenuItem{
|
||||||
|
@ -224,7 +212,7 @@ func (self *MergeAndRebaseHelper) PromptForConflictHandling() error {
|
||||||
|
|
||||||
func (self *MergeAndRebaseHelper) AbortMergeOrRebaseWithConfirm() error {
|
func (self *MergeAndRebaseHelper) AbortMergeOrRebaseWithConfirm() error {
|
||||||
// prompt user to confirm that they want to abort, then do it
|
// prompt user to confirm that they want to abort, then do it
|
||||||
mode := self.workingTreeStateNoun()
|
mode := self.c.Git().Status.WorkingTreeState().CommandName()
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: fmt.Sprintf(self.c.Tr.AbortTitle, mode),
|
Title: fmt.Sprintf(self.c.Tr.AbortTitle, mode),
|
||||||
Prompt: fmt.Sprintf(self.c.Tr.AbortPrompt, mode),
|
Prompt: fmt.Sprintf(self.c.Tr.AbortPrompt, mode),
|
||||||
|
@ -236,23 +224,11 @@ func (self *MergeAndRebaseHelper) AbortMergeOrRebaseWithConfirm() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MergeAndRebaseHelper) workingTreeStateNoun() string {
|
|
||||||
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
|
||||||
switch workingTreeState {
|
|
||||||
case enums.REBASE_MODE_NONE:
|
|
||||||
return ""
|
|
||||||
case enums.REBASE_MODE_MERGING:
|
|
||||||
return "merge"
|
|
||||||
default:
|
|
||||||
return "rebase"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PromptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress
|
// PromptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress
|
||||||
func (self *MergeAndRebaseHelper) PromptToContinueRebase() error {
|
func (self *MergeAndRebaseHelper) PromptToContinueRebase() error {
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: self.c.Tr.Continue,
|
Title: self.c.Tr.Continue,
|
||||||
Prompt: self.c.Tr.ConflictsResolved,
|
Prompt: fmt.Sprintf(self.c.Tr.ConflictsResolved, self.c.Git().Status.WorkingTreeState().CommandName()),
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
// By the time we get here, we might have unstaged changes again,
|
// By the time we get here, we might have unstaged changes again,
|
||||||
// e.g. if the user had to fix build errors after resolving the
|
// e.g. if the user had to fix build errors after resolving the
|
||||||
|
|
|
@ -4,8 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
@ -116,12 +114,12 @@ func (self *ModeHelper) Statuses() []ModeStatus {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
IsActive: func() bool {
|
IsActive: func() bool {
|
||||||
return !self.suppressRebasingMode && self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE
|
return !self.suppressRebasingMode && self.c.Git().Status.WorkingTreeState().Any()
|
||||||
},
|
},
|
||||||
Description: func() string {
|
Description: func() string {
|
||||||
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
||||||
return self.withResetButton(
|
return self.withResetButton(
|
||||||
presentation.FormatWorkingTreeStateTitle(self.c.Tr, workingTreeState), style.FgYellow,
|
workingTreeState.Title(self.c.Tr), style.FgYellow,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
Reset: self.mergeAndRebaseHelper.AbortMergeOrRebaseWithConfirm,
|
Reset: self.mergeAndRebaseHelper.AbortMergeOrRebaseWithConfirm,
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/patch_exploring"
|
"github.com/jesseduffield/lazygit/pkg/gui/patch_exploring"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
)
|
)
|
||||||
|
@ -22,7 +21,7 @@ func NewPatchBuildingHelper(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchBuildingHelper) ValidateNormalWorkingTreeState() (bool, error) {
|
func (self *PatchBuildingHelper) ValidateNormalWorkingTreeState() (bool, error) {
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
if self.c.Git().Status.WorkingTreeState().Any() {
|
||||||
return false, errors.New(self.c.Tr.CantPatchWhileRebasingError)
|
return false, errors.New(self.c.Tr.CantPatchWhileRebasingError)
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts"
|
"github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts"
|
||||||
|
@ -583,7 +582,7 @@ func (self *RefreshHelper) refreshStateFiles() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 {
|
if self.c.Git().Status.WorkingTreeState().Any() && conflictFileCount == 0 && prevConflictFileCount > 0 {
|
||||||
self.c.OnUIThread(func() error { return self.mergeAndRebaseHelper.PromptToContinueRebase() })
|
self.c.OnUIThread(func() error { return self.mergeAndRebaseHelper.PromptToContinueRebase() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
"github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||||
|
@ -682,7 +681,7 @@ func (self *LocalCommitsController) rewordEnabled(commit *models.Commit) *types.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) isRebasing() bool {
|
func (self *LocalCommitsController) isRebasing() bool {
|
||||||
return self.c.Model().WorkingTreeStateAtLastCommitRefresh != enums.REBASE_MODE_NONE
|
return self.c.Model().WorkingTreeStateAtLastCommitRefresh.Any()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) moveDown(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
func (self *LocalCommitsController) moveDown(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
|
@ -869,7 +868,8 @@ func (self *LocalCommitsController) revert(commit *models.Commit) error {
|
||||||
HandleConfirm: func() error {
|
HandleConfirm: func() error {
|
||||||
self.c.LogAction(self.c.Tr.Actions.RevertCommit)
|
self.c.LogAction(self.c.Tr.Actions.RevertCommit)
|
||||||
return self.c.WithWaitingStatusSync(self.c.Tr.RevertingStatus, func() error {
|
return self.c.WithWaitingStatusSync(self.c.Tr.RevertingStatus, func() error {
|
||||||
if err := self.c.Git().Commit.Revert(commit.Hash); err != nil {
|
result := self.c.Git().Commit.Revert(commit.Hash)
|
||||||
|
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return self.afterRevertCommit()
|
return self.afterRevertCommit()
|
||||||
|
@ -976,7 +976,7 @@ func (self *LocalCommitsController) moveFixupCommitToOwnerStackedBranch(targetCo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
if self.c.Git().Status.WorkingTreeState().Any() {
|
||||||
// Can't move commits while rebasing
|
// Can't move commits while rebasing
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/constants"
|
"github.com/jesseduffield/lazygit/pkg/constants"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
|
@ -109,19 +108,16 @@ func (self *StatusController) onClick(opts gocui.ViewMouseBindingOpts) error {
|
||||||
upstreamStatus := utils.Decolorise(presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr, time.Now(), self.c.UserConfig()))
|
upstreamStatus := utils.Decolorise(presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr, time.Now(), self.c.UserConfig()))
|
||||||
repoName := self.c.Git().RepoPaths.RepoName()
|
repoName := self.c.Git().RepoPaths.RepoName()
|
||||||
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
||||||
switch workingTreeState {
|
if workingTreeState.Any() {
|
||||||
case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING:
|
workingTreeStatus := fmt.Sprintf("(%s)", workingTreeState.LowerCaseTitle(self.c.Tr))
|
||||||
workingTreeStatus := fmt.Sprintf("(%s)", presentation.FormatWorkingTreeStateLower(self.c.Tr, workingTreeState))
|
|
||||||
if cursorInSubstring(opts.X, upstreamStatus+" ", workingTreeStatus) {
|
if cursorInSubstring(opts.X, upstreamStatus+" ", workingTreeStatus) {
|
||||||
return self.c.Helpers().MergeAndRebase.CreateRebaseOptionsMenu()
|
return self.c.Helpers().MergeAndRebase.CreateRebaseOptionsMenu()
|
||||||
}
|
}
|
||||||
if cursorInSubstring(opts.X, upstreamStatus+" "+workingTreeStatus+" ", repoName) {
|
if cursorInSubstring(opts.X, upstreamStatus+" "+workingTreeStatus+" ", repoName) {
|
||||||
return self.c.Helpers().Repos.CreateRecentReposMenu()
|
return self.c.Helpers().Repos.CreateRecentReposMenu()
|
||||||
}
|
}
|
||||||
default:
|
} else if cursorInSubstring(opts.X, upstreamStatus+" ", repoName) {
|
||||||
if cursorInSubstring(opts.X, upstreamStatus+" ", repoName) {
|
return self.c.Helpers().Repos.CreateRecentReposMenu()
|
||||||
return self.c.Helpers().Repos.CreateRecentReposMenu()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
@ -78,7 +77,7 @@ func (self *UndoController) reflogUndo() error {
|
||||||
undoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit undo]"}
|
undoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit undo]"}
|
||||||
undoingStatus := self.c.Tr.UndoingStatus
|
undoingStatus := self.c.Tr.UndoingStatus
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
if self.c.Git().Status.WorkingTreeState().Any() {
|
||||||
return errors.New(self.c.Tr.CantUndoWhileRebasing)
|
return errors.New(self.c.Tr.CantUndoWhileRebasing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +141,7 @@ func (self *UndoController) reflogRedo() error {
|
||||||
redoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit redo]"}
|
redoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit redo]"}
|
||||||
redoingStatus := self.c.Tr.RedoingStatus
|
redoingStatus := self.c.Tr.RedoingStatus
|
||||||
|
|
||||||
if self.c.Git().Status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
if self.c.Git().Status.WorkingTreeState().Any() {
|
||||||
return errors.New(self.c.Tr.CantRedoWhileRebasing)
|
return errors.New(self.c.Tr.CantRedoWhileRebasing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,16 +82,10 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode-specific global keybindings
|
// Mode-specific global keybindings
|
||||||
if self.c.Model().WorkingTreeStateAtLastCommitRefresh.IsRebasing() {
|
if state := self.c.Model().WorkingTreeStateAtLastCommitRefresh; state.Any() {
|
||||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu),
|
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu),
|
||||||
description: self.c.Tr.ViewRebaseOptions,
|
description: state.OptionsMapTitle(self.c.Tr),
|
||||||
style: style.FgYellow,
|
|
||||||
})
|
|
||||||
} else if self.c.Model().WorkingTreeStateAtLastCommitRefresh.IsMerging() {
|
|
||||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
|
||||||
key: keybindings.Label(self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu),
|
|
||||||
description: self.c.Tr.ViewMergeOptions,
|
|
||||||
style: style.FgYellow,
|
style: style.FgYellow,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
|
@ -18,7 +17,7 @@ func FormatStatus(
|
||||||
currentBranch *models.Branch,
|
currentBranch *models.Branch,
|
||||||
itemOperation types.ItemOperation,
|
itemOperation types.ItemOperation,
|
||||||
linkedWorktreeName string,
|
linkedWorktreeName string,
|
||||||
workingTreeState enums.RebaseMode,
|
workingTreeState models.WorkingTreeState,
|
||||||
tr *i18n.TranslationSet,
|
tr *i18n.TranslationSet,
|
||||||
userConfig *config.UserConfig,
|
userConfig *config.UserConfig,
|
||||||
) string {
|
) string {
|
||||||
|
@ -31,8 +30,8 @@ func FormatStatus(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if workingTreeState != enums.REBASE_MODE_NONE {
|
if workingTreeState.Any() {
|
||||||
status += style.FgYellow.Sprintf("(%s) ", FormatWorkingTreeStateLower(tr, workingTreeState))
|
status += style.FgYellow.Sprintf("(%s) ", workingTreeState.LowerCaseTitle(tr))
|
||||||
}
|
}
|
||||||
|
|
||||||
name := GetBranchTextStyle(currentBranch.Name).Sprint(currentBranch.Name)
|
name := GetBranchTextStyle(currentBranch.Name).Sprint(currentBranch.Name)
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package presentation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
|
||||||
)
|
|
||||||
|
|
||||||
func FormatWorkingTreeStateTitle(tr *i18n.TranslationSet, rebaseMode enums.RebaseMode) string {
|
|
||||||
switch rebaseMode {
|
|
||||||
case enums.REBASE_MODE_REBASING:
|
|
||||||
return tr.RebasingStatus
|
|
||||||
case enums.REBASE_MODE_MERGING:
|
|
||||||
return tr.MergingStatus
|
|
||||||
default:
|
|
||||||
// should never actually display this
|
|
||||||
return "none"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatWorkingTreeStateLower(tr *i18n.TranslationSet, rebaseMode enums.RebaseMode) string {
|
|
||||||
switch rebaseMode {
|
|
||||||
case enums.REBASE_MODE_REBASING:
|
|
||||||
return tr.LowercaseRebasingStatus
|
|
||||||
case enums.REBASE_MODE_MERGING:
|
|
||||||
return tr.LowercaseMergingStatus
|
|
||||||
default:
|
|
||||||
// should never actually display this
|
|
||||||
return "none"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
@ -288,7 +287,7 @@ type Model struct {
|
||||||
ReflogCommits []*models.Commit
|
ReflogCommits []*models.Commit
|
||||||
|
|
||||||
BisectInfo *git_commands.BisectInfo
|
BisectInfo *git_commands.BisectInfo
|
||||||
WorkingTreeStateAtLastCommitRefresh enums.RebaseMode
|
WorkingTreeStateAtLastCommitRefresh models.WorkingTreeState
|
||||||
RemoteBranches []*models.RemoteBranch
|
RemoteBranches []*models.RemoteBranch
|
||||||
Tags []*models.Tag
|
Tags []*models.Tag
|
||||||
|
|
||||||
|
|
|
@ -306,11 +306,15 @@ type TranslationSet struct {
|
||||||
ViewMergeRebaseOptionsTooltip string
|
ViewMergeRebaseOptionsTooltip string
|
||||||
ViewMergeOptions string
|
ViewMergeOptions string
|
||||||
ViewRebaseOptions string
|
ViewRebaseOptions string
|
||||||
|
ViewCherryPickOptions string
|
||||||
|
ViewRevertOptions string
|
||||||
NotMergingOrRebasing string
|
NotMergingOrRebasing string
|
||||||
AlreadyRebasing string
|
AlreadyRebasing string
|
||||||
RecentRepos string
|
RecentRepos string
|
||||||
MergeOptionsTitle string
|
MergeOptionsTitle string
|
||||||
RebaseOptionsTitle string
|
RebaseOptionsTitle string
|
||||||
|
CherryPickOptionsTitle string
|
||||||
|
RevertOptionsTitle string
|
||||||
CommitSummaryTitle string
|
CommitSummaryTitle string
|
||||||
CommitDescriptionTitle string
|
CommitDescriptionTitle string
|
||||||
CommitDescriptionSubTitle string
|
CommitDescriptionSubTitle string
|
||||||
|
@ -392,6 +396,8 @@ type TranslationSet struct {
|
||||||
MergingStatus string
|
MergingStatus string
|
||||||
LowercaseRebasingStatus string
|
LowercaseRebasingStatus string
|
||||||
LowercaseMergingStatus string
|
LowercaseMergingStatus string
|
||||||
|
LowercaseCherryPickingStatus string
|
||||||
|
LowercaseRevertingStatus string
|
||||||
AmendingStatus string
|
AmendingStatus string
|
||||||
CherryPickingStatus string
|
CherryPickingStatus string
|
||||||
UndoingStatus string
|
UndoingStatus string
|
||||||
|
@ -1359,11 +1365,15 @@ func EnglishTranslationSet() *TranslationSet {
|
||||||
ViewMergeRebaseOptionsTooltip: "View options to abort/continue/skip the current merge/rebase.",
|
ViewMergeRebaseOptionsTooltip: "View options to abort/continue/skip the current merge/rebase.",
|
||||||
ViewMergeOptions: "View merge options",
|
ViewMergeOptions: "View merge options",
|
||||||
ViewRebaseOptions: "View rebase options",
|
ViewRebaseOptions: "View rebase options",
|
||||||
|
ViewCherryPickOptions: "View cherry-pick options",
|
||||||
|
ViewRevertOptions: "View revert options",
|
||||||
NotMergingOrRebasing: "You are currently neither rebasing nor merging",
|
NotMergingOrRebasing: "You are currently neither rebasing nor merging",
|
||||||
AlreadyRebasing: "Can't perform this action during a rebase",
|
AlreadyRebasing: "Can't perform this action during a rebase",
|
||||||
RecentRepos: "Recent repositories",
|
RecentRepos: "Recent repositories",
|
||||||
MergeOptionsTitle: "Merge options",
|
MergeOptionsTitle: "Merge options",
|
||||||
RebaseOptionsTitle: "Rebase options",
|
RebaseOptionsTitle: "Rebase options",
|
||||||
|
CherryPickOptionsTitle: "Cherry-pick options",
|
||||||
|
RevertOptionsTitle: "Revert options",
|
||||||
CommitSummaryTitle: "Commit summary",
|
CommitSummaryTitle: "Commit summary",
|
||||||
CommitDescriptionTitle: "Commit description",
|
CommitDescriptionTitle: "Commit description",
|
||||||
CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus, {{.commitMenuKeybinding}} to open menu",
|
CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus, {{.commitMenuKeybinding}} to open menu",
|
||||||
|
@ -1381,7 +1391,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||||
SecondaryTitle: "Secondary",
|
SecondaryTitle: "Secondary",
|
||||||
ReflogCommitsTitle: "Reflog",
|
ReflogCommitsTitle: "Reflog",
|
||||||
GlobalTitle: "Global keybindings",
|
GlobalTitle: "Global keybindings",
|
||||||
ConflictsResolved: "All merge conflicts resolved. Continue?",
|
ConflictsResolved: "All merge conflicts resolved. Continue the %s?",
|
||||||
Continue: "Continue",
|
Continue: "Continue",
|
||||||
UnstagedFilesAfterConflictsResolved: "Files have been modified since conflicts were resolved. Auto-stage them and continue?",
|
UnstagedFilesAfterConflictsResolved: "Files have been modified since conflicts were resolved. Auto-stage them and continue?",
|
||||||
Keybindings: "Keybindings",
|
Keybindings: "Keybindings",
|
||||||
|
@ -1451,8 +1461,10 @@ func EnglishTranslationSet() *TranslationSet {
|
||||||
MovingStatus: "Moving",
|
MovingStatus: "Moving",
|
||||||
RebasingStatus: "Rebasing",
|
RebasingStatus: "Rebasing",
|
||||||
MergingStatus: "Merging",
|
MergingStatus: "Merging",
|
||||||
LowercaseRebasingStatus: "rebasing", // lowercase because it shows up in parentheses
|
LowercaseRebasingStatus: "rebasing", // lowercase because it shows up in parentheses
|
||||||
LowercaseMergingStatus: "merging", // lowercase because it shows up in parentheses
|
LowercaseMergingStatus: "merging", // lowercase because it shows up in parentheses
|
||||||
|
LowercaseCherryPickingStatus: "cherry-picking", // lowercase because it shows up in parentheses
|
||||||
|
LowercaseRevertingStatus: "reverting", // lowercase because it shows up in parentheses
|
||||||
AmendingStatus: "Amending",
|
AmendingStatus: "Amending",
|
||||||
CherryPickingStatus: "Cherry-picking",
|
CherryPickingStatus: "Cherry-picking",
|
||||||
UndoingStatus: "Undoing",
|
UndoingStatus: "Undoing",
|
||||||
|
|
|
@ -31,7 +31,7 @@ func main() {
|
||||||
|
|
||||||
integrationTest := getIntegrationTest()
|
integrationTest := getIntegrationTest()
|
||||||
|
|
||||||
if os.Getenv(components.WAIT_FOR_DEBUGGER_ENV_VAR) != "" {
|
if os.Getenv(components.WAIT_FOR_DEBUGGER_ENV_VAR) != "" && !daemon.InDaemonMode() {
|
||||||
println("Waiting for debugger to attach...")
|
println("Waiting for debugger to attach...")
|
||||||
for !isDebuggerAttached() {
|
for !isDebuggerAttached() {
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package components
|
package components
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// for running common actions
|
// for running common actions
|
||||||
type Common struct {
|
type Common struct {
|
||||||
t *TestDriver
|
t *TestDriver
|
||||||
|
@ -43,10 +45,10 @@ func (self *Common) AcknowledgeConflicts() {
|
||||||
Confirm()
|
Confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Common) ContinueOnConflictsResolved() {
|
func (self *Common) ContinueOnConflictsResolved(command string) {
|
||||||
self.t.ExpectPopup().Confirmation().
|
self.t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Continue")).
|
Title(Equals("Continue")).
|
||||||
Content(Contains("All merge conflicts resolved. Continue?")).
|
Content(Contains(fmt.Sprintf("All merge conflicts resolved. Continue the %s?", command))).
|
||||||
Confirm()
|
Confirm()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ var Rebase = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
|
||||||
t.Views().Information().Content(Contains("Rebasing"))
|
t.Views().Information().Content(Contains("Rebasing"))
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Information().Content(DoesNotContain("Rebasing"))
|
t.Views().Information().Content(DoesNotContain("Rebasing"))
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ var RebaseAndDrop = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
IsFocused().
|
IsFocused().
|
||||||
PressPrimaryAction()
|
PressPrimaryAction()
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Information().Content(DoesNotContain("Rebasing"))
|
t.Views().Information().Content(DoesNotContain("Rebasing"))
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ var RebaseConflictsFixBuildErrors = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
|
||||||
popup := t.ExpectPopup().Confirmation().
|
popup := t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Continue")).
|
Title(Equals("Continue")).
|
||||||
Content(Contains("All merge conflicts resolved. Continue?"))
|
Content(Contains("All merge conflicts resolved. Continue the rebase?"))
|
||||||
|
|
||||||
// While the popup is showing, fix some build errors
|
// While the popup is showing, fix some build errors
|
||||||
t.Shell().UpdateFile("file", "make it compile again")
|
t.Shell().UpdateFile("file", "make it compile again")
|
||||||
|
|
|
@ -69,7 +69,7 @@ var CherryPickConflicts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction()
|
PressPrimaryAction()
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Files().IsEmpty()
|
t.Views().Files().IsEmpty()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package commit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var RevertWithConflictSingleCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Reverts a commit that conflicts",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateFileAndAdd("myfile", "")
|
||||||
|
shell.Commit("add empty file")
|
||||||
|
shell.CreateFileAndAdd("myfile", "first line\n")
|
||||||
|
shell.Commit("add first line")
|
||||||
|
shell.UpdateFileAndAdd("myfile", "first line\nsecond line\n")
|
||||||
|
shell.Commit("add second line")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains("CI ◯ add second line").IsSelected(),
|
||||||
|
Contains("CI ◯ add first line"),
|
||||||
|
Contains("CI ◯ add empty file"),
|
||||||
|
).
|
||||||
|
SelectNextItem().
|
||||||
|
Press(keys.Commits.RevertCommit).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Confirmation().
|
||||||
|
Title(Equals("Revert commit")).
|
||||||
|
Content(MatchesRegexp(`Are you sure you want to revert \w+?`)).
|
||||||
|
Confirm()
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Conflicts!")).
|
||||||
|
Select(Contains("View conflicts")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
/* EXPECTED:
|
||||||
|
Proper display of revert commits is not implemented yet; we'll do this in the next PR
|
||||||
|
Contains("revert").Contains("CI <-- CONFLICT --- add first line"),
|
||||||
|
Contains("CI ◯ add second line"),
|
||||||
|
Contains("CI ◯ add first line"),
|
||||||
|
Contains("CI ◯ add empty file"),
|
||||||
|
ACTUAL: */
|
||||||
|
Contains("CI ◯ <-- YOU ARE HERE --- add second line"),
|
||||||
|
Contains("CI ◯ add first line"),
|
||||||
|
Contains("CI ◯ add empty file"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Options().Content(Contains("View revert options: m"))
|
||||||
|
t.Views().Information().Content(Contains("Reverting (Reset)"))
|
||||||
|
|
||||||
|
t.Views().Files().IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("UU myfile").IsSelected(),
|
||||||
|
).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().MergeConflicts().IsFocused().
|
||||||
|
SelectNextItem().
|
||||||
|
PressPrimaryAction()
|
||||||
|
|
||||||
|
t.ExpectPopup().Alert().
|
||||||
|
Title(Equals("Continue")).
|
||||||
|
Content(Contains("All merge conflicts resolved. Continue the revert?")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
Lines(
|
||||||
|
Contains(`CI ◯ Revert "add first line"`),
|
||||||
|
Contains("CI ◯ add second line"),
|
||||||
|
Contains("CI ◯ add first line"),
|
||||||
|
Contains("CI ◯ add empty file"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
|
@ -61,7 +61,7 @@ func doTheRebaseForAmendTests(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Continue")).
|
Title(Equals("Continue")).
|
||||||
Content(Contains("All merge conflicts resolved. Continue?")).
|
Content(Contains("All merge conflicts resolved. Continue the rebase?")).
|
||||||
Cancel()
|
Cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ var ResolveExternally = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
}).
|
}).
|
||||||
Press(keys.Universal.Refresh)
|
Press(keys.Universal.Refresh)
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("merge")
|
||||||
|
|
||||||
t.Views().Files().
|
t.Views().Files().
|
||||||
IsEmpty()
|
IsEmpty()
|
||||||
|
|
|
@ -51,6 +51,6 @@ var ResolveMultipleFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
).
|
).
|
||||||
PressPrimaryAction()
|
PressPrimaryAction()
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("merge")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -43,7 +43,7 @@ var ResolveWithoutTrailingLf = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
|
||||||
t.ExpectPopup().Alert().
|
t.ExpectPopup().Alert().
|
||||||
Title(Equals("Continue")).
|
Title(Equals("Continue")).
|
||||||
Content(Contains("All merge conflicts resolved. Continue?")).
|
Content(Contains("All merge conflicts resolved. Continue the merge?")).
|
||||||
Cancel()
|
Cancel()
|
||||||
|
|
||||||
t.Views().Files().
|
t.Views().Files().
|
||||||
|
|
|
@ -93,7 +93,7 @@ var DiscardAllDirChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("merge")
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Continue")).
|
Title(Equals("Continue")).
|
||||||
Content(Contains("Files have been modified since conflicts were resolved. Auto-stage them and continue?")).
|
Content(Contains("Files have been modified since conflicts were resolved. Auto-stage them and continue?")).
|
||||||
|
|
|
@ -53,7 +53,7 @@ var DiscardVariousChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Continue")).
|
Title(Equals("Continue")).
|
||||||
Content(Contains("All merge conflicts resolved. Continue?")).
|
Content(Contains("All merge conflicts resolved. Continue the merge?")).
|
||||||
Cancel()
|
Cancel()
|
||||||
|
|
||||||
discardOneByOne([]statusFile{
|
discardOneByOne([]statusFile{
|
||||||
|
|
|
@ -40,7 +40,7 @@ var DiscardVariousChangesRangeSelect = NewIntegrationTest(NewIntegrationTestArgs
|
||||||
|
|
||||||
t.ExpectPopup().Confirmation().
|
t.ExpectPopup().Confirmation().
|
||||||
Title(Equals("Continue")).
|
Title(Equals("Continue")).
|
||||||
Content(Contains("All merge conflicts resolved. Continue?")).
|
Content(Contains("All merge conflicts resolved. Continue the merge?")).
|
||||||
Cancel()
|
Cancel()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
|
|
|
@ -60,7 +60,7 @@ var AmendCommitWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction() // pick "4"
|
PressPrimaryAction() // pick "4"
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Common().AcknowledgeConflicts()
|
t.Common().AcknowledgeConflicts()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package interactive_rebase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var RebaseWithCommitThatBecomesEmpty = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Performs a rebase involving a commit that becomes empty during the rebase, and gets dropped.",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.EmptyCommit("initial commit")
|
||||||
|
// It is important that we create two separate commits for the two
|
||||||
|
// changes to the file, but only one commit for the same changes on our
|
||||||
|
// branch; otherwise, the commit would be discarded at the start of the
|
||||||
|
// rebase already.
|
||||||
|
shell.CreateFileAndAdd("file", "change 1\n")
|
||||||
|
shell.Commit("master change 1")
|
||||||
|
shell.UpdateFileAndAdd("file", "change 1\nchange 2\n")
|
||||||
|
shell.Commit("master change 2")
|
||||||
|
shell.NewBranchFrom("branch", "HEAD^^")
|
||||||
|
shell.CreateFileAndAdd("file", "change 1\nchange 2\n")
|
||||||
|
shell.Commit("branch change")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Branches().
|
||||||
|
Focus().
|
||||||
|
NavigateToLine(Contains("master")).
|
||||||
|
Press(keys.Branches.RebaseBranch)
|
||||||
|
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Rebase 'branch'")).
|
||||||
|
Select(Contains("Simple rebase")).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
t.Views().Commits().
|
||||||
|
Lines(
|
||||||
|
Contains("master change 2"),
|
||||||
|
Contains("master change 1"),
|
||||||
|
Contains("initial commit"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
|
@ -33,7 +33,7 @@ func handleConflictsFromSwap(t *TestDriver) {
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction() // pick "three"
|
PressPrimaryAction() // pick "three"
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Common().AcknowledgeConflicts()
|
t.Common().AcknowledgeConflicts()
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ func handleConflictsFromSwap(t *TestDriver) {
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction() // pick "two"
|
PressPrimaryAction() // pick "two"
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Commits().
|
t.Views().Commits().
|
||||||
Focus().
|
Focus().
|
||||||
|
|
|
@ -71,7 +71,7 @@ var MoveToEarlierCommitFromAddedFile = NewIntegrationTest(NewIntegrationTestArgs
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction() // choose the version with all three lines
|
PressPrimaryAction() // choose the version with all three lines
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Commits().
|
t.Views().Commits().
|
||||||
Focus().
|
Focus().
|
||||||
|
|
|
@ -67,7 +67,7 @@ var MoveToIndexFromAddedFileWithConflict = NewIntegrationTest(NewIntegrationTest
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction()
|
PressPrimaryAction()
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.ExpectPopup().Alert().
|
t.ExpectPopup().Alert().
|
||||||
Title(Equals("Error")).
|
Title(Equals("Error")).
|
||||||
|
|
|
@ -62,7 +62,7 @@ var MoveToIndexWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
).
|
).
|
||||||
PressPrimaryAction()
|
PressPrimaryAction()
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.ExpectPopup().Alert().
|
t.ExpectPopup().Alert().
|
||||||
Title(Equals("Error")).
|
Title(Equals("Error")).
|
||||||
|
|
|
@ -60,7 +60,7 @@ var PullMergeConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
).
|
).
|
||||||
PressPrimaryAction() // choose 'content4'
|
PressPrimaryAction() // choose 'content4'
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("merge")
|
||||||
|
|
||||||
t.Views().Status().Content(Equals("↑2 repo → master"))
|
t.Views().Status().Content(Equals("↑2 repo → master"))
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ var PullRebaseConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction() // choose 'content4'
|
PressPrimaryAction() // choose 'content4'
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Status().Content(Equals("↑1 repo → master"))
|
t.Views().Status().Content(Equals("↑1 repo → master"))
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ var PullRebaseInteractiveConflict = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction() // choose 'content4'
|
PressPrimaryAction() // choose 'content4'
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Status().Content(Equals("↑2 repo → master"))
|
t.Views().Status().Content(Equals("↑2 repo → master"))
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ var PullRebaseInteractiveConflictDrop = NewIntegrationTest(NewIntegrationTestArg
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
PressPrimaryAction() // choose 'content4'
|
PressPrimaryAction() // choose 'content4'
|
||||||
|
|
||||||
t.Common().ContinueOnConflictsResolved()
|
t.Common().ContinueOnConflictsResolved("rebase")
|
||||||
|
|
||||||
t.Views().Status().Content(Equals("↑1 repo → master"))
|
t.Views().Status().Content(Equals("↑1 repo → master"))
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,7 @@ var tests = []*components.IntegrationTest{
|
||||||
commit.ResetAuthorRange,
|
commit.ResetAuthorRange,
|
||||||
commit.Revert,
|
commit.Revert,
|
||||||
commit.RevertMerge,
|
commit.RevertMerge,
|
||||||
|
commit.RevertWithConflictSingleCommit,
|
||||||
commit.Reword,
|
commit.Reword,
|
||||||
commit.Search,
|
commit.Search,
|
||||||
commit.SetAuthor,
|
commit.SetAuthor,
|
||||||
|
@ -260,6 +261,7 @@ var tests = []*components.IntegrationTest{
|
||||||
interactive_rebase.QuickStartKeepSelection,
|
interactive_rebase.QuickStartKeepSelection,
|
||||||
interactive_rebase.QuickStartKeepSelectionRange,
|
interactive_rebase.QuickStartKeepSelectionRange,
|
||||||
interactive_rebase.Rebase,
|
interactive_rebase.Rebase,
|
||||||
|
interactive_rebase.RebaseWithCommitThatBecomesEmpty,
|
||||||
interactive_rebase.RewordCommitWithEditorAndFail,
|
interactive_rebase.RewordCommitWithEditorAndFail,
|
||||||
interactive_rebase.RewordFirstCommit,
|
interactive_rebase.RewordFirstCommit,
|
||||||
interactive_rebase.RewordLastCommit,
|
interactive_rebase.RewordLastCommit,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue