Fix sandbox exec dropping uncommitted changes with unpushed commits#366
Merged
Fix sandbox exec dropping uncommitted changes with unpushed commits#366
Conversation
ae87eca to
3cb79e5
Compare
jmsanders
previously approved these changes
Feb 19, 2026
2e1bf29 to
f9a08fd
Compare
f9a08fd to
693f95d
Compare
When sandbox exec runs on a branch with unpushed commits, the pull-back step was destroying local uncommitted changes. The sandbox diff (against HEAD) included the synced local changes, and the complex reset-and-apply logic couldn't reconcile them. Fix this by snapshotting the post-sync state as a detached ref (refs/rwx-sync) rather than leaving it on HEAD. After syncing local changes to the sandbox, we commit a snapshot, save it to refs/rwx-sync, then immediately reset HEAD back so the user's branch tip is unchanged during exec. On pull, we diff against refs/rwx-sync to capture only exec-produced changes, which apply cleanly regardless of unpushed commits. This also simplifies pullChangesFromSandbox — the local-changed-files merge and per-file reset logic is no longer needed since the diff now inherently contains only exec changes, and git apply is atomic.
693f95d to
dcdbd9e
Compare
When there are no local changes to sync, syncChangesToSandbox returned early without creating refs/rwx-sync. This meant pull would either fail (first exec) or diff against a stale ref (subsequent execs). Point the ref at the current sandbox HEAD so pull always has a valid baseline.
Split the fire-and-forget compound shell command into two checked steps so that partial failures (e.g. reset failing after update-ref) are detected and reported instead of leaving the sandbox in a bad state.
When there are no local changes, sync creates refs/rwx-sync by pointing it at HEAD. The error from this update-ref was previously silently discarded, which could leave pull without a valid baseline and produce a confusing error. Surface the failure so the root cause is clear.
…ailure Previously, refs/rwx-sync was deleted at the start of sync before the patch was applied. If sync failed between the deletion and the snapshot step, pull would have no baseline ref to diff against. Move the deletion into the snapshot command chain so the previous ref remains valid until the new snapshot is ready.
TAGraves
approved these changes
Feb 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sandbox execruns on a branch with unpushed commits, the pull-back step was destroying local uncommitted changes. The sandbox diff (against HEAD) included the synced local changes, and the complex reset-and-apply logic couldn't reconcile them.refs/rwx-sync) rather than on the branch itself. After syncing local changes, we commit a snapshot, save it torefs/rwx-sync, then immediately reset HEAD back so the user's branch tip is unchanged during exec.refs/rwx-syncto capture only exec-produced changes, which apply cleanly regardless of unpushed commits.git applyis atomic, and the diff now inherently contains only exec changes.Test plan
go test ./internal/... ./cmd/...— all unit tests passgolangci-lint run ./...— no lint issuesrun-rwx-testing-sandboxverifies uncommitted changes survive sandbox exec with unpushed commits