Use when replaying the current local branch onto upstream/main, or onto another provided remote branch, by stashing local changes, resetting to the target branch, and cherry-picking missing commits back one by one.
Use this skill when the current local branch should be replayed onto upstream/main.
upstream/main is the default target, but the same process should work with any provided remote branch such as origin/main or upstream/release.
- [ ] Inspect the current branch, target branch, and local changes
- [ ] Stash local changes if needed and create a backup branch
- [ ] Reset the current branch to the target ref (e.g., upstream/main)
- [ ] Cherry-pick missing commits from the backup branch one by one
- For each commit with conflicts: resolve source, then manifests, then lockfiles
- For package.json conflicts: compare each dependency individually and keep the highest semantic version (e.g., 11.11.1 > 11.11.0, 21.2.0 > 20.3.2)
- After resolving lockfile conflicts: regenerate via wrapper before committing
- [ ] Re-apply any stash and resolve conflicts with the same rules
- [ ] Delete the backup branch
- [ ] Run validation and summarize the final branch state
TARGET_REF=${TARGET_REF:-upstream/main}
CURRENT_BRANCH=$(git branch --show-current)
BACKUP_BRANCH="backup/${CURRENT_BRANCH//\//-}"
git fetch --all --prune
printf '%s\n' "$CURRENT_BRANCH"
git status --short
git log --oneline --decorate --graph --max-count=20
Only stash if there are actual local changes:
# Check for changes first
git status --short
# Only stash if output is not empty
git stash push -u -m "rebase-to-upstream: $CURRENT_BRANCH"
# Create backup branch before any destructive operations
git branch "$BACKUP_BRANCH"
git reset --hard "$TARGET_REF"
git cherry -v "$TARGET_REF" "$BACKUP_BRANCH"
git log --reverse --format=%H "$TARGET_REF".."$BACKUP_BRANCH"
For each commit:
git cherry-pick <commit-hash>
If conflicts occur, resolve them in this order:
git add <path>major.minor.patch (ignore pre-release tags like -alpha, -beta)"npm": "11.11.0" vs "npm": "11.11.1" → keep 11.11.1 (patch is higher)"ng-packagr": "20.3.2" vs "ng-packagr": "21.2.0" → keep 21.2.0 (major is higher)"rxjs": "7.8.0" vs "rxjs": "7.5.0" → keep 7.8.0 (minor is higher)git checkout --theirs or git checkout --ours for package.json conflicts. These commands accept/reject the entire conflict block, which will incorrectly resolve some dependencies. You must manually edit the file to keep the highest version for each individual dependency.git add <path>Do NOT manually edit or merge conflict markers
Accept the cherry-picked side: git checkout --theirs path/to/package-lock.json
Regenerate immediately via wrapper before committing:
# Standard flow: just run npm install via wrapper for affected project
sh compose.sh <affected-target>
# Only if npm install fails, use the update workaround:
# 1) Edit compose.yml: change service command from "npm install" to "npm update"
# 2) Run: sh compose.sh <affected-target>
# 3) Restore compose.yml back to "npm install --no-audit"
# 4) Run: sh compose.sh <affected-target>
Stage the regenerated lockfile: git add path/to/package-lock.json
git cherry-pick --continue
# Or if no auto-commit: git commit --no-verify -m "original commit message"
git stash list
git stash apply <stash-ref>
# If conflicts occur, resolve using the same rules as step 5
# Regenerate lockfiles via wrapper before committing if needed
git branch -D "$BACKUP_BRANCH"
Run validation for affected targets:
sh test.sh <affected-target> # For specific project/suite changes
sh test.sh root # Only when root files changed
sh test.sh e2e # Only when tests-e2e or shared e2e files changed
When conflicts occur during cherry-pick, resolve in this order:
git checkout --theirs then regenerate via wrapper (see Step 5c)upstream/main is only the default target; override when user provides another remote branchgit reset --hardgit status --short)sh compose.sh, sh test.sh) for all npm operations; never run ad-hoc local npm install or npm update