Skip to content

Commit

Permalink
Retry on index.lock error
Browse files Browse the repository at this point in the history
I don't know why we're getting index.lock errors but they're impossile to stop
anyway given that other processes can be calling git commands. So we're retrying
a few times before re-raising. To do this we need to clone the command and the current
implementation for that is best-effort.

I do worry about the maintainability of that but we'll see how it goes.
  • Loading branch information
jesseduffield committed Jul 10, 2023
1 parent d44d164 commit c22513b
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
24 changes: 23 additions & 1 deletion pkg/commands/git_cmd_obj_runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package commands

import (
"strings"
"time"

"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/sirupsen/logrus"
)
Expand All @@ -18,7 +21,26 @@ func (self *gitCmdObjRunner) Run(cmdObj oscommands.ICmdObj) error {
}

func (self *gitCmdObjRunner) RunWithOutput(cmdObj oscommands.ICmdObj) (string, error) {
return self.innerRunner.RunWithOutput(cmdObj)
// TODO: have this retry logic in other places we run the command
waitTime := 50 * time.Millisecond
retryCount := 5

var output string
var err error
for i := 0; i < retryCount; i++ {
newCmdObj := cmdObj.Clone()
output, err = self.innerRunner.RunWithOutput(newCmdObj)

if err == nil || !strings.Contains(output, ".git/index.lock") {
return output, err
}

// if we have an error based on the index lock, we should wait a bit and then retry
self.log.Warn("index.lock prevented command from running. Retrying command after a small wait")
time.Sleep(waitTime)
}

return output, err
}

func (self *gitCmdObjRunner) RunWithOutputs(cmdObj oscommands.ICmdObj) (string, string, error) {
Expand Down
20 changes: 20 additions & 0 deletions pkg/commands/oscommands/cmd_obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type ICmdObj interface {

GetCredentialStrategy() CredentialStrategy
GetTask() gocui.Task

Clone() ICmdObj
}

type CmdObj struct {
Expand Down Expand Up @@ -215,3 +217,21 @@ func (self *CmdObj) GetCredentialStrategy() CredentialStrategy {
func (self *CmdObj) GetTask() gocui.Task {
return self.task
}

func (self *CmdObj) Clone() ICmdObj {
newCmdObj := &CmdObj{}
*newCmdObj = *self
newCmdObj.cmd = cloneCmd(self.cmd)
if self.task != nil {
// TODO: clone the task as well. We can't re-use tasks once they've been completed.
panic("Cannot clone a command object that has a task, not yet implemented")
}
return newCmdObj
}

func cloneCmd(cmd *exec.Cmd) *exec.Cmd {
clone := &exec.Cmd{}
*clone = *cmd

return clone
}
2 changes: 1 addition & 1 deletion pkg/integration/tests/file/discard_changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
var DiscardChanges = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Discarding all possible permutations of changed files",
ExtraCmdArgs: []string{},
Skip: true, // failing due to index.lock file being created
Skip: false,
SetupConfig: func(config *config.AppConfig) {
},
SetupRepo: func(shell *Shell) {
Expand Down

0 comments on commit c22513b

Please sign in to comment.