| name | rebase-to-upstream |
| description | 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. |
Rebase To Upstream
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.
Task List
- [ ] 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
Workflow
1. Inspect Current 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
2. Stash and Backup (if needed)
Only stash if there are actual local changes:
git status --short
git stash push -u -m "rebase-to-upstream: $CURRENT_BRANCH"
git branch "$BACKUP_BRANCH"
3. Reset to Target
git reset --hard "$TARGET_REF"
4. Identify Missing Commits
git cherry -v "$TARGET_REF" "$BACKUP_BRANCH"
git log --reverse --format=%H "$TARGET_REF".."$BACKUP_BRANCH"
5. Cherry-Pick Commits One by One
For each commit:
git cherry-pick <commit-hash>
If conflicts occur, resolve them in this order:
Step 5a: Resolve Source Files
- Resolve using standard merge conflict resolution
- Stage resolved files:
git add <path>
Step 5b: Resolve Manifests (package.json)
- Compare both sides dependency-by-dependency (not block-by-block)
- For each dependency key, resolve versions using semantic version comparison:
- Parse versions as
major.minor.patch (ignore pre-release tags like -alpha, -beta)
- Compare major first, then minor, then patch
- Keep the highest version number for that specific dependency
- Examples:
"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)
- CRITICAL: Do NOT use
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.
- Stage resolved files:
git add <path>
Step 5c: Resolve Lockfiles (package-lock.json)
-
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:
sh compose.sh <affected-target>
-
Stage the regenerated lockfile: git add path/to/package-lock.json
Step 5d: Complete the Cherry-Pick
git cherry-pick --continue
6. Apply Stash (if one was created)
git stash list
git stash apply <stash-ref>
7. Cleanup
git branch -D "$BACKUP_BRANCH"
8. Validation
Run validation for affected targets:
sh test.sh <affected-target>
sh test.sh root
sh test.sh e2e
Conflict Resolution Quick Reference
When conflicts occur during cherry-pick, resolve in this order:
- Source files: Standard merge resolution
- package.json: Manual edit per dependency (see Step 5b)
- package-lock.json:
git checkout --theirs then regenerate via wrapper (see Step 5c)
Guardrails
- This skill is branch-agnostic: works from any current local branch
upstream/main is only the default target; override when user provides another remote branch
- Always create backup branch before
git reset --hard
- Only stash when local changes actually exist (check with
git status --short)
- Use repo wrappers (
sh compose.sh, sh test.sh) for all npm operations; never run ad-hoc local npm install or npm update
- Regenerate lockfiles immediately after resolving conflicts, before committing each cherry-pick - this keeps each commit atomic and correct