Rebase

Rebase current branch onto a target branch using the optimal strategy

phatblat 11 updated 22d ago
Claude CodeGeneric
View source ↗
---
description: Rebase current branch onto a target branch using the optimal strategy
model: sonnet
allowed-tools: Bash(git:*), AskUserQuestion
category: workflow
argument-hint: "[target-branch]"
---

# Git Rebase: Smart Branch Update

Rebase the current branch onto a target branch, automatically selecting the best strategy based on divergence analysis.

## Context Gathering

Collect all needed state in one pass:

!`git branch --show-current 2>/dev/null`
!`git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || git config init.defaultBranch || echo "main"`
!`git status --porcelain=v1`

## Instructions

### 1. Resolve Branches

- **Subject branch**: current branch (from above)
- **Target branch**: `$ARGUMENTS` if provided, otherwise the detected default branch (from above)
- Abort immediately if subject branch == target branch and tell the user

### 2. Guard: Clean Working Tree

If `git status --porcelain=v1` shows any output, stop and tell the user:
> "Working tree is dirty. Commit or stash changes before rebasing."

### 3. Fetch & Update Target

```bash
git fetch origin
git fetch origin <target>:<target>   # fast-forward local target branch

If the fast-forward fails (target has diverged locally), stop and report.

4. Create Backup Branch

git branch <subject>.bak

Report: Created backup branch <subject>.bak

If .bak already exists, ask the user whether to overwrite it or abort.

5. Divergence Analysis

Run these in one bash call:

MERGE_BASE=$(git merge-base HEAD <target>)
echo "merge_base=$MERGE_BASE"
echo "subject_commits=$(git log $MERGE_BASE..HEAD --oneline | wc -l | tr -d ' ')"
echo "target_commits=$(git log $MERGE_BASE..<target> --oneline | wc -l | tr -d ' ')"
echo "subject_files=$(git diff --name-only $MERGE_BASE HEAD)"
echo "target_files=$(git diff --name-only $MERGE_BASE <target>)"
# Check if merge-base is on the target branch lineage
git merge-base --is-ancestor $MERGE_BASE <target> && echo "base_on_target=yes" || echo "base_on_target=no"

Compute overlap: files changed in both subject and target since merge-base.

6. Strategy Selection

Use this decision tree:

Condition Strategy
target_commits ≥ 20 AND overlapping files ≥ 3 cherry-pick
base_on_target=no (branch cut from non-target branch) rebase --onto
Otherwise simple rebase

Display the analysis before proceeding:

Branch analysis:
  Subject:         <subject> (<N> commits ahead of merge-base)
  Target:          <target> (<N> commits since merge-base)
  Overlapping files: <N>
  Merge-base on target lineage: yes/no

Selected strategy: <strategy>
Reason: <one sentence>

Then proceed with the selected strategy.


Strategy A: Simple Rebase

git rebase <target>

On success → go to Step 8. On conflict → go to Step 7 (Conflict Handler).


Strategy B: Rebase --onto

Determine <old-base>: the commit just before the subject branch diverged from its original base.

OLD_BASE=$(git merge-base HEAD <target>)
git rebase --onto <target> $OLD_BASE HEAD

On success → go to Step 8. On conflict → go to Step 7 (Conflict Handler).


Strategy C: Cherry-pick

  1. Collect commits to replay (oldest first):

    git log --reverse --format="%H" <merge-base>..HEAD
    
  2. Create a temp branch from target:

    git checkout -b <subject>__cherrypick__ <target>
    
  3. Cherry-pick each commit in order:

    git cherry-pick <sha>
    

    On conflict → go to Step 7 (Conflict Handler) before continuing.

  4. On success of all picks:

    git branch -D <subject>            # delete old branch
    git branch -m <subject>__cherrypick__ <subject>  # rename to original name
    git checkout <subject>
    

On complete success → go to Step 8.


7. Conflict Handler

When a conflict is detected mid-operation, pause and ask the user:

"Conflict detected in <file(s)>.

How would you like to proceed?

a) Abort — restore from <subject>.bak and clean up b) Pause here — resolve conflicts manually, then run git rebase --continue (or git cherry-pick --continue) yourself

Enter a or b:"

If user chooses a (Abort):

For rebase:

git rebase --abort

For cherry-pick:

git cherry-pick --abort
git checkout <subject>
git branch -D <subject>__cherrypick__  # if it exists

Then restore:

git checkout <subject>   # if not already on it
git reset --hard <subject>.bak

Report: "Restored <subject> from backup. Branch is unchanged."

If user chooses b (Pause):

Report the exact commands the user needs to resolve and continue, e.g.:

Paused at conflict. Resolve the conflicts in:
  - <file1>
  - <file2>

Then run:
  git add <files>
  git rebase --continue    # or: git cherry-pick --continue

The backup branch <subject>.bak is still available if you need to roll back:
  git reset --hard <subject>.bak

Then stop — do not continue until the user resumes.


8. Fix Remote Tracking & Push

After rebase, the upstream tracking ref may point to the target branch instead of the subject branch. Always reset it explicitly:

git branch --set-upstream-to=origin/<subject> <subject>

Then force push with an explicit refspec to ensure tracking stays correct:

git push --force-with-lease -u origin <subject>:<subject>

Verify tracking is correct:

git branch -vv | grep '^\*'

The output must show [origin/<subject> ...] — if it shows the target branch name, tracking is wrong and must be fixed before proceeding.

9. Success Report

Rebase complete.
  Strategy used:   <strategy>
  Subject branch:  <subject>  (<N> commits on top of <target>)
  Tracking:        origin/<subject>
  Backup branch:   <subject>.bak  (kept — delete when satisfied)

To clean up backup:
  git branch -D <subject>.bak

Note: rerere is enabled, so conflict ```

Maintain Rebase?

Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.

[Rebase on getagentictools](https://getagentictools.com/loops/phatblat-git-rebase-smart-branch-update?ref=badge)