Skip to content
Development
Skill

/smart-rebase

Smart partial rebase for squash-merge repositories. Auto-detect which commits to keep/drop when base branch was squash-merged into target. Use when: user says 'rebase', 'partial rebase', 'base already merged', 'smart rebase', or /smart-rebase. Not for: simple git rebase (the

From plugin
sd0x-dev-flow
18899 skills16 agents5 hooks
Install
$ npx -y skills add sd0xdev/sd0x-dev-flow --skill smart-rebase --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/smart-rebase

Context preview

The summary Claude sees to decide when to auto-load this skill.

Smart partial rebase for squash-merge repositories. Auto-detect which commits to keep/drop when base branch was squash-merged into target. Use when: user says 'rebase', 'partial rebase', 'base already merged', 'smart rebase', or /smart-rebase. Not for: simple git rebase (the

SKILL.md

smart-rebase.SKILL.md
name: smart-rebase
description: "Smart partial rebase for squash-merge repositories. Auto-detect which commits to keep/drop when base branch was squash-merged into target. Use when: user says 'rebase', 'partial rebase', 'base already merged', 'smart rebase', or /smart-rebase. Not for: simple git rebase (the developer runs it — Claude never executes rebase), merge conflict resolution (use /merge-prep), branch switching (the developer runs git checkout). Output: rebase plan table + a shell-quoted git rebase --onto command for the developer to run after the ambiguity check in Step 5."
allowed-tools: Bash(git:*), Bash(bash:*), Read, Grep, Glob

Smart Rebase — Partial Rebase for Squash-Merge Repos

Analyze branch history → identify squash-merged commits → generate precise `git rebase --onto` command.

When NOT to Use

  • Simple `git rebase` without squash-merge complexity — **the developer runs it**; Claude never

executes `rebase`, here or anywhere else (§ Permissions). "Use git directly" is an instruction to the human, and this list is read by the dispatcher before § Permissions loads, so it says so here

  • Merge conflict resolution (use `/merge-prep`)
  • Branch management or switching — the developer runs the git command
  • Cherry-picking specific commits (use `git cherry-pick`)

Core Problem

In squash-merge repositories, when a feature branch is based on another branch that was already squash-merged:

main:    A ─── S (squash merge of B1+B2+B3) ─── ...
              ↑
feature: A ─ B1 ─ B2 ─ B3 ─ F1 ─ F2 ─ F3
              ↑ drop (in S)   ↑ keep (unique)

Need: `git rebase --onto main B3 feature` to keep only F1-F3.

Permissions

Claude **must not** execute `git rebase` — **there is no authorization that lifts this**. `rebase` is a destructive operation under Anchor Register #4 (`@rules/discretion.md`), whose enumerated approval workflows are a closed set: `/push-ci` (push), `/smart-commit --execute` (add + commit) and `/epic-merge` (rebase --onto, force-with-lease, squash-merge). This skill is not on that list, so user approval here cannot create the exception — adding a workflow to the list is itself an Anchor-level change. This skill **outputs** the rebase command; the developer runs it.

> **Note on `allowed-tools`**: `Bash(git:*)` is granted because Steps 1–3 read history (`git log`, > `git rev-parse`, `git branch --show-current`), and `Bash(bash:*)` to run the analysis script — > the latter cannot be narrowed to specific script paths until > [#9354](https://github.com/anthropics/claude-code/issues/9354) is resolved. **A tool grant is not > an authorization**: what may be executed is decided by the rule above, not by what the permission > string happens to permit.

Prerequisites

Before starting, validate:

| Check | Command | Fail action | |-------|---------|-------------| | Not on a protected branch | `git branch --show-current` must not match the **complete** protected set defined in `@rules/git-workflow.md` § Prohibited (which lists the complete protected set): `main`, `master`, `develop`, `release/*`. Do not re-spell a shorter list here — a partial copy is how `master` and `release/*` reached the force-push suggestion below | Abort with warning | | Clean working tree | `git status --porcelain` must be empty | Abort: "stash or commit changes first" | | Not detached HEAD | `git symbolic-ref HEAD` succeeds | Abort: "checkout a branch first" |

Names in commands

Every command this skill outputs carries ref names, and **a ref name is not display text**: `git check-ref-format` accepts `;`, backticks, `$( )` and `'` inside one — all measured. A name substituted into a command as a bare word runs whatever it contains, and a fixed pair of single quotes is broken by a name containing `'`.

So every `<…>` slot in a command block below is written `<quoted …>`: substitute a **shell-quoted** value, single-quoted with each `'` rendered as `'\''`.

**Shell-quoting is only half of it, and the other half is git's own option parser.** Quotes are consumed by the shell; git never sees them, so a branch named `--all` is still an option when it arrives. Measured: `git check-ref-format refs/heads/--all` exits 0, and `git push --force-with-lease origin '--all'` pushed **every** branch in the repository, not the one named. The mechanism the templates below rely on is the **`--` / `--end-of-options` separator**, placed before the ref operand — not fully-qualifying it. That distinction is load-bearing for one operand in particular: a `git rebase` **branch** operand written `refs/heads/<branch>` is measured to land on a **detached HEAD** and never move the branch, which is the whole point of the command, whereas the same short name after `--` stops the option parser and — **when the short name resolves unambiguously** — updates the ref. That qualification is not hypothetical and the separator does not supply it: with a branch `refs/heads/tags/v0.0.1` and a tag `v0.0.1` both present, `git rebase --onto main main -- 'tags/v0.0.1'` **exits 0 and leaves the branch unmoved** (measured — `docs/features/ref-name-hardening/requests/2026-08-20-ref-name-hardening-r1.md` finding 1). Until the ambiguity probe that closes this lands (that ticket's AC 1), **the emitted `rebase_command` is not safe to run verbatim on a repository where the current branch name could also name a tag** — check `git rev-parse --verify` for an `is ambiguous` warning on the operand before running it. So the separator, carried in the template, is the rule — `--` for `git push` and `git rebase`, `--end-of-options` for `git merge-base` and for `git log --not` (Step 6); a `<quoted branch>` after it stays a short name on purpose. **Which spelling matters, and where, is measured — not a blanket rule.** Measured on git 2.55.0 in this repository:

| Command | `--` | `--end-of-options` | Consequence | |---------|------|--------------------|-------------| | `git push`, `git fetch`, `git merge-base` | accepted | accepted |

Read more
Ships withsd0x-dev-flow

Language: English | 繁體中文 | 简体中文 | 日本語 | 한국어 | Español The harness layer for Claude Code. Let the model choose the path. Keep "done" verifiable. Full control plane on Claude Code. Skills-only distribution for Codex CLI and other compatible agents.

Get the whole plugin

Other skills on sd0x-dev-flow.