Git History Surgery skill for Codex

Rewrite history with a backup and a proof. Codex rewrites history with recipes that need no interactive editor: autosquash for fixups, GIT_SEQUENCE_EDITOR and GIT_EDITOR scripting for reword and edit, cherry-pick rebuilds for reordering, and reset --keep for misplaced commits. Each rewrite starts with a backup branch and ends with an empty tree diff plus range-diff, and force pushes wait for your explicit go-ahead.

  • Engineering Workflow
  • $git-history-surgery
  • 204 lines
  • 2 files
  • ~1,900 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- git-history-surgery

Installs to ~/.agents/skills/git-history-surgery/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $git-history-surgery, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Rewrites local git history precisely without an interactive editor - fixup commits with autosquash, scripted rebase todos via GIT_SEQUENCE_EDITOR for reword, reorder, drop and edit, splitting a commit, squashing a branch with reset --soft, moving commits between branches, rebasing stacks with --update-refs, and rescuing lost work from the reflog or fsck. Every rewrite starts with a backup ref and ends with a range-diff check. Use when asked to squash, reorder, reword or split commits, clean a branch before merge, undo a bad rebase or reset, or recover deleted commits.

Use it when

  • A branch needs squashing, reordering or rewording before merge
  • One commit mixes changes that should be separate
  • Work seems lost after a reset, rebase or deleted branch

Use something else when

How to check the result

git diff between the backup branch and HEAD is empty for history-only rewrites, git range-diff shows the intended commit mapping, and rebase --exec passes on every commit.

The mistake it prevents

Running git rebase -i in an agent shell with no sequence editor configured, which hangs waiting for an editor that never opens.

~/.agents/skills/git-history-surgery/SKILL.md

--- name: git-history-surgery description: Rewrites local git history precisely without an interactive editor - fixup commits with autosquash, scripted rebase todos via GIT_SEQUENCE_EDITOR for… license: MIT ---

A rewrite is correct when the final tree is exactly what was intended (usually identical to the pre-rewrite tree), each resulting commit is coherent and builds, a backup ref makes the operation reversible in one command, and nothing shared was rewritten without the user’s consent.

Safety protocol (every time)

git status --short                         # must be clean; stash or commit first
git log --oneline --graph -15
git branch backup/$(git branch --show-current)-$(date +%Y%m%d-%H%M%S)
git rev-parse --abbrev-ref @{upstream} 2>/dev/null && git log --oneline @{upstream}..HEAD
  • If the commits you will rewrite are already on a remote branch others use, stop and ask. Rewriting them forces everyone else to recover.
  • Know your base: usually git merge-base HEAD origin/main. Use it explicitly rather than counting HEAD~n by eye.
  • Codex cannot drive an interactive editor. Use the non-interactive recipes below; never run a bare git rebase -i without GIT_SEQUENCE_EDITOR set.

Recipe chooser

GoalRecipe
Fold a correction into an earlier commitFixup + autosquash
Squash the whole branch into one commitreset --soft
Change an old commit messageScripted reword
Reorder or drop commitsCherry-pick onto a fresh branch, or rebase --onto
Split one commit into severalScripted edit, then reset and re-commit
Commits landed on the wrong branchBranch + reset --keep
Rebase a stack of dependent branchesrebase --update-refs
Undo a rebase, reset or amendReflog
Remove a file or secret from all historygit filter-repo (see hard rules)

Recipes

Fixup + autosquash

git add -- src/cart.py
git commit --fixup=<target-sha>                 # creates "fixup! <target subject>"
BASE=$(git merge-base HEAD origin/main)
git rebase --autosquash "$BASE"                 # Git 2.44+: works without -i
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash "$BASE"   # older Git: accept the generated todo

--fixup=amend:<sha> also replaces the target’s message, but it opens an editor; use the scripted reword below instead.

Squash the whole branch

BASE=$(git merge-base HEAD origin/main)
git reset --soft "$BASE"
git commit -F "$TMPDIR/squashed-msg.txt"

Write the message from the combined intent, not by concatenating old subjects.

Reword an older commit

BASE=$(git merge-base HEAD origin/main)
SHA=$(git rev-parse --short <target>)
printf 'Cap bulk discount at a single tier\n\nTiers stacked, so 100+ unit orders were undercharged.\n' > "$TMPDIR/msg.txt"
GIT_SEQUENCE_EDITOR="sed -i.bak 's/^pick $SHA/reword $SHA/'" \
GIT_EDITOR="cp $TMPDIR/msg.txt" \
git rebase -i "$BASE"

