| name | rebase |
| version | 1.1.1 |
| description | Rebase a branch onto main (or a target) with squash-first strategy, semantic merge verification, and safe force-push. |
| allowed-tools | Agent, Bash, Edit, Glob, Grep, Read, Write |
| model | opus |
Context
- Arguments:
${ARGS}
- Project root: !
git rev-parse --show-toplevel 2>/dev/null || echo "NOT_IN_GIT_REPO"
- Current branch: !
git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "NO_BRANCH"
- Default base: !
sh -c 'ref=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed "s@^refs/remotes/origin/@@"); echo "${ref:-main}"'
- Commits ahead: !
git rev-list --count HEAD --not --remotes 2>/dev/null || echo "unknown"
- Ecosystem: !
sh -c 'e=""; [ -f Cargo.toml ] && e="${e:+$e,}rust"; [ -f package.json ] && e="${e:+$e,}node"; [ -f pyproject.toml ] && e="${e:+$e,}python"; [ -f go.mod ] && e="${e:+$e,}go"; echo "${e:-unknown}"'
- Tooling: !
[ -f Justfile ] && echo "just" || { [ -f Makefile ] && echo "make" || echo "none"; }
Ecosystem Defaults
Use project tooling (Justfile/Makefile) first. Fall back to these only when no project recipe exists:
| Ecosystem | Build | Lint | Format | Test | Lock Regen |
|---|
| Rust | cargo build --workspace | cargo clippy --workspace --all-targets -- -D warnings | cargo fmt --all | cargo test --workspace | cargo update |
| Node | npm run build | npm run lint | npm run format or npx prettier --write . | npm test | npm install |
| Python | uv build or python -m build | ruff check . | ruff format . | pytest | uv lock |
| Go | go build ./... | golangci-lint run | gofmt -w . | go test ./... | go mod tidy |
Shell variables (TARGET, MERGE_BASE) do not persist across Bash tool calls. Re-derive from Context when needed.
Rebase Skill
Expert git operator performing safe, semantically-correct rebases. The #1 failure mode in rebases is not merge conflicts — it is silent semantic breakage after a "clean" auto-merge. Your primary job is to prevent that.
Phase 0: Pre-flight Validation
If "Project root" is "NOT_IN_GIT_REPO" or "Current branch" is "NO_BRANCH" or "HEAD" — stop and inform user.
Resolve target branch from ${ARGS}:
| Args | Action |
|---|
| Empty | Rebase onto the default base from Context |
Branch name (e.g. main, upstream/main) | Rebase onto origin/<branch> (fetch ensures it's current) |
PR URL (https://github.com/.../pull/123) | gh pr view <number> --json baseRefName to extract base, rebase onto origin/<base> |
Important: Always rebase onto the remote tracking ref (origin/<branch>), not the local branch — git fetch origin updates remote refs but not local branches.
For PR URLs, this extracts the PR's base branch (the branch it merges into). To rebase onto another PR's head branch for stacking, provide the branch name directly.
Set TARGET to the resolved target ref. Run git fetch origin to ensure it's current.
Pre-flight checks:
git status --porcelain — if non-empty, ask user: stash (git stash push -m "rebase-skill: pre-rebase stash") or abort
ls .git/rebase-merge .git/rebase-apply 2>/dev/null — if either exists, run git rebase --abort automatically, report it, and continue
git config rerere.enabled — if true, note it internally and continue (rerere may silently auto-apply prior conflict resolutions; verify Phase 3 output carefully)
Phase 1: Pre-flight Analysis
1a. Compute divergence
MERGE_BASE=$(git merge-base HEAD $TARGET)
git log --oneline $MERGE_BASE..HEAD
git log --oneline $MERGE_BASE..$TARGET
git diff --name-only $MERGE_BASE..HEAD
git diff --name-only $MERGE_BASE..$TARGET
Compute: COMMIT_COUNT (our commits), BEHIND_COUNT (their commits), OUR_BRANCH_FILES (files we changed), THEIR_FILES (files they changed), OVERLAP_FILES (intersection of both).
1a-fast. Fast path for simple rebases
If OVERLAP_FILES is empty and BEHIND_COUNT is small (< 20): skip Phase 1c (structural risk analysis) and Phase 4b (verification subagents). Proceed with a direct rebase followed by build/test verification only.
1b. Classify overlapping files
For each file in OVERLAP_FILES:
Generated files (never manually merge — accept TARGET's version, regenerate after):
- Lock files:
Cargo.lock, package-lock.json, yarn.lock, pnpm-lock.yaml, uv.lock, go.sum
- Schema files:
*.schema.json, openapi.json, openapi.yaml, acp-schema.json, acp-meta.json
- Codegen output: files containing
// This file is auto-generated, // DO NOT EDIT, /* auto-generated */, or living in directories named generated/
- Protobuf/gRPC:
*.pb.rs, *.pb.go, *_grpc.rs
- Heuristic fallback: any file whose first 5 lines contain
auto-generated, DO NOT EDIT, or @generated; any *.lock* file; any file in a directory named generated/, dist/, or build/
Hand-written files — everything else.
1c. Detect structural risks on TARGET
Launch ONE Explore subagent to analyze commits from MERGE_BASE to TARGET (substitute actual SHA/ref values — subagents cannot access shell variables):
Analyze commits from <MERGE_BASE_SHA> to <TARGET_REF> in <project root>.
Focus on commits touching OUR_BRANCH_FILES or structural files (Cargo.toml, package.json, tsconfig.json, mod.rs, __init__.py, index.ts, lib.rs).
Check for: file renames/moves (--diff-filter=R), file→directory transitions, crate/package renames or splits, type/API renames, namespace changes, function signature changes.
Output a RISK MATRIX:
FILE | RISK_TYPE | WHAT_CHANGED | IMPACT_ON_OUR_CODE | CONFIDENCE
1d. Present pre-flight summary
Present to user: TARGET, commit counts, overlapping files (generated vs hand-written), structural risks from the risk matrix. Proceed immediately.
Persist the risk matrix in full — it's referenced in Phases 3 and 4.
Phase 2: Squash & Rebase
2a. Squash if multiple commits (HARD RULE — no exceptions)
Always squash when COMMIT_COUNT > 1. If COMMIT_COUNT is 1, skip to Phase 2b.
Compute MERGE_BASE=$(git merge-base HEAD $TARGET). Read the branch's commit messages (git log --reverse --format="%s%n%b" $MERGE_BASE..HEAD), compose a single commit message following the repo's conventions (check git log -5 --oneline for style). Write to a temp file for shell safety.
git reset --soft $MERGE_BASE
git commit -F <message-file>
2b. Rebase
Run git rebase $TARGET.
Phase 3: Conflict Resolution
Check git status for conflicts after each rebase step.
Generated files — accept TARGET's version: git checkout $TARGET -- <file> then git add <file>.
Hand-written files — read conflict markers, consult the risk matrix, use TARGET's new names/paths for renamed types or moved modules, preserve both sides' functional changes.
When ambiguous — use best judgment based on the risk matrix, preserving both sides' functional intent. If a conflict is truly unresolvable (no clear correct answer exists), run git rebase --abort, report the specific conflicting file and context in the final summary, and exit.
After resolving all files: git add <resolved files> && git rebase --continue
Use GIT_EDITOR=true git rebase --continue to prevent editor prompts in the agent context.
If another conflict round occurs, repeat. If rebase aborts unexpectedly: git rebase --abort, report the failure and repo state in the final summary, and exit.
Phase 4: Semantic Verification
A clean rebase is NOT a correct rebase. This is the critical differentiator.
4a. Identify all branch files
Run git diff --name-only $TARGET..HEAD. Every one of these files must be verified — not just the ones that conflicted.
4b. Launch parallel verification subagents
Only launch agents for risk categories from the Phase 1 risk matrix. Load the briefing from references/semantic-verification-template.md in this skill's directory. Launch all applicable agents in a single response:
- Stale Imports — if RENAME/MOVE/SPLIT risks
- Stale API References — if TYPE/API/NAMESPACE risks
- Signature Compatibility — if SIGNATURE risks
Skip if risk matrix was empty.
4c. Fix all reported issues
For each finding: read the file, apply the correction, git add.
4d. Build
Use project tooling. Check Justfile/Makefile first for a build target. Fall back to the Ecosystem Defaults table above.
If build fails: read error, fix, re-run. Repeat until clean.
Phase 5: Regeneration
5a. Regenerate lockfiles
If any lockfile was accepted from TARGET in Phase 3, regenerate it using the package manager (see Ecosystem Defaults table — Lock Regen column). This restores the branch's dependencies that were lost when accepting TARGET's lockfile.
5b. Discover and run generators
Check project tooling (just/make/package.json scripts/CI workflows) for targets containing: generate, gen, schema, codegen, or types. Run each using project tooling recipes, not bare commands — recipes often add required feature flags or environment variables.
After each generator: git add the regenerated files.
5c. Format
Use project tooling or Ecosystem Defaults table above.
5d. Amend commit
Stage only regenerated/formatted/fixed files (not git add -A). Runs unconditionally to capture Phase 4c changes.
git add <changed-files>
git commit --amend --no-edit
Phase 6: Final Verification & Push
6a. Build
Run build using project tooling or Ecosystem Defaults. This catches compile errors from regeneration before running tests.
6b. Tests
Run via project tooling, fall back to ecosystem default (cargo test, npm test, pytest, go test ./...).
Build, tests, and lint are independent and can be launched as parallel Bash calls for speed.
If tests fail: determine if it's a regression from our rebase (fix it) or pre-existing (note it, don't fix). Fix regressions, amend, re-test.
6c. Final lint pass
One more lint run after regeneration and amendments.
Notable Rust pattern: needless_borrow after rebase often means a function changed from returning T to &T. Our &var creates &&T — remove the extra &.
Fix all lint errors.
6d. Summary & push
Run git push --force-with-lease origin HEAD. Never --force. If lease fails, report it in the summary and stop — do NOT retry with --force. Present completion summary: branch, target, files changed, verification results (build/lint/tests/semantic checks/regenerated files), push result.
If stash was created in Phase 0: git stash pop to restore working changes.
Rules (Never Violate)
- Squash before rebase when branch has >1 commit. No exceptions.
- Never manually merge generated files. Accept TARGET, regenerate.
- Always use project tooling (just/make) over bare commands. Feature flags matter.
- Run semantic verification before declaring success. Clean rebase != correct rebase.
- Build must pass before committing. Never push broken code.
--force-with-lease, never --force. Prevents clobbering others' pushes.
Abort & Cleanup
On abort: git rebase --abort if in progress, git stash pop the named stash if created in Phase 0, report phase reached and repo state.