From b95bfeb164724c135c899d0e01934039031a4b68 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 15 Mar 2026 14:05:09 +0100 Subject: [PATCH] Add test demonstrating problem with staging only some changed lines Given a block of consecutive changed lines, trying to stage only some of them doesn't work correctly in all cases: - if the staged lines are the last lines in the block of changes, it already works - when staging some changes in the middle of the block, it doesn't work as desired, but we also don't try to fix this case in this branch, because it's harder to do, and not as common as the other two - staging the first lines of the block doesn't work as desired, and we will fix that in this branch. --- ...ge_partial_block_of_changes_first_lines.go | 80 +++++++++++++++++++ ...age_partial_block_of_changes_last_lines.go | 68 ++++++++++++++++ ...e_partial_block_of_changes_middle_lines.go | 74 +++++++++++++++++ pkg/integration/tests/test_list.go | 3 + 4 files changed, 225 insertions(+) create mode 100644 pkg/integration/tests/staging/stage_partial_block_of_changes_first_lines.go create mode 100644 pkg/integration/tests/staging/stage_partial_block_of_changes_last_lines.go create mode 100644 pkg/integration/tests/staging/stage_partial_block_of_changes_middle_lines.go diff --git a/pkg/integration/tests/staging/stage_partial_block_of_changes_first_lines.go b/pkg/integration/tests/staging/stage_partial_block_of_changes_first_lines.go new file mode 100644 index 000000000..b737abc06 --- /dev/null +++ b/pkg/integration/tests/staging/stage_partial_block_of_changes_first_lines.go @@ -0,0 +1,80 @@ +package staging + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var StagePartialBlockOfChangesFirstLines = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Stage only the first few lines of a block of consecutive changes", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().Gui.UseHunkModeInStagingView = false + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n") + shell.Commit("one") + + shell.UpdateFile("file1", "1\n2b\n3b\n4b\n5b\n6b\n7b\n8\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Lines( + Contains("file1").IsSelected(), + ). + PressEnter() + + t.Views().Staging(). + IsFocused(). + ContainsLines( + Contains(" 1"), + Contains("-2"), + Contains("-3"), + Contains("-4"), + Contains("-5"), + Contains("-6"), + Contains("-7"), + Contains("+2b"), + Contains("+3b"), + Contains("+4b"), + Contains("+5b"), + Contains("+6b"), + Contains("+7b"), + Contains(" 8"), + ). + SelectedLines(Contains("-2")). + PressPrimaryAction(). + SelectedLines(Contains("-3")). + PressPrimaryAction(). + NavigateToLine(Contains("+2b")). + PressPrimaryAction(). + SelectedLines(Contains("+3b")). + PressPrimaryAction() + + t.Views().StagingSecondary(). + ContainsLines( + /* EXPECTED: + Contains(" 1"), + Contains("-2"), + Contains("-3"), + Contains("+2b"), + Contains("+3b"), + Contains(" 4"), + Contains(" 5"), + Contains(" 6"), + ACTUAL: */ + Contains(" 1"), + Contains("-2"), + Contains("-3"), + Contains(" 4"), + Contains(" 5"), + Contains(" 6"), + Contains(" 7"), + Contains("+2b"), + Contains("+3b"), + Contains(" 8"), + ) + }, +}) diff --git a/pkg/integration/tests/staging/stage_partial_block_of_changes_last_lines.go b/pkg/integration/tests/staging/stage_partial_block_of_changes_last_lines.go new file mode 100644 index 000000000..355b02292 --- /dev/null +++ b/pkg/integration/tests/staging/stage_partial_block_of_changes_last_lines.go @@ -0,0 +1,68 @@ +package staging + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var StagePartialBlockOfChangesLastLines = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Stage only the last few lines of a consecutive block of changes", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().Gui.UseHunkModeInStagingView = false + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n") + shell.Commit("one") + + shell.UpdateFile("file1", "1\n2b\n3b\n4b\n5b\n6b\n7b\n8\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Lines( + Contains("file1").IsSelected(), + ). + PressEnter() + + t.Views().Staging(). + IsFocused(). + ContainsLines( + Contains(" 1"), + Contains("-2"), + Contains("-3"), + Contains("-4"), + Contains("-5"), + Contains("-6"), + Contains("-7"), + Contains("+2b"), + Contains("+3b"), + Contains("+4b"), + Contains("+5b"), + Contains("+6b"), + Contains("+7b"), + Contains(" 8"), + ). + NavigateToLine(Contains("-6")). + PressPrimaryAction(). + SelectedLines(Contains("-7")). + PressPrimaryAction(). + NavigateToLine(Contains("+6b")). + PressPrimaryAction(). + SelectedLines(Contains("+7b")). + PressPrimaryAction() + + t.Views().StagingSecondary(). + ContainsLines( + Contains(" 3"), + Contains(" 4"), + Contains(" 5"), + Contains("-6"), + Contains("-7"), + Contains("+6b"), + Contains("+7b"), + Contains(" 8"), + ) + }, +}) diff --git a/pkg/integration/tests/staging/stage_partial_block_of_changes_middle_lines.go b/pkg/integration/tests/staging/stage_partial_block_of_changes_middle_lines.go new file mode 100644 index 000000000..085c188a9 --- /dev/null +++ b/pkg/integration/tests/staging/stage_partial_block_of_changes_middle_lines.go @@ -0,0 +1,74 @@ +package staging + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var StagePartialBlockOfChangesMiddleLines = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Stage only the middle lines of a consecutive block of changes", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().Gui.UseHunkModeInStagingView = false + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file1", "1\n2\n3\n4\n5\n6\n7\n8\n") + shell.Commit("one") + + shell.UpdateFile("file1", "1\n2b\n3b\n4b\n5b\n6b\n7b\n8\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Lines( + Contains("file1").IsSelected(), + ). + PressEnter() + + t.Views().Staging(). + IsFocused(). + ContainsLines( + Contains(" 1"), + Contains("-2"), + Contains("-3"), + Contains("-4"), + Contains("-5"), + Contains("-6"), + Contains("-7"), + Contains("+2b"), + Contains("+3b"), + Contains("+4b"), + Contains("+5b"), + Contains("+6b"), + Contains("+7b"), + Contains(" 8"), + ). + NavigateToLine(Contains("-4")). + PressPrimaryAction(). + SelectedLines(Contains("-5")). + PressPrimaryAction(). + NavigateToLine(Contains("+4b")). + PressPrimaryAction(). + SelectedLines(Contains("+5b")). + PressPrimaryAction() + + t.Views().StagingSecondary(). + // This is not the desired result, ideally the added lines would come right after the + // deleted lines. However, this is hard to do, and it's a lot less common than staging + // either the first lines or last lines of a block of changes, so we live with the + // imperfection for now (but document it with a test here). + ContainsLines( + Contains(" 1"), + Contains(" 2"), + Contains(" 3"), + Contains("-4"), + Contains("-5"), + Contains(" 6"), + Contains(" 7"), + Contains("+4b"), + Contains("+5b"), + Contains(" 8"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index c336cce1f..ba4c5b32b 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -379,6 +379,9 @@ var tests = []*components.IntegrationTest{ staging.Search, staging.StageHunks, staging.StageLines, + staging.StagePartialBlockOfChangesFirstLines, + staging.StagePartialBlockOfChangesLastLines, + staging.StagePartialBlockOfChangesMiddleLines, staging.StageRanges, stash.Apply, stash.ApplyPatch,