Manage patch lifetime from the focused diff

Removing a whole or partial patch from its source commit, and replacing
a patch when the user selects another commit, must not depend on
entering a patch-building panel. Keep those state transitions covered
through the diff that now owns patch selection.

Co-Authored-By: GitHub Copilot <copilot@github.com>
This commit is contained in:
Stefan Haller
2026-10-05 11:44:42 +02:00
co-authored by GitHub Copilot
parent 8bfd86ca2c
commit f3e98ed222
5 changed files with 103 additions and 104 deletions
@@ -1,18 +1,19 @@
package patch_building
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var RemovePartsOfAddedFile = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Remove a custom patch from a file that was added in a commit",
var RemovePartOfAddedFileFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Remove a custom patch containing one line of an added file from its commit",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("first commit")
shell.CreateFileAndAdd("file1", "1st line\n2nd line\n3rd line\n")
shell.Commit("commit to remove from")
},
@@ -30,27 +31,21 @@ var RemovePartsOfAddedFile = NewIntegrationTest(NewIntegrationTestArgs{
Lines(
Contains("A file1").IsSelected(),
).
PressEnter()
Press(keys.Universal.FocusMainView)
t.Views().PatchBuilding().
t.Views().Main().
IsFocused().
SelectNextItem().
NavigateToLine(Contains("+2nd line")).
PressPrimaryAction()
t.Views().Information().Content(Contains("Building patch"))
t.Common().SelectPatchOption(Contains("Remove patch from original commit"))
t.Views().CommitFiles().
t.Views().Main().
IsFocused().
Lines(
Contains("A file1").IsSelected(),
).
PressEscape()
t.Views().Main().ContainsLines(
Equals("+1st line"),
Equals("+3rd line"),
)
ContainsLines(
Equals("+1st line"),
Equals("+3rd line"),
)
},
})
@@ -1,15 +1,17 @@
package patch_building
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var RemoveFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Remove a custom patch from a commit",
var RemovePatchFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Remove a whole-file custom patch from its original commit",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "file1 content\n")
shell.CreateFileAndAdd("file2", "file2 content\n")
@@ -30,30 +32,23 @@ var RemoveFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
Contains("file1"),
Contains("file2"),
).
SelectNextItem().
Press(keys.Universal.FocusMainView)
t.Views().Main().
IsFocused().
SelectedLines(Contains("+file1 content")).
PressPrimaryAction()
t.Views().Information().Content(Contains("Building patch"))
t.Views().Secondary().Content(Contains("+file1 content"))
t.Common().SelectPatchOption(Contains("Remove patch from original commit"))
t.Views().Files().IsEmpty()
t.Views().CommitFiles().
IsFocused().
Lines(
Contains("file2").IsSelected(),
).
PressEscape()
t.Views().Main().
IsFocused().
Content(Contains("+file2 content"))
t.Views().Commits().
Lines(
Contains("first commit").IsSelected(),
)
t.Views().Commits().Lines(
Contains("first commit").IsSelected(),
)
},
})
@@ -0,0 +1,71 @@
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var StartPatchFromAnotherCommit = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Confirm replacing a custom patch when selecting lines from another commit",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "file1 content")
shell.Commit("first commit")
shell.CreateFileAndAdd("file2", "file2 content")
shell.Commit("second commit")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("second commit").IsSelected(),
Contains("first commit"),
).
PressEnter()
t.Views().CommitFiles().
IsFocused().
Lines(
Contains("file2").IsSelected(),
).
Press(keys.Universal.FocusMainView)
t.Views().Main().
IsFocused().
SelectedLines(Contains("+file2 content")).
PressPrimaryAction()
t.Views().Information().Content(Contains("Building patch"))
t.Views().Secondary().Content(Contains("file2"))
t.Views().Main().PressEscape()
t.Views().CommitFiles().IsFocused().PressEscape()
t.Views().Commits().
IsFocused().
NavigateToLine(Contains("first commit")).
PressEnter()
t.Views().CommitFiles().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
Press(keys.Universal.FocusMainView)
t.Views().Main().
IsFocused().
SelectedLines(Contains("+file1 content")).
PressPrimaryAction()
t.ExpectPopup().Confirmation().
Title(Contains("Discard patch")).
Content(Contains("You can only build a patch from one commit/stash-entry at a time. Discard current patch?")).
Confirm()
t.Views().Secondary().Content(Contains("file1").DoesNotContain("file2"))
},
})
@@ -1,62 +0,0 @@
package patch_building
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var StartNewPatch = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Attempt to add a file from another commit to a patch, then agree to start a new patch",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "file1 content")
shell.Commit("first commit")
shell.CreateFileAndAdd("file2", "file2 content")
shell.Commit("second commit")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("second commit").IsSelected(),
Contains("first commit"),
).
PressEnter()
t.Views().CommitFiles().
IsFocused().
Lines(
Contains("file2").IsSelected(),
).
PressPrimaryAction().
Tap(func() {
t.Views().Information().Content(Contains("Building patch"))
t.Views().Secondary().Content(Contains("file2"))
}).
PressEscape()
t.Views().Commits().
IsFocused().
NavigateToLine(Contains("first commit")).
PressEnter()
t.Views().CommitFiles().
IsFocused().
Lines(
Contains("file1").IsSelected(),
).
PressPrimaryAction().
Tap(func() {
t.ExpectPopup().Confirmation().
Title(Contains("Discard patch")).
Content(Contains("You can only build a patch from one commit/stash-entry at a time. Discard current patch?")).
Confirm()
t.Views().Secondary().Content(Contains("file1").DoesNotContain("file2"))
})
},
})
+3 -3
View File
@@ -445,6 +445,8 @@ var tests = []*components.IntegrationTest{
main_view.RangeSelectDiffLines,
main_view.RawFallbackUnderAnExternalDiff,
main_view.RemoveLinesFromTheCustomPatch,
main_view.RemovePartOfAddedFileFromCommit,
main_view.RemovePatchFromCommit,
main_view.RenderTheDiffBesideThePatchMarks,
main_view.ResetAPatchBuiltFromACommitsDiff,
main_view.ResetPatchWithEscape,
@@ -477,6 +479,7 @@ var tests = []*components.IntegrationTest{
main_view.StageRangeSpanningFiles,
main_view.StageUnderConformingDiffRenderer,
main_view.StageUnderUnsupportedDiffRenderer,
main_view.StartPatchFromAnotherCommit,
main_view.UnstageDiffLines,
misc.ConfirmOnQuit,
misc.CopyConfirmationMessageToClipboard,
@@ -493,15 +496,12 @@ var tests = []*components.IntegrationTest{
misc.RecentReposWithLongNames,
misc.StartInGitDir,
patch_building.CopyRenamedFileDiff,
patch_building.RemoveFromCommit,
patch_building.RemovePartsOfAddedFile,
patch_building.RenameSimilarityThresholdChange,
patch_building.RenamedFilePartial,
patch_building.RenamedFileWhole,
patch_building.SelectAllFiles,
patch_building.SelectDirecoriesSharingPrefix,
patch_building.SpecificSelection,
patch_building.StartNewPatch,
patch_building.ToggleDirectory,
patch_building.ToggleRange,
reflog.Checkout,