diff --git a/pkg/integration/tests/interactive_rebase/lock_error_partway_through_skip.go b/pkg/integration/tests/interactive_rebase/lock_error_partway_through_skip.go new file mode 100644 index 000000000..c2865aff1 --- /dev/null +++ b/pkg/integration/tests/interactive_rebase/lock_error_partway_through_skip.go @@ -0,0 +1,76 @@ +package interactive_rebase + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" + "github.com/jesseduffield/lazygit/pkg/integration/tests/shared" +) + +var LockErrorPartwayThroughSkip = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Skip in a rebase while another git process takes index.lock before the next commit is committed", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell. + CreateFileAndAdd("file", "original\n"). + Commit("base"). + UpdateFileAndAdd("file", "changed\n"). + Commit("commit to edit"). + CreateFileAndAdd("file-y", "y\n"). + Commit("add file-y"). + CreateFileAndAdd("file-z", "z\n"). + Commit("add file-z") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains("add file-z").IsSelected(), + Contains("add file-y"), + Contains("commit to edit"), + Contains("base"), + ). + NavigateToLine(Contains("commit to edit")). + Press(keys.Universal.Edit). + Lines( + Contains("─── Pending rebase todos"), + Contains("pick").Contains("add file-z"), + Contains("pick").Contains("add file-y"), + Contains("─── Commits"), + Contains("commit to edit").IsSelected(), + Contains("base"), + ) + + // After amending the commit we stopped at, git has to make a new commit + // when it picks "add file-y", rather than fast-forwarding to it. The + // lock then stops it after it has applied the changes, but before it + // has committed them. + t.Shell().RunCommand([]string{"git", "commit", "--amend", "-m", "edited commit"}) + shared.HoldIndexLockBeforeNextPickIsCommitted(t.Shell()) + + t.GlobalPress(keys.Universal.CreateRebaseOptionsMenu) + t.ExpectPopup().Menu(). + Title(Equals("Rebase options")). + Select(Contains("skip")). + Confirm() + + /* EXPECTED: + t.ExpectPopup().Alert(). + Title(Equals("Error")). + Content(Contains("index.lock': File exists.")). + Confirm() + + t.Views().Files(). + Lines( + Contains("A").Contains("file-y"), + ) + ACTUAL: */ + t.Views().Commits(). + Lines( + Contains("add file-z"), + Contains("edited commit"), + Contains("base"), + ) + }, +}) diff --git a/pkg/integration/tests/shared/index_lock.go b/pkg/integration/tests/shared/index_lock.go index 29e513f6f..c8414813f 100644 --- a/pkg/integration/tests/shared/index_lock.go +++ b/pkg/integration/tests/shared/index_lock.go @@ -30,3 +30,15 @@ func HoldIndexLockAfterNextCommit(shell *Shell) { shell.CreateFile(".git/hooks/post-commit", "#!/bin/sh\n"+holdIndexLockScript) shell.MakeExecutable(".git/hooks/post-commit") } + +// HoldIndexLockBeforeNextPickIsCommitted installs a reference-transaction hook +// that takes index.lock (see holdIndexLockScript) the next time a rebase or +// cherry-pick has applied the changes of a commit, but hasn't committed them +// yet. This is when git creates CHERRY_PICK_HEAD. +func HoldIndexLockBeforeNextPickIsCommitted(shell *Shell) { + shell.CreateFile(".git/hooks/reference-transaction", `#!/bin/sh +[ "$1" = committed ] || exit 0 +awk '$3 == "CHERRY_PICK_HEAD" && $2 !~ /^0+$/ { found = 1 } END { exit !found }' || exit 0 +`+holdIndexLockScript) + shell.MakeExecutable(".git/hooks/reference-transaction") +} diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 21aec9a55..9dc3e4ff4 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -362,6 +362,7 @@ var tests = []*components.IntegrationTest{ interactive_rebase.InteractiveRebaseOfCopiedBranch, interactive_rebase.InteractiveRebaseWithConflictForEditCommand, interactive_rebase.LockErrorPartwayThroughRebase, + interactive_rebase.LockErrorPartwayThroughSkip, interactive_rebase.MidRebaseRangeSelect, interactive_rebase.Move, interactive_rebase.MoveAcrossBranchBoundaryOutsideRebase,