mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-11-06 13:00:59 -04:00
Disable moving a patch between a merge commit and another commit
If the patch comes from a merge commit, moving it to a later commit leaves the user in a rebase that is stuck before its first todo. Moving it to an earlier commit, or into a new commit before the merge, finishes, but with surprising results. The rebase doesn't replay a merge commit; it recreates it from its parents. If the patch contains changes from the merged branch, the commits on that branch that made them become empty. And a new commit "before" the merge ends up at the tip of the merged branch. Moving a patch to a later merge commit gets stuck in the same way. Moving a patch to a merge commit isn't useful in either direction, so disable both. The other patch commands amend the merge commit itself and work fine, so they stay enabled. They are useful for removing changes that were added to a merge commit by accident. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
9383172a6c
commit
e8261e06d1
@@ -48,6 +48,11 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
||||
}
|
||||
|
||||
if self.c.Git().Patch.PatchBuilder.CanRebase && self.c.Git().Status.WorkingTreeState().None() {
|
||||
var disabledReasonForMergeCommit *types.DisabledReason
|
||||
if self.isPatchFromMergeCommit() {
|
||||
disabledReasonForMergeCommit = &types.DisabledReason{Text: self.c.Tr.NotSupportedForPatchFromMergeCommit}
|
||||
}
|
||||
|
||||
menuItems = append(menuItems, []*types.MenuItem{
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.RemovePatchFromOriginalCommit, utils.ShortHash(self.c.Git().Patch.PatchBuilder.To)),
|
||||
@@ -68,10 +73,11 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
||||
Keys: menuKey('n'),
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.MovePatchIntoNewCommitBefore,
|
||||
Tooltip: self.c.Tr.MovePatchIntoNewCommitBeforeTooltip,
|
||||
OnPress: self.handlePullPatchIntoNewCommitBefore,
|
||||
Keys: menuKey('N'),
|
||||
Label: self.c.Tr.MovePatchIntoNewCommitBefore,
|
||||
Tooltip: self.c.Tr.MovePatchIntoNewCommitBeforeTooltip,
|
||||
OnPress: self.handlePullPatchIntoNewCommitBefore,
|
||||
Keys: menuKey('N'),
|
||||
DisabledReason: disabledReasonForMergeCommit,
|
||||
},
|
||||
}...)
|
||||
|
||||
@@ -79,7 +85,10 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
|
||||
selectedCommit := self.c.Contexts().LocalCommits.GetSelected()
|
||||
if selectedCommit != nil && self.c.Git().Patch.PatchBuilder.To != selectedCommit.Hash() {
|
||||
|
||||
var disabledReason *types.DisabledReason
|
||||
disabledReason := disabledReasonForMergeCommit
|
||||
if selectedCommit.IsMerge() {
|
||||
disabledReason = &types.DisabledReason{Text: self.c.Tr.CannotMovePatchToMergeCommit}
|
||||
}
|
||||
if self.c.Contexts().LocalCommits.AreMultipleItemsSelected() {
|
||||
disabledReason = &types.DisabledReason{Text: self.c.Tr.RangeSelectNotSupported}
|
||||
}
|
||||
@@ -123,6 +132,11 @@ func (self *CustomPatchOptionsMenuAction) getPatchCommitIndex() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func (self *CustomPatchOptionsMenuAction) isPatchFromMergeCommit() bool {
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
return commitIndex != -1 && self.c.Model().Commits[commitIndex].IsMerge()
|
||||
}
|
||||
|
||||
func (self *CustomPatchOptionsMenuAction) handleDeletePatchFromCommit() error {
|
||||
commits := self.c.Model().Commits
|
||||
commitIndex := self.getPatchCommitIndex()
|
||||
|
||||
@@ -1013,6 +1013,8 @@ type TranslationSet struct {
|
||||
RangeSelectUp string
|
||||
RangeSelectDown string
|
||||
RangeSelectNotSupported string
|
||||
NotSupportedForPatchFromMergeCommit string
|
||||
CannotMovePatchToMergeCommit string
|
||||
NoItemSelected string
|
||||
SelectedItemIsNotABranch string
|
||||
SelectedItemDoesNotHaveFiles string
|
||||
@@ -2230,6 +2232,8 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
RangeSelectUp: "Range select up",
|
||||
RangeSelectDown: "Range select down",
|
||||
RangeSelectNotSupported: "Action does not support range selection, please select a single item",
|
||||
NotSupportedForPatchFromMergeCommit: "Not supported for a patch from a merge commit",
|
||||
CannotMovePatchToMergeCommit: "Cannot move a patch to a merge commit",
|
||||
NoItemSelected: "No item selected",
|
||||
SelectedItemIsNotABranch: "Selected item is not a branch",
|
||||
SelectedItemDoesNotHaveFiles: "Selected item does not have files to view",
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package main_view
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var DisableMovingPatchFromMergeCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Moving a patch from a merge commit to another commit, or into a new commit before it, is disabled",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
NewBranch("main-branch").
|
||||
CreateFileAndAdd("file1", "file1 content\n").
|
||||
Commit("first commit").
|
||||
NewBranch("feature").
|
||||
CreateFileAndAdd("file2", "file2 content\n").
|
||||
Commit("feature commit").
|
||||
Checkout("main-branch").
|
||||
CreateFileAndAdd("file3", "file3 content\n").
|
||||
Commit("main commit").
|
||||
Merge("feature")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("Merge branch 'feature' into main-branch").IsSelected(),
|
||||
Contains("feature commit"),
|
||||
Contains("main commit"),
|
||||
Contains("first commit"),
|
||||
).
|
||||
PressEnter()
|
||||
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("file2").IsSelected(),
|
||||
).
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
NavigateToLine(Contains("first commit"))
|
||||
|
||||
t.GlobalPress(keys.Universal.CreatePatchOptionsMenu)
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Patch options")).
|
||||
Select(Contains("Move patch to selected commit")).
|
||||
Tooltip(Contains("Disabled: Not supported for a patch from a merge commit")).
|
||||
Select(Contains("Move patch into new commit before the original commit")).
|
||||
Tooltip(Contains("Disabled: Not supported for a patch from a merge commit")).
|
||||
Cancel()
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,71 @@
|
||||
package main_view
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var DisableMovingPatchToMergeCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Moving a patch to an earlier or later merge commit is disabled",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
NewBranch("main-branch").
|
||||
CreateFileAndAdd("file1", "file1 content\n").
|
||||
Commit("first commit").
|
||||
NewBranch("feature").
|
||||
CreateFileAndAdd("file2", "file2 content\n").
|
||||
Commit("feature commit").
|
||||
Checkout("main-branch").
|
||||
CreateFileAndAdd("file3", "file3 content\n").
|
||||
Commit("main commit").
|
||||
Merge("feature").
|
||||
CreateFileAndAdd("file4", "file4 content\n").
|
||||
Commit("top commit")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
checkMovingPatchToMergeCommitIsDisabled := func(commitToMoveFrom string, file string) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
NavigateToLine(Contains(commitToMoveFrom)).
|
||||
PressEnter()
|
||||
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains(file).IsSelected(),
|
||||
).
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Information().Content(Contains("Building patch"))
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
NavigateToLine(Contains("Merge branch 'feature' into main-branch"))
|
||||
|
||||
t.GlobalPress(keys.Universal.CreatePatchOptionsMenu)
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Patch options")).
|
||||
Select(Contains("Move patch to selected commit")).
|
||||
Tooltip(Contains("Disabled: Cannot move a patch to a merge commit")).
|
||||
Cancel()
|
||||
|
||||
t.Common().ResetCustomPatch()
|
||||
}
|
||||
|
||||
t.Views().Commits().
|
||||
Lines(
|
||||
Contains("top commit").IsSelected(),
|
||||
Contains("Merge branch 'feature' into main-branch"),
|
||||
Contains("feature commit"),
|
||||
Contains("main commit"),
|
||||
Contains("first commit"),
|
||||
)
|
||||
|
||||
checkMovingPatchToMergeCommitIsDisabled("top commit", "file4")
|
||||
checkMovingPatchToMergeCommitIsDisabled("main commit", "file3")
|
||||
},
|
||||
})
|
||||
@@ -407,6 +407,8 @@ var tests = []*components.IntegrationTest{
|
||||
main_view.CopySelectedDiffLines,
|
||||
main_view.CustomPatchGoesThroughTheDiffRenderer,
|
||||
main_view.CustomPatchIgnoresLineEndingConversion,
|
||||
main_view.DisableMovingPatchFromMergeCommit,
|
||||
main_view.DisableMovingPatchToMergeCommit,
|
||||
main_view.DiscardAllChanges,
|
||||
main_view.DiscardDiffLines,
|
||||
main_view.DiscardFromACommitOnlyWhereItCanBeRewritten,
|
||||
|
||||
Reference in New Issue
Block a user