Interactive Rebase & Worktrees
A cookbook for parallel SDK upgrade spikes using git worktree and interactive rebase - so expo upgrade does not freeze main and your stash list does not become archaeology.
Search across all documentation pages
A cookbook for parallel SDK upgrade spikes using git worktree and interactive rebase - so expo upgrade does not freeze main and your stash list does not become archaeology.
Quick-reference recipe card - copy-paste ready.
# From primary clone - add SDK spike worktree (sibling directory)
cd ~/WEBDEV/ShipApp
git fetch origin
git worktree add ../ShipApp-sdk57-spike -b spike/sdk-57-upgrade origin/main# Spike worktree - upgrade in isolation
cd ../ShipApp-sdk57-spike
npm ci
npx expo install expo@~57.0.4 --fix
npx expo-doctor
npm run typecheck && npm run test -- --ci# Primary clone - keep shipping features on main
cd ~/WEBDEV/ShipApp
git checkout main
git checkout -b feat/SHIP-501-settings-redesign
# Metro on default 8081 - spike uses 8082 (see below)# Before PR - squash fixup commits on feature branch
git checkout feat/SHIP-501-settings-redesign
git fetch origin && git rebase -i origin/main
# Mark WIP commits as squash/fixup; keep one feat commit# After spike validated - remove worktree
cd ~/WEBDEV/ShipApp
git worktree remove ../ShipApp-sdk57-spikeWhen to reach for this:
main.npm ci.When to avoid:
release/* or hotfix/* branches others have checked out - rebase rewrites history.node_modules trees cost gigabytes.Scenario: ShipApp runs Expo SDK 56 in production. Team needs SDK 57 spike while feat/* branches land daily on main.
Step 1 - Create spike worktree
cd ~/WEBDEV/ShipApp
git pull --ff-only origin main
git worktree add ../ShipApp-sdk57-spike -b spike/sdk-57-upgrade origin/main
git worktree list/Users/csjcode/WEBDEV/ShipApp abc1234 [main]
/Users/csjcode/WEBDEV/ShipApp-sdk57-spike abc1234 [spike/sdk-57-upgrade]Both directories share one .git object store - branches differ, disks separate.
Step 2 - Isolate Metro ports
# ../ShipApp-sdk57-spike/.env.local (gitignored)
EXPO_PACKAGER_PORT=8082cd ../ShipApp-sdk57-spike
npm ci
npx expo start --port 8082Primary clone keeps npx expo start on 8081 - no "port already in use" collisions.
Step 3 - Run upgrade with checkpoint commits
cd ../ShipApp-sdk57-spike
npx expo install expo@~57.0.4 --fix
git add package.json package-lock.json
git commit -m "chore(sdk): bump expo to SDK 57 [SPIKE-57]"
npx expo prebuild --clean
git add ios android
git commit -m "chore(native): prebuild after SDK 57 [SPIKE-57]"
npm run typecheck
# fix breaks...
git commit -am "fix(types): navigation params after RN 0.86 [SPIKE-57]"WIP commits are fine on spike branch - interactive rebase before opening PR.
Step 4 - Parallel feature work in primary clone
cd ~/WEBDEV/ShipApp
git checkout -b feat/SHIP-501-settings-redesign
# unaffected by spike's package.json - separate node_modules
npm ci
npm run test -- --ci
git push -u origin feat/SHIP-501-settings-redesignTeammates never pull half-upgraded SDK from main.
Step 5 - Interactive rebase before PR
Feature branch accumulated noise:
git checkout feat/SHIP-501-settings-redesign
git log --oneline origin/main..HEADa1b2c3d fix typo
d4e5f6g fix lint
g7h8i9j feat(settings): redesign layout [SHIP-501]
j1k2l3m wipgit rebase -i origin/mainIn the editor, reorder and mark:
pick g7h8i9j feat(settings): redesign layout [SHIP-501]
squash j1k2l3m wip
squash d4e5f6g fix lint
squash a1b2c3d fix typogit push --force-with-lease origin feat/SHIP-501-settings-redesign--force-with-lease - safer than --force; fails if remote advancedmain, release/*, hotfix/*Step 6 - Finish spike and land on main
cd ../ShipApp-sdk57-spike
npm run lint && npm run typecheck && npm run test -- --ci
npx expo-doctorSquash spike commits for review:
git rebase -i origin/main
# squash all SPIKE-57 commits into one:
# chore(sdk): upgrade to Expo SDK 57 [SPIKE-57]git push -u origin spike/sdk-57-upgrade
# Open PR → main; full device matrix + EAS preview build requiredAfter merge:
cd ~/WEBDEV/ShipApp
git pull --ff-only origin main
git worktree remove ../ShipApp-sdk57-spike
git branch -d spike/sdk-57-upgrade # if mergedTrigger preview build on PR for SDK PRs - Expo Go alone misses native changes.
| Branch type | Interactive rebase? | Force push? |
|---|---|---|
feat/* (solo) | Yes | --force-with-lease OK |
spike/* | Yes | --force-with-lease OK |
main | No | Never |
release/* | No | Breaks RC audit |
hotfix/* | No | Cherry-pick instead |
Shared feat/* | Coordinate | Prefer merge |
# Abort a rebase gone wrong
git rebase --abort
# Recovery reflog
git reflog | head -20
git checkout -b recovery-branch HEAD@{3}git worktree list
git worktree add ../path -b new-branch start-point
git worktree remove ../path
git worktree prune # clean stale metadata
# Cannot remove worktree with uncommitted changes
git -C ../ShipApp-sdk57-spike status# Optional: shared node_modules via pnpm (advanced)
# Prefer full npm ci per worktree for fidelity with CImain instead.expo-doctor in CI - Hidden dependency skew. Fix: Add doctor step to PR checks.git worktree list monthly. Fix: git worktree remove + git worktree prune.git rebase -i --rebase-merges or avoid merge commits on feature branches.| Alternative | Use When | Don't Use When |
|---|---|---|
git stash | 30-minute context switch | Multi-day SDK spike |
| Second full clone | Simple mental model | Double fetch time and disk |
| Feature flags on main | Small SDK delta | Native folder overhaul |
| Draft PR from spike | Visibility without merge | Still blocks CI if targeting main early |
Worktrees share object database - faster, less disk. Second clone is simpler but duplicates .git history. Prefer worktrees for same-repo parallel branches.
Two or three (main + spike + hotfix investigation). More than that - disk and mental overhead exceed benefit.
git merge origin/main into spike before PR is safer for long spikes. Interactive rebase onto main produces linear history but costs conflict resolution time.
Yes - worktrees push to same origin. Branch spike/sdk-57-upgrade triggers same GitHub Actions as any remote branch.
One logical unit: one ticket or one SDK bump. Separate feat from chore(sdk) if reviewers need to bisect later.
expo-doctor before type: buildStack versions: This page was written for React 19.2.3, React Native 0.86.0, and Expo SDK 57 (
expo~57.0.4).
Reviewed by Chris St. John·Last updated Jul 16, 2026