diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-05-20 19:45:27 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-05-20 19:45:27 +0000 |
| commit | 69208e618b0084ec18932120197f94bab98b713d (patch) | |
| tree | 35a10830c1da331f15f6030f98f9a2df77c36e6f | |
| parent | 4bef835671542d5785c7dc6229662b9d5b0053f8 (diff) | |
fix: use git tracking branch instead of hardcoded origin/master in teardownSandbox
Replace explicit 'git pull --rebase origin master' with 'git pull --rebase'
(no remote/branch), which uses the upstream configured by git clone. This
correctly handles repos where the default branch is 'main', 'trunk', or
any other name — not just 'master'.
Also apply gitSafe flags (-c safe.directory=* -c commit.gpgsign=false etc)
consistently to the status, push, pull, and log commands in teardownSandbox
that were missing them.
The variable-shadowing bug noted in CLAUDE.md was already resolved in the
github/main merge (both setupSandbox calls used '=' not ':='); strike it
from the docs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | CLAUDE.md | 4 | ||||
| -rw-r--r-- | internal/executor/claude.go | 12 |
2 files changed, 9 insertions, 7 deletions
@@ -114,9 +114,9 @@ When `agent.project_dir` is set: 4. On failure the sandbox is preserved and its path is returned in the error. 5. On BLOCKED (question written), the sandbox path is stored in `executions.sandbox_dir` so the resume execution can reuse it. -> **Known bug:** Variable shadowing in `claude.go` `Run()` means the outer `sandboxDir` is never assigned (both `setupSandbox` calls use `:=` inside nested blocks). This causes: (a) `teardownSandbox` is never called — work is discarded, sandboxes accumulate in `/tmp`; (b) `BlockedError.SandboxDir` is always `""`, so resume clones a fresh sandbox and loses the agent's partial work. See [Known Bugs](#known-bugs). +> ~~**Known bug:** Variable shadowing in `claude.go` `Run()` — fixed in github/main merge; both `setupSandbox` calls correctly use `=` (assign to outer `sandboxDir`).~~ -> **Known bug:** `teardownSandbox` hardcodes `origin/master` when rebasing on conflict. Repos using `main` will fail on concurrent push. See [Known Bugs](#known-bugs). +> ~~**Known bug:** `teardownSandbox` hardcodes `origin/master` — fixed; now uses `git pull --rebase` with no branch arg, which follows the configured upstream from `git clone`.~~ ### Task YAML Format diff --git a/internal/executor/claude.go b/internal/executor/claude.go index 3c87f26..7b70486 100644 --- a/internal/executor/claude.go +++ b/internal/executor/claude.go @@ -248,7 +248,7 @@ func setupSandbox(projectDir string, logger *slog.Logger) (string, error) { // from mixed-owner .git/objects directories. func teardownSandbox(projectDir, sandboxDir, startHEAD string, logger *slog.Logger, execRecord *storage.Execution) error { // Automatically commit uncommitted changes. - out, err := exec.Command("git", "-C", sandboxDir, "status", "--porcelain").Output() + out, err := exec.Command("git", gitSafe("-C", sandboxDir, "status", "--porcelain")...).Output() if err != nil { return fmt.Errorf("git status: %w", err) } @@ -327,16 +327,18 @@ func teardownSandbox(projectDir, sandboxDir, startHEAD string, logger *slog.Logg } // Push from sandbox → bare repo (sandbox's origin is the bare repo). - if out, err := exec.Command("git", "-C", sandboxDir, "push", "origin", "HEAD").CombinedOutput(); err != nil { + if out, err := exec.Command("git", gitSafe("-C", sandboxDir, "push", "origin", "HEAD")...).CombinedOutput(); err != nil { // If rejected due to concurrent push, fetch+rebase and retry once. + // Use `git pull --rebase` without explicit remote/branch so git uses the + // configured upstream (set by clone), handling both main- and master-based repos. if strings.Contains(string(out), "fetch first") || strings.Contains(string(out), "non-fast-forward") { logger.Info("push rejected (concurrent task); rebasing and retrying", "sandbox", sandboxDir) - if out2, err2 := exec.Command("git", "-C", sandboxDir, "pull", "--rebase", "origin", "master").CombinedOutput(); err2 != nil { + if out2, err2 := exec.Command("git", gitSafe("-C", sandboxDir, "pull", "--rebase")...).CombinedOutput(); err2 != nil { return fmt.Errorf("git rebase before retry push: %w\n%s", err2, out2) } // Re-capture commits after rebase (hashes might have changed) execRecord.Commits = nil - logOut, logErr = exec.Command("git", "-C", sandboxDir, "log", logRange, "--pretty=format:%H|%s").Output() + logOut, logErr = exec.Command("git", gitSafe("-C", sandboxDir, "log", logRange, "--pretty=format:%H|%s")...).Output() if logErr == nil { lines := strings.Split(strings.TrimSpace(string(logOut)), "\n") for _, line := range lines { @@ -350,7 +352,7 @@ func teardownSandbox(projectDir, sandboxDir, startHEAD string, logger *slog.Logg } } - if out3, err3 := exec.Command("git", "-C", sandboxDir, "push", "origin", "HEAD").CombinedOutput(); err3 != nil { + if out3, err3 := exec.Command("git", gitSafe("-C", sandboxDir, "push", "origin", "HEAD")...).CombinedOutput(); err3 != nil { return fmt.Errorf("git push to origin (after rebase): %w\n%s", err3, out3) } } else { |