GIT_SEQUENCE_EDITOR edits the todo list; GIT_EDITOR is called with the message file path as its last argument, so cp overwrites it with your text. sed -i.bak works on both GNU and BSD sed. For the most recent commit, git commit --amend -F msg.txt is enough.

Reorder or drop

Drop one commit:

git rebase --onto <bad-sha>^ <bad-sha>

Reorder transparently by rebuilding the branch with cherry-pick:

git switch -c rebuilt "$BASE"
git cherry-pick <sha-C> <sha-A> <sha-B>        # in the new order
git diff backup/<branch>-<stamp> rebuilt       # empty: same final tree
git switch <branch> && git reset --hard rebuilt   # confirm with the user before --hard

Reordering can create conflicts when later commits depend on earlier ones; resolve with merge-conflict-resolution, or reconsider the order.

Split a commit

For HEAD:

git reset HEAD~                         # changes back to working tree, unstaged
git add -- src/tax.py && git commit -m "Extract tax calculation"
git add -- src/cart.py tests/ && git commit -m "Cap bulk discount at a single tier"

For an older commit, stop the rebase at it:

GIT_SEQUENCE_EDITOR="sed -i.bak 's/^pick $SHA/edit $SHA/'" git rebase -i "$BASE"
git reset HEAD~
# stage and commit in pieces; for partial files use a patch with git apply --cached
git rebase --continue

Within one file, stage hunks non-interactively with git diff file > p.patch, trim to the wanted hunks, then git apply --cached --recount p.patch (git-commit-hygiene covers this in detail).

Commits on the wrong branch

git branch feature/discounts             # new branch keeps the 3 commits
git reset --keep HEAD~3                  # move current branch back; refuses if it would lose local edits
git switch feature/discounts

Stacked branches

git rebase --update-refs origin/main     # rebases the branch and moves every branch ref inside the range

Set git config rebase.updateRefs true per repo if the user works in stacks; see stacked-pull-requests for the full workflow.

Rescue

Committed work is rarely lost: reflog entries are kept 90 days by default, or 30 days for commits no longer reachable from any branch (gc.reflogExpire, gc.reflogExpireUnreachable).

git reflog --date=relative -20            # where HEAD has been
git reflog show <branch> -10              # where a branch pointed
git branch rescue/<name> <sha>            # pin a found commit before doing anything else
git rebase --abort                        # mid-rebase: back to where you started
git reset --keep ORIG_HEAD                # undo the last rebase/reset/merge when the tree is clean

Commits never referenced by a reflog (a dropped stash, a deleted branch from a fresh clone) can still be found until garbage collection:

git fsck --unreachable --no-reflogs | awk '/commit/ {print $3}' \
  | xargs -n1 git log -1 --format='%h %cr %s'
git stash apply <sha>                     # a dropped stash shows up as a commit "WIP on ..."

Pin anything valuable with a branch immediately; git gc may prune unreachable objects.

Verify the rewrite

git diff backup/<branch>-<stamp> HEAD            # empty when only the history changed
git range-diff "$BASE" backup/<branch>-<stamp> HEAD   # commit-by-commit comparison
git log --oneline "$BASE"..HEAD
git rebase --exec "<test cmd>" "$BASE"           # every commit still builds and passes

If git diff against the backup is not empty and you did not intend a content change, something was lost or duplicated during conflict resolution. Restore with git reset --keep backup/<branch>-<stamp> and redo.

Delete the backup branch only after the user confirms the result.

Hard rules

  • Force pushing is destructive for collaborators. Only with explicit user confirmation, and only as git push --force-with-lease --force-if-includes, never plain --force.
  • git reset --hard, git clean -fd and git checkout -- . discard uncommitted work. Confirm with the user and prefer --keep, which refuses to overwrite local changes.
  • Removing secrets or large files from all history needs git filter-repo (a separate install that needs network approval), rewrites every commit SHA, and requires every clone to be re-cloned. Secrets must be rotated regardless; history rewriting does not un-leak them. Get the user’s explicit decision first.
  • Never rewrite main/master or release branches.

Report

Rewrote feature/bulk-pricing (local only, not pushed):
  before: 7 commits (3 fixups, 1 WIP)   after: 3 commits
  backup: backup/feature-bulk-pricing-20261028-1412
  git diff backup HEAD: empty (history-only change)
  every commit passes `pytest -q` (rebase --exec)
To publish: git push --force-with-lease --force-if-includes  (awaiting your OK)

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Git History Surgery"
  short_description: "Rewrite history with a backup and a proof"
  default_prompt: "$git-history-surgery Squash my fixup commits into the right commits before I merge"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc