From 3ecf3ae4cb1f814402d5ced0ac6340c6cf277226 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 7 Nov 2026 09:49:44 +0100 Subject: [PATCH] Add a test for a lock error partway through a cherry-pick If a lock stops a cherry-pick of several commits partway through, the git command runner runs the same "git cherry-pick" command again. This fails with "cherry-pick is already in progress", and the user is left with a cherry-pick that stopped halfway. Unlike a rebase, git doesn't reschedule the commit that failed, so continuing the cherry-pick would skip that commit. Co-Authored-By: Claude Opus 5.5 --- .../lock_error_partway_through_cherry_pick.go | 87 +++++++++++++++++++ pkg/integration/tests/test_list.go | 1 + 2 files changed, 88 insertions(+) create mode 100644 pkg/integration/tests/cherry_pick/lock_error_partway_through_cherry_pick.go diff --git a/pkg/integration/tests/cherry_pick/lock_error_partway_through_cherry_pick.go b/pkg/integration/tests/cherry_pick/lock_error_partway_through_cherry_pick.go new file mode 100644 index 000000000..b3329ab9a --- /dev/null +++ b/pkg/integration/tests/cherry_pick/lock_error_partway_through_cherry_pick.go @@ -0,0 +1,87 @@ +package cherry_pick + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" + "github.com/jesseduffield/lazygit/pkg/integration/tests/shared" +) + +var LockErrorPartwayThroughCherryPick = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Cherry pick two commits while another git process takes index.lock partway through", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().Git.LocalBranchSortOrder = "recency" + }, + SetupRepo: func(shell *Shell) { + shell. + CreateFileAndAdd("file", "original\n"). + Commit("base"). + NewBranch("source"). + CreateFileAndAdd("file1", "one\n"). + Commit("one"). + CreateFileAndAdd("file2", "two\n"). + Commit("two"). + Checkout("master") + + // The cherry-pick commits "one"; the lock then stops it when it tries + // to pick "two". + shared.HoldIndexLockAfterNextCommit(shell) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Branches(). + Focus(). + Lines( + Contains("master"), + Contains("source"), + ). + SelectNextItem(). + PressEnter() + + t.Views().SubCommits(). + IsFocused(). + Lines( + Contains("two").IsSelected(), + Contains("one"), + Contains("base"), + ). + Press(keys.Commits.CherryPickCopy). + SelectNextItem(). + Press(keys.Commits.CherryPickCopy) + + t.Views().Information().Content(Contains("2 commits copied")) + + t.Views().Commits(). + Focus(). + Lines( + Contains("base").IsSelected(), + ). + Press(keys.Commits.PasteCommits). + Tap(func() { + t.ExpectPopup().Alert(). + Title(Equals("Cherry-pick")). + Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")). + Confirm() + }). + /* EXPECTED: + Lines( + Contains("two"), + Contains("one"), + Contains("base"), + ) + ACTUAL: */ + Tap(func() { + t.ExpectPopup().Alert(). + Title(Equals("Error")). + Content(Contains("cherry-pick is already in progress")). + Confirm() + }). + Lines( + Contains("─── Pending cherry-picks"), + Contains("pick").Contains("two"), + Contains("─── Commits"), + Contains("one"), + Contains("base"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 501e9a86b..21aec9a55 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -117,6 +117,7 @@ var tests = []*components.IntegrationTest{ cherry_pick.CherryPickRange, cherry_pick.CherryPickRangeAfterPaste, cherry_pick.CherryPickStoppedByUntrackedFile, + cherry_pick.LockErrorPartwayThroughCherryPick, commit.AddCoAuthor, commit.AddCoAuthorRange, commit.AddCoAuthorWhileCommitting,