git: add retry logic for checked out branch conflicts
Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: se1c139889d8c3e3fk
diff --git a/loop/agent.go b/loop/agent.go
index 2398526..b3fd6c4 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -1540,17 +1540,51 @@
commits = append(commits, headCommit)
}
- branch := cmp.Or(a.branchName, "sketch/"+a.config.SessionID)
+ originalBranch := cmp.Or(a.branchName, "sketch/"+a.config.SessionID)
+ branch := originalBranch
// TODO: I don't love the force push here. We could see if the push is a fast-forward, and,
// if it's not, we could make a backup with a unique name (perhaps append a timestamp) and
// then use push with lease to replace.
- cmd = exec.Command("git", "push", "--force", a.gitRemoteAddr, "HEAD:refs/heads/"+branch)
- cmd.Dir = a.workingDir
- if out, err := cmd.CombinedOutput(); err != nil {
+
+ // Try up to 10 times with different branch names if the branch is checked out on the remote
+ var out []byte
+ var err error
+ for retries := range 10 {
+ if retries > 0 {
+ // Add a numeric suffix to the branch name
+ branch = fmt.Sprintf("%s%d", originalBranch, retries)
+ }
+
+ cmd = exec.Command("git", "push", "--force", a.gitRemoteAddr, "HEAD:refs/heads/"+branch)
+ cmd.Dir = a.workingDir
+ out, err = cmd.CombinedOutput()
+
+ if err == nil {
+ // Success! Break out of the retry loop
+ break
+ }
+
+ // Check if this is the "refusing to update checked out branch" error
+ if !strings.Contains(string(out), "refusing to update checked out branch") {
+ // This is a different error, so don't retry
+ break
+ }
+
+ // If we're on the last retry, we'll report the error
+ if retries == 9 {
+ break
+ }
+ }
+
+ if err != nil {
a.pushToOutbox(ctx, errorMessage(fmt.Errorf("git push to host: %s: %v", out, err)))
} else {
headCommit.PushedBranch = branch
+ // Update the agent's branch name if we ended up using a different one
+ if branch != originalBranch {
+ a.branchName = branch
+ }
}
}