This commit is contained in:
JhunHong 2026-09-09 06:09:12 +00:00 committed by GitHub
commit 58cf058e80
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 138 additions and 69 deletions

View file

@ -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
}

View file

@ -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
}

View file

@ -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()
})
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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,

View file

@ -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{})

View file

@ -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() {

View file

@ -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",

View file

@ -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(

View file

@ -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(