mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Merge 6e666bb6c3 into c07f4d381b
This commit is contained in:
commit
58cf058e80
|
|
@ -88,8 +88,8 @@ func (self *PatchCommands) SaveTemporaryPatch(patch string) (string, error) {
|
|||
}
|
||||
|
||||
// DeletePatchesFromCommit applies a patch in reverse for a commit
|
||||
func (self *PatchCommands) DeletePatchesFromCommit(commits []*models.Commit, commitIndex int) error {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIndex, false); err != nil {
|
||||
func (self *PatchCommands) DeletePatchesFromCommit(commits []*models.Commit, commitIndex int, parentIdx int) error {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIndex, parentIdx, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -113,12 +113,12 @@ func (self *PatchCommands) DeletePatchesFromCommit(commits []*models.Commit, com
|
|||
return self.rebase.ContinueRebase()
|
||||
}
|
||||
|
||||
func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, sourceCommitIdx int, destinationCommitIdx int) error {
|
||||
func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, sourceCommitIdx int, destinationCommitIdx int, parentIdx int) error {
|
||||
if sourceCommitIdx < destinationCommitIdx {
|
||||
// Passing true for keepCommitsThatBecomeEmpty: if the moved-from
|
||||
// commit becomes empty, we want to keep it, mainly for consistency with
|
||||
// moving the patch to a *later* commit, which behaves the same.
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, destinationCommitIdx, true); err != nil {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, destinationCommitIdx, parentIdx, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -217,14 +217,14 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
|
|||
return self.rebase.ContinueRebase()
|
||||
}
|
||||
|
||||
func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitIdx int, stash bool) error {
|
||||
func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitIdx int, parentIdx int, stash bool) error {
|
||||
if stash {
|
||||
if err := self.stash.Push(fmt.Sprintf(self.Tr.AutoStashForMovingPatchToIndex, commits[commitIdx].ShortHash())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx, false); err != nil {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx, parentIdx, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -275,10 +275,11 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
|
|||
func (self *PatchCommands) PullPatchIntoNewCommit(
|
||||
commits []*models.Commit,
|
||||
commitIdx int,
|
||||
parentIdx int,
|
||||
commitSummary string,
|
||||
commitDescription string,
|
||||
) error {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx, false); err != nil {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx, parentIdx, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -318,10 +319,11 @@ func (self *PatchCommands) PullPatchIntoNewCommit(
|
|||
func (self *PatchCommands) PullPatchIntoNewCommitBefore(
|
||||
commits []*models.Commit,
|
||||
commitIdx int,
|
||||
parentIdx int,
|
||||
commitSummary string,
|
||||
commitDescription string,
|
||||
) error {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx+1, true); err != nil {
|
||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx+1, parentIdx, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ func NewRebaseCommands(
|
|||
}
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
|
||||
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, parentIdx int, summary string, description string) error {
|
||||
// This check is currently unreachable (handled in LocalCommitsController.reword),
|
||||
// but kept as a safeguard in case this method is used elsewhere.
|
||||
if self.config.NeedsGpgSubprocessForCommit() {
|
||||
return errors.New(self.Tr.DisabledForGPG)
|
||||
}
|
||||
|
||||
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
|
||||
err := self.BeginInteractiveRebaseForCommit(commits, index, parentIdx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, su
|
|||
return self.ContinueRebase()
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) RewordCommitInEditor(commits []*models.Commit, index int) (*oscommands.CmdObj, error) {
|
||||
func (self *RebaseCommands) RewordCommitInEditor(commits []*models.Commit, index int, parentIdx int) (*oscommands.CmdObj, error) {
|
||||
changes := []daemon.ChangeTodoAction{{
|
||||
Hash: commits[index].Hash(),
|
||||
NewAction: todo.Reword,
|
||||
|
|
@ -63,36 +63,36 @@ func (self *RebaseCommands) RewordCommitInEditor(commits []*models.Commit, index
|
|||
self.os.LogCommand(logTodoChanges(changes), false)
|
||||
|
||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, index+1),
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, parentIdx),
|
||||
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, start, end int) error {
|
||||
return self.GenericAmend(commits, start, end, func(_ *models.Commit) error {
|
||||
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, start, end int, parentIdx int) error {
|
||||
return self.GenericAmend(commits, start, end, parentIdx, func(_ *models.Commit) error {
|
||||
return self.commit.ResetAuthor()
|
||||
})
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, start, end int, value string) error {
|
||||
return self.GenericAmend(commits, start, end, func(_ *models.Commit) error {
|
||||
func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, start, end int, parentIdx int, value string) error {
|
||||
return self.GenericAmend(commits, start, end, parentIdx, func(_ *models.Commit) error {
|
||||
return self.commit.SetAuthor(value)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) AddCommitCoAuthor(commits []*models.Commit, start, end int, value string) error {
|
||||
return self.GenericAmend(commits, start, end, func(commit *models.Commit) error {
|
||||
func (self *RebaseCommands) AddCommitCoAuthor(commits []*models.Commit, start, end int, parentIdx int, value string) error {
|
||||
return self.GenericAmend(commits, start, end, parentIdx, func(commit *models.Commit) error {
|
||||
return self.commit.AddCoAuthor(commit.Hash(), value)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, start, end int, f func(commit *models.Commit) error) error {
|
||||
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, start, end int, parentIdx int, f func(commit *models.Commit) error) error {
|
||||
if start == end && models.IsHeadCommit(commits, start) {
|
||||
// we've selected the top commit so no rebase is required
|
||||
return f(commits[start])
|
||||
}
|
||||
|
||||
err := self.BeginInteractiveRebaseForCommitRange(commits, start, end, false)
|
||||
err := self.BeginInteractiveRebaseForCommitRange(commits, start, end, parentIdx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -140,13 +140,8 @@ func (self *RebaseCommands) MoveCommits(commits []*models.Commit, startIdx int,
|
|||
}).Run()
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx int, endIdx int, action todo.TodoCommand, flag string) error {
|
||||
baseIndex := endIdx + 1
|
||||
if action == todo.Squash || action == todo.Fixup {
|
||||
baseIndex++
|
||||
}
|
||||
|
||||
baseHashOrRoot := getBaseHashOrRoot(commits, baseIndex)
|
||||
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx int, endIdx int, parentIdx int, action todo.TodoCommand, flag string) error {
|
||||
baseHashOrRoot := getBaseHashOrRoot(commits, parentIdx)
|
||||
|
||||
changes := lo.FilterMap(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) (daemon.ChangeTodoAction, bool) {
|
||||
return daemon.ChangeTodoAction{
|
||||
|
|
@ -296,7 +291,7 @@ func (self *RebaseCommands) getHashOfLastCommitMade() (string, error) {
|
|||
}
|
||||
|
||||
// AmendTo amends the given commit with whatever files are staged
|
||||
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) error {
|
||||
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int, parentIdx int) error {
|
||||
commit := commits[commitIndex]
|
||||
|
||||
if err := self.commit.CreateFixupCommit(commit.Hash()); err != nil {
|
||||
|
|
@ -309,7 +304,7 @@ func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) e
|
|||
}
|
||||
|
||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, commitIndex+1),
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, parentIdx),
|
||||
overrideEditor: true,
|
||||
instruction: daemon.NewMoveFixupCommitDownInstruction(commit.Hash(), fixupHash, true),
|
||||
}).Run()
|
||||
|
|
@ -403,7 +398,7 @@ func (self *RebaseCommands) SquashAllAboveFixupCommits(commit *models.Commit) er
|
|||
// BeginInteractiveRebaseForCommit starts an interactive rebase to edit the current
|
||||
// commit and pick all others. After this you'll want to call `self.ContinueRebase()
|
||||
func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
|
||||
commits []*models.Commit, commitIndex int, keepCommitsThatBecomeEmpty bool,
|
||||
commits []*models.Commit, commitIndex int, parentIdx int, keepCommitsThatBecomeEmpty bool,
|
||||
) error {
|
||||
if commitIndex < len(commits) && commits[commitIndex].IsMerge() {
|
||||
if self.config.NeedsGpgSubprocessForCommit() {
|
||||
|
|
@ -417,11 +412,11 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
|
|||
}).Run()
|
||||
}
|
||||
|
||||
return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, keepCommitsThatBecomeEmpty)
|
||||
return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, parentIdx, keepCommitsThatBecomeEmpty)
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) BeginInteractiveRebaseForCommitRange(
|
||||
commits []*models.Commit, start, end int, keepCommitsThatBecomeEmpty bool,
|
||||
commits []*models.Commit, start, end int, parentIdx int, keepCommitsThatBecomeEmpty bool,
|
||||
) error {
|
||||
if len(commits)-1 < end {
|
||||
return errors.New("index outside of range of commits")
|
||||
|
|
@ -444,7 +439,7 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommitRange(
|
|||
self.os.LogCommand(logTodoChanges(changes), false)
|
||||
|
||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, end+1),
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, parentIdx),
|
||||
overrideEditor: true,
|
||||
keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty,
|
||||
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
||||
|
|
@ -517,8 +512,8 @@ func (self *RebaseCommands) runSkipEditorCommand(cmdObj *oscommands.CmdObj) erro
|
|||
}
|
||||
|
||||
// DiscardOldFileChanges discards changes to a file from an old commit
|
||||
func (self *RebaseCommands) DiscardOldFileChanges(commits []*models.Commit, commitIndex int, filePaths []string) error {
|
||||
if err := self.BeginInteractiveRebaseForCommit(commits, commitIndex, false); err != nil {
|
||||
func (self *RebaseCommands) DiscardOldFileChanges(commits []*models.Commit, commitIndex int, parentIdx int, filePaths []string) error {
|
||||
if err := self.BeginInteractiveRebaseForCommit(commits, commitIndex, parentIdx, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||
gitConfigMockResponses map[string]string
|
||||
commitOpts []models.NewCommitOpts
|
||||
commitIndex int
|
||||
parentIndex int
|
||||
fileName []string
|
||||
runner *oscommands.FakeCmdObjRunner
|
||||
test func(error)
|
||||
|
|
@ -111,6 +112,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||
gitConfigMockResponses: nil,
|
||||
commitOpts: []models.NewCommitOpts{},
|
||||
commitIndex: 0,
|
||||
parentIndex: 0,
|
||||
fileName: []string{"test999.txt"},
|
||||
runner: oscommands.NewFakeRunner(t),
|
||||
test: func(err error) {
|
||||
|
|
@ -122,6 +124,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||
gitConfigMockResponses: map[string]string{"commit.gpgSign": "true"},
|
||||
commitOpts: []models.NewCommitOpts{{Name: "commit", Hash: "123456"}},
|
||||
commitIndex: 0,
|
||||
parentIndex: 0,
|
||||
fileName: []string{"test999.txt"},
|
||||
runner: oscommands.NewFakeRunner(t),
|
||||
test: func(err error) {
|
||||
|
|
@ -136,6 +139,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||
{Name: "commit2", Hash: "abcdef"},
|
||||
},
|
||||
commitIndex: 0,
|
||||
parentIndex: 1,
|
||||
fileName: []string{"test999.txt"},
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"rebase", "--interactive", "--autostash", "--keep-empty", "--no-autosquash", "--rebase-merges", "abcdef"}, "", nil).
|
||||
|
|
@ -163,7 +167,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||
commits := lo.Map(s.commitOpts,
|
||||
func(opts models.NewCommitOpts, _ int) *models.Commit { return models.NewCommit(hashPool, opts) })
|
||||
|
||||
s.test(instance.DiscardOldFileChanges(commits, s.commitIndex, s.fileName))
|
||||
s.test(instance.DiscardOldFileChanges(commits, s.commitIndex, s.parentIndex, s.fileName))
|
||||
s.runner.CheckForMissingCalls()
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -339,6 +339,8 @@ func (self *CommitFilesController) discard(selectedNodes []*filetree.CommitFileN
|
|||
HandleConfirm: func() error {
|
||||
commits := self.c.Model().Commits
|
||||
selectedLineIdx := self.c.Contexts().LocalCommits.GetSelectedLineIdx()
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
return self.c.WithWaitingStatusBlockingInput(types.WaitingStatusOpts{
|
||||
Message: self.c.Tr.RebasingStatus,
|
||||
HideWorkingTreeState: true,
|
||||
|
|
@ -361,7 +363,7 @@ func (self *CommitFilesController) discard(selectedNodes []*filetree.CommitFileN
|
|||
})
|
||||
}
|
||||
|
||||
err := self.c.Git().Rebase.DiscardOldFileChanges(commits, selectedLineIdx, filePaths)
|
||||
err := self.c.Git().Rebase.DiscardOldFileChanges(commits, selectedLineIdx, parentIdx, filePaths)
|
||||
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,9 +134,11 @@ func (self *CustomPatchOptionsMenuAction) handleDeletePatchFromCommit() error {
|
|||
|
||||
commits := self.c.Model().Commits
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit)
|
||||
err := self.c.Git().Patch.DeletePatchesFromCommit(commits, commitIndex)
|
||||
err := self.c.Git().Patch.DeletePatchesFromCommit(commits, commitIndex, parentIdx)
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||
})
|
||||
}
|
||||
|
|
@ -147,9 +149,11 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchToSelectedCommit() erro
|
|||
commits := self.c.Model().Commits
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
toCommitIndex := self.c.Contexts().LocalCommits.GetSelectedLineIdx()
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.MovePatchToSelectedCommit)
|
||||
err := self.c.Git().Patch.MovePatchToSelectedCommit(commits, commitIndex, toCommitIndex)
|
||||
err := self.c.Git().Patch.MovePatchToSelectedCommit(commits, commitIndex, toCommitIndex, parentIdx)
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||
})
|
||||
}
|
||||
|
|
@ -164,9 +168,11 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error
|
|||
HandleConfirm: func() error {
|
||||
commits := self.c.Model().Commits
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoIndex)
|
||||
err := self.c.Git().Patch.MovePatchIntoIndex(commits, commitIndex, mustStash)
|
||||
err := self.c.Git().Patch.MovePatchIntoIndex(commits, commitIndex, parentIdx, mustStash)
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||
})
|
||||
},
|
||||
|
|
@ -177,6 +183,8 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
|
|||
self.returnFocusFromPatchExplorerIfNecessary()
|
||||
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
self.c.Helpers().Commits.OpenCommitMessagePanel(
|
||||
&helpers.OpenCommitMessagePanelOpts{
|
||||
// Pass a commit index of one less than the moved-from commit, so that
|
||||
|
|
@ -191,7 +199,7 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
|
|||
self.c.Helpers().Commits.CloseCommitMessagePanel()
|
||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit)
|
||||
err := self.c.Git().Patch.PullPatchIntoNewCommit(commits, commitIndex, summary, description)
|
||||
err := self.c.Git().Patch.PullPatchIntoNewCommit(commits, commitIndex, parentIdx, summary, description)
|
||||
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -212,6 +220,8 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommitBefore() e
|
|||
self.returnFocusFromPatchExplorerIfNecessary()
|
||||
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 2)
|
||||
self.c.Helpers().Commits.OpenCommitMessagePanel(
|
||||
&helpers.OpenCommitMessagePanelOpts{
|
||||
// Pass a commit index of one less than the moved-from commit, so that
|
||||
|
|
@ -226,7 +236,7 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommitBefore() e
|
|||
self.c.Helpers().Commits.CloseCommitMessagePanel()
|
||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit)
|
||||
err := self.c.Git().Patch.PullPatchIntoNewCommitBefore(commits, commitIndex, summary, description)
|
||||
err := self.c.Git().Patch.PullPatchIntoNewCommitBefore(commits, commitIndex, parentIdx, summary, description)
|
||||
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
|
|
@ -252,6 +253,39 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S
|
|||
})
|
||||
}
|
||||
|
||||
func (self *CommitsHelper) GetParentCommit(selectedCommits []*models.Commit, endIdx int, depth int) (*models.Commit, int) {
|
||||
commits := self.c.Model().Commits
|
||||
|
||||
currentCommit := selectedCommits[len(selectedCommits)-1]
|
||||
parentIndex := endIdx
|
||||
var parentCommit *models.Commit
|
||||
|
||||
for d := 0; d < depth; d++ {
|
||||
selectedParents := currentCommit.Parents()
|
||||
if len(selectedParents) == 0 {
|
||||
self.c.Log.Warn("Selected commit has no parents, the nearest commit is used")
|
||||
return commits[parentIndex], parentIndex + 1
|
||||
}
|
||||
parentHash := selectedParents[0]
|
||||
found := false
|
||||
for i, commit := range commits {
|
||||
if commit.Hash() == parentHash {
|
||||
parentIndex = i
|
||||
parentCommit = commits[parentIndex]
|
||||
currentCommit = parentCommit
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
self.c.Log.Warnf("Parent commit %s not found in visible commit list, the nearest commit is used ", parentHash)
|
||||
return commits[parentIndex], parentIndex + 1
|
||||
}
|
||||
}
|
||||
|
||||
return parentCommit, parentIndex
|
||||
}
|
||||
|
||||
func (self *CommitsHelper) addCoAuthor(suggestionFunc func(string) []*types.Suggestion) error {
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.AddCoAuthorPromptTitle,
|
||||
|
|
|
|||
|
|
@ -740,6 +740,8 @@ func (self *LocalCommitsController) squashDown(selectedCommits []*models.Commit,
|
|||
return self.updateTodos(todo.Squash, selectedCommits)
|
||||
}
|
||||
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.Squash,
|
||||
Prompt: self.c.Tr.SureSquashThisCommit,
|
||||
|
|
@ -751,7 +753,7 @@ func (self *LocalCommitsController) squashDown(selectedCommits []*models.Commit,
|
|||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.SquashCommitDown)
|
||||
return self.interactiveRebase(commits, todo.Squash, startIdx, endIdx)
|
||||
return self.interactiveRebase(commits, todo.Squash, startIdx, endIdx, parentIdx)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
@ -763,6 +765,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star
|
|||
if self.isRebasing() {
|
||||
return self.updateTodos(todo.Fixup, selectedCommits)
|
||||
}
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: self.c.Tr.Fixup,
|
||||
|
|
@ -778,7 +781,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star
|
|||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.FixupCommit)
|
||||
return self.interactiveRebase(commits, todo.Fixup, startIdx, endIdx)
|
||||
return self.interactiveRebase(commits, todo.Fixup, startIdx, endIdx, parentIdx)
|
||||
})
|
||||
},
|
||||
Tooltip: self.c.Tr.FixupTooltip,
|
||||
|
|
@ -794,7 +797,7 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star
|
|||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.FixupCommitKeepMessage)
|
||||
return self.interactiveRebaseWithFlag(commits, todo.Fixup, startIdx, endIdx, "-C")
|
||||
return self.interactiveRebaseWithFlag(commits, todo.Fixup, startIdx, endIdx, parentIdx, "-C")
|
||||
})
|
||||
},
|
||||
Tooltip: self.c.Tr.FixupKeepMessageTooltip,
|
||||
|
|
@ -872,7 +875,10 @@ func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepat
|
|||
self.c.Git().Commit.RewordLastCommitInEditorWithMessageFileCmdObj(filepath))
|
||||
}
|
||||
|
||||
err := self.c.Git().Rebase.BeginInteractiveRebaseForCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx(), false)
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
err := self.c.Git().Rebase.BeginInteractiveRebaseForCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx(), parentIdx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -903,11 +909,14 @@ func (self *LocalCommitsController) handleReword(summary string, description str
|
|||
self.c.Tr.RewordingStatus, nil, nil)
|
||||
}
|
||||
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
return self.c.WithWaitingStatusBlockingInput(types.WaitingStatusOpts{
|
||||
Message: self.c.Tr.RewordingStatus,
|
||||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
err := self.c.Git().Rebase.RewordCommit(commits, selectedIdx, summary, description)
|
||||
err := self.c.Git().Rebase.RewordCommit(commits, selectedIdx, parentIdx, summary, description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -923,8 +932,11 @@ func (self *LocalCommitsController) doRewordEditor() error {
|
|||
return self.c.RunSubprocessAndRefresh(self.c.Git().Commit.RewordLastCommitInEditorCmdObj())
|
||||
}
|
||||
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
subProcess, err := self.c.Git().Rebase.RewordCommitInEditor(
|
||||
self.c.Model().Commits, self.context().GetSelectedLineIdx(),
|
||||
self.c.Model().Commits, self.context().GetSelectedLineIdx(), parentIdx,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -984,6 +996,8 @@ func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, start
|
|||
|
||||
isMerge := selectedCommits[0].IsMerge()
|
||||
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.DropCommitTitle,
|
||||
Prompt: lo.Ternary(isMerge, self.c.Tr.DropMergeCommitPrompt, self.c.Tr.DropCommitPrompt),
|
||||
|
|
@ -1000,7 +1014,7 @@ func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, start
|
|||
if isMerge {
|
||||
return self.dropMergeCommit(commits, startIdx)
|
||||
}
|
||||
return self.interactiveRebase(commits, todo.Drop, startIdx, endIdx)
|
||||
return self.interactiveRebase(commits, todo.Drop, startIdx, endIdx, parentIdx)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
@ -1018,13 +1032,15 @@ func (self *LocalCommitsController) edit(selectedCommits []*models.Commit, start
|
|||
return self.updateTodos(todo.Edit, selectedCommits)
|
||||
}
|
||||
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
commits := self.c.Model().Commits
|
||||
if !commits[endIdx].IsMerge() {
|
||||
return self.c.WithWaitingStatusBlockingInput(types.WaitingStatusOpts{
|
||||
Message: self.c.Tr.RebasingStatus,
|
||||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
err := self.c.Git().Rebase.InteractiveRebase(commits, startIdx, endIdx, todo.Edit, "")
|
||||
err := self.c.Git().Rebase.InteractiveRebase(commits, startIdx, endIdx, parentIdx, todo.Edit, "")
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
||||
err, types.RefreshOptions{BatchUIUpdates: true})
|
||||
})
|
||||
|
|
@ -1093,12 +1109,12 @@ func (self *LocalCommitsController) pick(selectedCommits []*models.Commit) error
|
|||
panic("should be disabled when not rebasing")
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) interactiveRebase(commits []*models.Commit, action todo.TodoCommand, startIdx int, endIdx int) error {
|
||||
return self.interactiveRebaseWithFlag(commits, action, startIdx, endIdx, "")
|
||||
func (self *LocalCommitsController) interactiveRebase(commits []*models.Commit, action todo.TodoCommand, startIdx int, endIdx int, parentIdx int) error {
|
||||
return self.interactiveRebaseWithFlag(commits, action, startIdx, endIdx, parentIdx, "")
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) interactiveRebaseWithFlag(commits []*models.Commit, action todo.TodoCommand, startIdx int, endIdx int, flag string) error {
|
||||
err := self.c.Git().Rebase.InteractiveRebase(commits, startIdx, endIdx, action, flag)
|
||||
func (self *LocalCommitsController) interactiveRebaseWithFlag(commits []*models.Commit, action todo.TodoCommand, startIdx int, endIdx int, parentIdx int, flag string) error {
|
||||
err := self.c.Git().Rebase.InteractiveRebase(commits, startIdx, endIdx, parentIdx, action, flag)
|
||||
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||
}
|
||||
|
|
@ -1226,6 +1242,9 @@ func (self *LocalCommitsController) move(
|
|||
func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
||||
var handleCommit func() error
|
||||
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
|
||||
if self.isSelectedHeadCommit() {
|
||||
handleCommit = func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
|
||||
|
|
@ -1246,7 +1265,7 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
|||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.AmendCommit)
|
||||
err := self.c.Git().Rebase.AmendTo(commits, selectedIdx)
|
||||
err := self.c.Git().Rebase.AmendTo(commits, selectedIdx, parentIdx)
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||
})
|
||||
})
|
||||
|
|
@ -1274,30 +1293,31 @@ func (self *LocalCommitsController) canAmend(_ *models.Commit) *types.DisabledRe
|
|||
return self.canAmendRange(self.c.Model().Commits, idx, idx)
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) amendAttribute(_ []*models.Commit, start, end int) error {
|
||||
func (self *LocalCommitsController) amendAttribute(selectedCommits []*models.Commit, start, end int) error {
|
||||
// The author operations index into the full commit list by absolute
|
||||
// start/end, so capture that here on the UI thread rather than reading
|
||||
// Model().Commits from the worker the menu items dispatch to.
|
||||
commits := self.c.Model().Commits
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, end, 1)
|
||||
opts := self.c.KeybindingsOpts()
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: "Amend commit attribute",
|
||||
Items: []*types.MenuItem{
|
||||
{
|
||||
Label: self.c.Tr.ResetAuthor,
|
||||
OnPress: func() error { return self.resetAuthor(commits, start, end) },
|
||||
OnPress: func() error { return self.resetAuthor(commits, start, end, parentIdx) },
|
||||
Keys: opts.GetKeys(opts.Config.AmendAttribute.ResetAuthor),
|
||||
Tooltip: self.c.Tr.ResetAuthorTooltip,
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.SetAuthor,
|
||||
OnPress: func() error { return self.setAuthor(commits, start, end) },
|
||||
OnPress: func() error { return self.setAuthor(commits, start, end, parentIdx) },
|
||||
Keys: opts.GetKeys(opts.Config.AmendAttribute.SetAuthor),
|
||||
Tooltip: self.c.Tr.SetAuthorTooltip,
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.AddCoAuthor,
|
||||
OnPress: func() error { return self.addCoAuthor(commits, start, end) },
|
||||
OnPress: func() error { return self.addCoAuthor(commits, start, end, parentIdx) },
|
||||
Keys: opts.GetKeys(opts.Config.AmendAttribute.AddCoAuthor),
|
||||
Tooltip: self.c.Tr.AddCoAuthorTooltip,
|
||||
},
|
||||
|
|
@ -1305,13 +1325,13 @@ func (self *LocalCommitsController) amendAttribute(_ []*models.Commit, start, en
|
|||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) resetAuthor(commits []*models.Commit, start, end int) error {
|
||||
func (self *LocalCommitsController) resetAuthor(commits []*models.Commit, start, end int, parentIdx int) error {
|
||||
return self.c.WithWaitingStatusBlockingInput(types.WaitingStatusOpts{
|
||||
Message: self.c.Tr.AmendingStatus,
|
||||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.ResetCommitAuthor)
|
||||
if err := self.c.Git().Rebase.ResetCommitAuthor(commits, start, end); err != nil {
|
||||
if err := self.c.Git().Rebase.ResetCommitAuthor(commits, start, end, parentIdx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1320,7 +1340,7 @@ func (self *LocalCommitsController) resetAuthor(commits []*models.Commit, start,
|
|||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) setAuthor(commits []*models.Commit, start, end int) error {
|
||||
func (self *LocalCommitsController) setAuthor(commits []*models.Commit, start, end int, parentIdx int) error {
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.SetAuthorPromptTitle,
|
||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc(),
|
||||
|
|
@ -1330,7 +1350,7 @@ func (self *LocalCommitsController) setAuthor(commits []*models.Commit, start, e
|
|||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.SetCommitAuthor)
|
||||
if err := self.c.Git().Rebase.SetCommitAuthor(commits, start, end, value); err != nil {
|
||||
if err := self.c.Git().Rebase.SetCommitAuthor(commits, start, end, parentIdx, value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1343,7 +1363,7 @@ func (self *LocalCommitsController) setAuthor(commits []*models.Commit, start, e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) addCoAuthor(commits []*models.Commit, start, end int) error {
|
||||
func (self *LocalCommitsController) addCoAuthor(commits []*models.Commit, start, end int, parentIdx int) error {
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.AddCoAuthorPromptTitle,
|
||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc(),
|
||||
|
|
@ -1353,7 +1373,7 @@ func (self *LocalCommitsController) addCoAuthor(commits []*models.Commit, start,
|
|||
HideWorkingTreeState: true,
|
||||
}, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.AddCommitCoAuthor)
|
||||
if err := self.c.Git().Rebase.AddCommitCoAuthor(commits, start, end, value); err != nil {
|
||||
if err := self.c.Git().Rebase.AddCommitCoAuthor(commits, start, end, parentIdx, value); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.RefreshFromWorker(types.RefreshOptions{})
|
||||
|
|
|
|||
|
|
@ -225,9 +225,11 @@ func (self *PatchBuildingController) discardSelectionFromCommit() error {
|
|||
|
||||
commits := self.c.Model().Commits
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
selectedCommits, _, endIdx := self.c.Contexts().LocalCommits.GetSelectedItems()
|
||||
_, parentIdx := self.c.Helpers().Commits.GetParentCommit(selectedCommits, endIdx, 1)
|
||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit)
|
||||
err := self.c.Git().Patch.DeletePatchesFromCommit(commits, commitIndex)
|
||||
err := self.c.Git().Patch.DeletePatchesFromCommit(commits, commitIndex, parentIdx)
|
||||
// Escape pops the patch-building context, so run it on the UI thread
|
||||
// before the refresh below.
|
||||
_ = self.c.GocuiGui().OnUIThreadAndWait(func() {
|
||||
|
|
|
|||
|
|
@ -1332,7 +1332,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
SetFixupMessageTooltip: "Set the message option for the fixup commit. The -C option means to use this commit's message instead of the target commit's message.",
|
||||
FixupDiscardMessage: "Fixup and discard this commit's message",
|
||||
FixupDiscardMessageTooltip: "Squash the selected commit into the commit below, discarding this commit's message.",
|
||||
SureSquashThisCommit: "Are you sure you want to squash the selected commit(s) into the commit below?",
|
||||
SureSquashThisCommit: "Are you sure you want to squash the selected commit(s) into the parent commit below?",
|
||||
Squash: "Squash",
|
||||
PickCommitTooltip: "Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase.",
|
||||
Pick: "Pick",
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ var OutsideRebaseRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
|||
Tap(func() {
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Squash")).
|
||||
Content(Contains("Are you sure you want to squash the selected commit(s) into the commit below?")).
|
||||
Content(Contains("Are you sure you want to squash the selected commit(s) into the parent commit below?")).
|
||||
Confirm()
|
||||
}).
|
||||
TopLines(
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ var SquashDownSecondCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
|||
Tap(func() {
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Squash")).
|
||||
Content(Equals("Are you sure you want to squash the selected commit(s) into the commit below?")).
|
||||
Content(Equals("Are you sure you want to squash the selected commit(s) into the parent commit below?")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
|
|
|
|||
Loading…
Reference in a new issue