Cloud agent env clones: use --filter=blob:none instead of --filter=tree:0 - #15281
Cloud agent env clones: use --filter=blob:none instead of --filter=tree:0#15281warp-agent-staging[bot] wants to merge 2 commits into
Conversation
…ee:0 Treeless partial clones (--filter=tree:0) omit tree objects, so any history walk against a path (git log -- <path>, git log -p/--stat/ --follow, git blame, git show) lazily refetches trees from the promisor remote once per commit visited. Each fetch reprints a full clone-style progress banner, which looks like repos being cloned in a loop, and the command effectively never finishes. Switch the clone and the matching pinned-ref fetch to --filter=blob:none. Blobless clones still omit file contents, so setup keeps most of its speed benefit, but they carry all trees, which makes path-limited history, git blame, and git show --stat fully local. Fixes APP-5509.
|
This PR was generated with Warp. Comment |
There was a problem hiding this comment.
Overview
Switches cloud agent environment clones from --filter=tree:0 to --filter=blob:none so path-limited history stops refetching trees per commit. Two further findings (an inaccurate doc-comment rationale and missing regression coverage) are already back with the author for revision; the one below needs your decision, so this review is neither an approval nor a rejection.
Concerns
- The clone step skips repo directories that already exist, so every already-provisioned or snapshotted environment keeps
remote.origin.partialclonefilter=tree:0indefinitely — including the environment whose run triggered this fix. Only newly created environments get the fix, and the PR records that gap without a migration or a tracked follow-up. Decide whether environment recreation is an acceptable rollout boundary: if it is, this needs a communicated operational follow-up, and if it is not, the clone path needs safe detection and reprovisioning of existing treeless clones without disturbing user-owned working trees.
Verdict
Checks: build pass, tests pass (author-run; the reviewer's local cargo nextest was killed by a runner memory limit), CI pending (15 passed, 10 skipped, 6 pending, none failing), visual proof n/a
Found: 0 critical, 0 important, 0 suggestions, 0 nits, 1 question
Responding as wilson: Open session · View factory task
Review found two issues in the initial blob:none change: - The doc comment on checkout_command_for (and the matching comment in clone_repo) claimed a partial clone 'only fetches the default branch', which is false: a plain git clone fetches all remote branches by default. The real reason the pinned-ref fetch is needed is that the requested SHA, branch, or tag may not have existed yet, or may have moved, by the time the clone ran. - None of the existing tests would catch a regression back to --filter=tree:0: the string-matching assertions just pin the literal filter value, and the real-git fixture tests only exercise fetch-then-checkout, which passes under either filter. Added blobless_clone_walks_path_limited_history_without_network, which clones with blob:none, repoints origin at an unreachable URL, and asserts a path-limited git log still completes locally. Verified manually that flipping the test's clone filter back to tree:0 makes it fail (git tries to fetch a missing tree from the now-unreachable promisor remote and errors out immediately).


Description
Cloud agent environment prep clones every source repo as a treeless partial clone (
git clone --filter=tree:0).--filter=tree:0omits tree objects, not just blobs, so any history walk against a path (git log -- <path>,git log -p/--stat/--follow,git blame,git show) lazily refetches trees from the promisor remote once per commit visited. Each lazy fetch reprints a full clone-style progress banner (remote: Enumerating objects… Receiving objects…), which is indistinguishable from a repo being cloned in a loop, and the command effectively never finishes.This was reported in Slack after a factory run appeared to hang with continuous "cloning" output while running
git log. Root-caused and tracked in APP-5509.This PR switches the clone and the matching pinned-ref fetch from
--filter=tree:0to--filter=blob:none. Blobless clones still omit file contents (most of the setup-time win is preserved), but they carry all trees, so path-limited history,git blame, andgit show --statare fully local and no longer trigger lazy refetches.Changes
app/src/ai/agent_sdk/driver/environment.rs: switch all four--filter=tree:0sites (parallel clone, parallel pinned-ref fetch, single-repo clone, single-repo pinned-ref fetch incheckout_command_for) to--filter=blob:none.git clonefetches all remote branches by default. The real reason the pinned-ref fetch is needed is that the requested SHA, branch, or tag may not have existed yet, or may have moved, by the time the clone ran.)app/src/ai/agent_sdk/driver/environment_tests.rsassertions and the real-git fixture helper (partial_clone) to match the new filter string.blobless_clone_walks_path_limited_history_without_network: a regression test that clones withblob:none, repointsoriginat an unreachable URL, and asserts a path-limitedgit logstill completes locally. It fails fast if the filter regresses totree:0(verified manually).Rollout shape: the clone path skips repos whose directory already exists ("Repository directory already exists, skipping clone..."). Any already-provisioned or snapshotted environment will keep its existing treeless clone until it is re-created from scratch — this change only affects newly-created environments.
Linked Issue
Testing
./script/format --checkandcargo clippy -p warp --all-targets --tests -- -D warningspass.cargo nextest run -p warp -E 'test(parallel_clone) or test(checkout_command) or test(checkout_result) or test(single_repo_checkout) or test(blobless_clone) or test(no_checkout_ref)': 13/13 pass, including the real-git fixture tests that exercise the actual fetch-then-checkout commands and the new regression test.Filter tradeoff measurements
Fresh clones of both repos, run back-to-back from this environment (network conditions vary run to run, but the relative deltas are representative):
.gitsizetree:0blob:nonetree:0blob:none.gitsize grows modestly (+5% for warp, +26% for warp-server) since trees are now retained. Clone wall time is noisier — network variance dominated the small absolute times here — but the on-disk cost of carrying trees is small relative to the multi-hundred-MB working tree either way.Demonstrating the fix
Before (in a
--filter=tree:0clone of warp-server):30 seconds, killed by timeout, 56 "cloning-looking" refetch banners for a query that should return instantly.
After (in a
--filter=blob:noneclone of the same repo):5 milliseconds, correct output, zero refetch chatter.
I also reproduced the original symptom directly: this very
/workspace/warpcheckout is itself atree:0clone (remote.origin.partialclonefilter=tree:0), and runninggit log -- app/src/ai/agent_sdk/driver/environment.rsagainst it produced the same runaway refetch output described in the report.Agent Mode
CHANGELOG-BUG-FIX: Cloud agent environments no longer hang with runaway "cloning" output when running
git log,git blame, or other path-limited history commands.