fix: pin archive DerivedData to the worktree (stop the ~2 GB/ship leak) - #3
Merged
Merged
Conversation
`xcodebuild archive` was the only one of pushback's four xcodebuild invocations without a `-derivedDataPath`. It fell back to Xcode's default `~/Library/Developer/Xcode/DerivedData/<Project>-<hash>`, where the hash is derived from the .xcodeproj ABSOLUTE path. Shipping from git worktrees therefore minted a separate 2-3 GB cache per worktree path, and Xcode never reclaims those when the worktree is deleted. Found in the wild at 15 orphaned directories, ~30 GB, against 7 live worktrees, growing by one cache per ship from a fresh worktree. The archive now builds into `$APP_DIR/build/archive`, which is worktree-local by construction ($APP_DIR is $REPO_ROOT/$PUSHBACK_APP_DIR), so the cache dies with the checkout. Cleanup follows the existing VERIFY_BUILD_DIR convention: clean before use (extending the rm at the top of the archive step) and clean after use (right after the upload, before step_done). The trap is deliberately untouched, matching how the script already treats build artifacts on failure. Audited the other three call sites: verify build and test already pin to $VERIFY_BUILD_DIR; -exportArchive works off -archivePath and never touches DerivedData. No other invocation needs the flag. Tradeoff, documented in the CHANGELOG so it isn't misfiled as a regression: the final `rm -rf "$APP_DIR/build"` means the release archive is now always a cold build. Under a worktree-per-feature workflow most ships start from a fresh worktree where no cache existed to reuse, and a hermetic release archive is worth having regardless. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
What
xcodebuild archivewas the only one of pushback's fourxcodebuildinvocations without a-derivedDataPath. It fell back to Xcode's default location,~/Library/Developer/Xcode/DerivedData/<Project>-<hash>, where the hash is derived from the.xcodeprojabsolute path.Shipping from git worktrees therefore minted a separate 2 to 3 GB cache for every worktree path, and Xcode never reclaims those when the worktree is deleted. Found in the wild at 15 orphaned directories totaling ~30 GB against 7 live worktrees, growing by one cache per ship from a fresh worktree.
The archive now builds into
$APP_DIR/build/archive, which is worktree-local by construction ($APP_DIRis$REPO_ROOT/$PUSHBACK_APP_DIR), so the cache dies with the checkout.Changes
pushback— newARCHIVE_BUILD_DIR="$APP_DIR/build/archive"alongside the other path vars;-derivedDataPath "$ARCHIVE_BUILD_DIR"on the archive invocation; pre-clean extended to cover it; post-userm -rfright after the upload.CHANGELOG.md— entry under[Unreleased] → Fixed, including the build-time tradeoff.README.md— new### Build artifactssubsection under Usage (the README previously documented neither artifacts nor cleanup).Audit of the other call sites
-derivedDataPath?build(verify)$VERIFY_BUILD_DIRtest(QA)$VERIFY_BUILD_DIRarchive-exportArchive-archivePathand never touches DerivedDataOnly the archive needed the flag.
Reviewer notes
Cleanup follows the existing convention, not a new one. Clean before use (extending the
rmat the top of the archive step, mirroring therm -rf "$VERIFY_BUILD_DIR"before the verify build) and clean after use (beforestep_done, same as the verify and QA steps). Thecleanup_on_failuretrap is deliberately untouched: it handles only version-bump/push recovery and stash restore today, andVERIFY_BUILD_DIRis likewise left behind on a failed verify. The pre-clean wipes any leftover on the next run, and the directory is worktree-local either way.Dry-run. The new
rm -rfis not gated onDRY_RUN, matching all five existingrm -rfcalls in the script.run_xcodebuildshort-circuits before invoking xcodebuild in dry-run, so no DerivedData is ever produced and therm -rfis a no-op on a nonexistent path.Tradeoff (documented in the CHANGELOG so it isn't misfiled as a regression later). The existing
rm -rf "$APP_DIR/build"at the end of a successful ship means the release archive is now always a cold build; previously the default-location cache persisted and a second ship from the same path reused it. This is a deliberate trade: under a worktree-per-feature workflow most ships start from a fresh worktree where there was no cache to reuse anyway, and a hermetic release archive is worth having on its own merits. If the wall-clock cost ever bites, the escape hatch is to stop deletingbuild/archiveafter the upload and exclude it from the final sweep, giving one warm cache per live worktree, bounded by worktree count instead of unbounded.Verification
bash -nandshellcheckclean.bash -xtrace shows the archive carrying-derivedDataPath .../worktrees/pb-ddleak-verify/ios/build/archive.xcodebuildand creates no DerivedData either way. The real build put 3.2 GB entirely insidebuild/archive(Build/Products/Debug-iphonesimulator/FlipOrPass.apppresent) while~/Library/Developer/Xcode/DerivedDatastayed at 0 B.🤖 Generated with Claude Code