skills/boneskull/claude-plugins/git-rebase-interactive

git-rebase-interactive

SKILL.md

Programmatic Interactive Git Rebase

This skill enables non-interactive execution of git interactive rebases. Use this when you need to:

  • Absorb/fixup commits into earlier commits
  • Squash multiple commits together
  • Reorder commits
  • Drop commits
  • Reword commit messages (limited support)

The Problem

Git's interactive rebase (git rebase -i) normally opens an editor for the user to modify a "todo" file. The GIT_SEQUENCE_EDITOR environment variable can override this, but:

  1. macOS BSD sed has different syntax than GNU sed for multi-line operations
  2. Complex todo modifications (reordering, inserting lines) are error-prone with sed

The Solution

Write the complete todo file using a temporary shell script:

# 1. Create a temp editor script that writes the desired todo
EDITOR_SCRIPT=$(mktemp)
cat > "$EDITOR_SCRIPT" << 'SCRIPT'
#!/bin/bash
cat > "$1" << 'TODO'
pick abc1234 First commit message
fixup def5678 Commit to absorb into first
pick ghi9012 Third commit stays separate
TODO
SCRIPT
chmod +x "$EDITOR_SCRIPT"

# 2. Run the rebase with our custom editor
GIT_SEQUENCE_EDITOR="$EDITOR_SCRIPT" git rebase -i <base-commit>

# 3. Clean up
rm "$EDITOR_SCRIPT"

Step-by-Step Process

1. Identify the commits

git log --oneline -10

Note the commit hashes and messages you want to work with.

2. Determine the base commit

The base commit is the parent of the oldest commit you want to modify:

# If oldest commit to modify is abc1234
git rebase -i 'abc1234^'  # Note: quote the caret for zsh

3. Plan the todo list

The todo file format is:

<action> <hash> <message>

Available actions:

Action Short Description
pick p Use commit as-is
reword r Use commit but edit message (requires interaction)
edit e Stop for amending (requires interaction)
squash s Meld into previous, combine messages
fixup f Meld into previous, discard this message
drop d Remove commit entirely

4. Build and execute

EDITOR_SCRIPT=$(mktemp)
cat > "$EDITOR_SCRIPT" << 'SCRIPT'
#!/bin/bash
cat > "$1" << 'TODO'
# Your todo list here - one line per commit
pick abc1234 First commit
fixup def5678 Second commit (will be absorbed)
pick ghi9012 Third commit
TODO
SCRIPT
chmod +x "$EDITOR_SCRIPT"

GIT_SEQUENCE_EDITOR="$EDITOR_SCRIPT" git rebase -i '<base>^'
rm "$EDITOR_SCRIPT"

Common Operations

Absorb fix commits into a feature commit

Scenario: You have a feature commit followed by fix commits that should be part of it.

abc1234 feat: add user authentication
def5678 fix: correct token validation  <- absorb this
ghi9012 fix: handle edge case          <- and this
jkl3456 chore: update deps             <- keep separate

Todo:

pick abc1234 feat: add user authentication
fixup def5678 fix: correct token validation
fixup ghi9012 fix: handle edge case
pick jkl3456 chore: update deps

Squash multiple commits with combined message

Use squash instead of fixup to keep all commit messages:

pick abc1234 feat: add user model
squash def5678 feat: add user controller
squash ghi9012 feat: add user routes

This will combine all three into one commit and open an editor to combine messages (or use GIT_EDITOR to automate).

Reorder commits

Simply list commits in the desired order:

pick ghi9012 Third commit (now first)
pick abc1234 First commit (now second)
pick def5678 Second commit (now third)

Drop a commit

Use drop or simply omit the line:

pick abc1234 Keep this
drop def5678 Remove this
pick ghi9012 Keep this too

Handling Conflicts

If the rebase encounters conflicts:

  1. The rebase will pause with a message
  2. Resolve conflicts in the affected files
  3. Stage the resolved files: git add <files>
  4. Continue: git rebase --continue
  5. Or abort: git rebase --abort

Complete Example Script

Here's a reusable function:

# Programmatic interactive rebase
# Usage: git_rebase_todo '<base>^' 'pick abc123 msg' 'fixup def456 msg' ...
git_rebase_todo() {
  local base="$1"
  shift

  local EDITOR_SCRIPT
  EDITOR_SCRIPT=$(mktemp)

  {
    echo '#!/bin/bash'
    echo 'cat > "$1" << '\''TODO'\'''
    for line in "$@"; do
      echo "$line"
    done
    echo 'TODO'
  } > "$EDITOR_SCRIPT"

  chmod +x "$EDITOR_SCRIPT"
  GIT_SEQUENCE_EDITOR="$EDITOR_SCRIPT" git rebase -i "$base"
  local result=$?
  rm "$EDITOR_SCRIPT"
  return $result
}

# Example usage:
git_rebase_todo 'abc1234^' \
  'pick abc1234 feat: add feature' \
  'fixup def5678 fix: correct issue' \
  'pick ghi9012 chore: update deps'

Limitations

  1. reword and edit actions still require user interaction for the actual editing
  2. Conflict resolution requires manual intervention
  3. Complex rebases with many commits may be easier to do interactively

Troubleshooting

"fatal: could not read file..."

The todo file path wasn't passed correctly. Ensure the script uses "$1".

Rebase doesn't seem to do anything

Check that commit hashes in the todo match actual commits. Use short hashes (7+ chars).

zsh: no matches found: abc^

Quote the caret: 'abc1234^' or escape it: abc1234\^

Weekly Installs
4
GitHub Stars
2
First Seen
Feb 21, 2026
Installed on
opencode4
gemini-cli4
github-copilot4
amp4
codex4
kimi-cli4