Fix index.lock error when committing with editor and there are no staged files (#6202)

If you commit with `shift-C` ("Commit changes using git editor") while
no files are staged, lazygit asks whether to stage all files. Confirming
this often fails with "fatal: Unable to create '.../.git/index.lock':
File exists". This is caused by the refresh of the Files view after the
stage-all, which runs `git status` on a worker. Fix this by waiting for
that refresh to be finished before calling `git commit`.

Committing with `c` didn't run into this in practice, because the
refresh is done long before the user has typed a commit message.
This commit is contained in:
Stefan Haller
2026-11-10 14:06:21 +01:00
committed by GitHub
3 changed files with 59 additions and 16 deletions
@@ -274,15 +274,7 @@ func (self *WorkingTreeHelper) WithEnsureCommittableFiles(handler func() error)
}
if self.c.UserConfig().Gui.SkipNoStagedFilesWarning {
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
if err := self.c.Git().WorkingTree.StageAll(false); err != nil {
return err
}
self.c.Refresh(types.RefreshOptions{
Scope: []types.RefreshableView{types.FILES},
Then: handler,
})
return nil
return self.stageAllAndThen(handler)
}
return self.promptToStageAllAndRetry(handler)
@@ -291,18 +283,24 @@ func (self *WorkingTreeHelper) WithEnsureCommittableFiles(handler func() error)
return handler()
}
func (self *WorkingTreeHelper) stageAllAndThen(then func() error) error {
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
if err := self.c.Git().WorkingTree.StageAll(false); err != nil {
return err
}
self.c.Refresh(types.RefreshOptions{
Scope: []types.RefreshableView{types.FILES},
Then: then,
})
return nil
}
func (self *WorkingTreeHelper) promptToStageAllAndRetry(retry func() error) error {
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.NoFilesStagedTitle,
Prompt: self.c.Tr.NoFilesStagedPrompt,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
if err := self.c.Git().WorkingTree.StageAll(false); err != nil {
return err
}
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
return retry()
return self.stageAllAndThen(retry)
},
})
@@ -0,0 +1,44 @@
package commit
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var CommitInEditorWithNothingStaged = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Commit using the git editor with nothing staged, confirming to stage all files",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.ShowFileTree = false
},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("first commit")
shell.CreateFile("file1", "file1 content")
shell.CreateFile("file2", "file2 content")
shell.SetConfig("core.editor", "sh -c 'echo my commit message >.git/COMMIT_EDITMSG'")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Equals("?? file1").IsSelected(),
Equals("?? file2"),
).
Press(keys.Files.CommitChangesWithEditor).
Tap(func() {
t.ExpectPopup().Confirmation().
Title(Equals("No files staged")).
Content(Equals("You have not staged any files. Commit all files?")).
Confirm()
}).
IsEmpty()
t.Views().Commits().
Lines(
Contains("my commit message"),
Contains("first commit"),
)
},
})
+1
View File
@@ -145,6 +145,7 @@ var tests = []*components.IntegrationTest{
commit.Commit,
commit.CommitAllWithNestedRepository,
commit.CommitDuringSquashMerge,
commit.CommitInEditorWithNothingStaged,
commit.CommitMultiline,
commit.CommitSkipHooks,
commit.CommitSwitchToEditor,