User's Guide
This guide walks you through using retcon to clean up a messy git branch.
Prerequisites
- A git repository with a messy feature branch
- The branch has been pushed or you have a backup
retconinstalled and in your PATH- An LLM agent available (retcon uses Claude Code by default)
Quick Start
# 1. Generate guidance for creating a spec
retcon prompt > guidance.md
# 2. Give the guidance to your agent to create a spec
# e.g. in `my-spec.toml`
# 3. Run the reconstruction
retcon execute my-spec.toml
Step 1: Create the Spec with Your Agent
The retcon prompt command outputs guidance you can give to your LLM agent. The agent will analyze your diffs and propose a series of commits.
# Get the guidance prompt
retcon prompt
Give this prompt to your agent along with context about your branch:
# Show the agent your changes
git diff origin/main...my-feature-branch
The agent will:
- Analyze the diff to understand what changed
- Identify logical groupings (refactors, features, tests, etc.)
- Propose a commit sequence with messages and hints
Iterate with your agent until you're happy with the structure. Ask questions like:
- "Can we split commit 2 into two parts?"
- "Should the config changes be in their own commit?"
- "Reorder so refactors come before features"
Once you've agreed on the structure, have the agent write out the TOML file:
Write this plan as a retcon spec file to my-spec.toml
Manual Spec Creation
You can also create the spec manually. First understand what changed:
# See the full diff against target
git diff origin/main...my-feature-branch
# See which files changed
git diff origin/main...my-feature-branch --stat
# See the messy commit history (for context)
git log origin/main..my-feature-branch --oneline
Focus on the diff, not the commits. The diff shows what actually changed; the commits show how you got there (which is what we're cleaning up).
Then create a TOML file describing the clean history you want:
# my-spec.toml
source = "my-feature-branch" # Your messy branch
remote = "origin/main" # Target for the PR
cleaned = "my-feature-branch-clean" # New clean branch
[[commit]]
message = "refactor: extract validation into dedicated module"
hints = """
Move validate_user() and validate_session() from lib.rs to validation.rs.
Include the ValidationError enum.
Pure reorganization - no behavior changes.
"""
[[commit]]
message = "feat: add OAuth provider support"
hints = """
New oauth.rs module with OAuthProvider trait.
Includes Google and GitHub implementations.
Token refresh logic in token.rs.
"""
[[commit]]
message = "test: add OAuth integration tests"
hints = """
New file tests/oauth_test.rs.
Mock provider for testing.
"""
Tips for Good Specs
- Refactors first: Put code reorganization before new features
- One concept per commit: Each commit should do one thing
- Specific hints: Name files and functions, not just concepts
- Note exclusions: If a file has changes for multiple commits, say which parts belong where
Step 2: Run Retcon
retcon execute my-spec.toml
Retcon will:
- Create the
cleanedbranch from the merge-base - For each commit in order:
- Show the LLM the diff and your hints
- Apply the relevant changes
- Run
cargo check(build verification) - If it passes, mark complete and move on
- If it fails, try to fix it
- If stuck, stop and ask for help
Watching Progress
Retcon prints progress as it works:
Resuming from commit 1/3: refactor: extract validation
Created commit
Building...
Build passed
✓ Commit complete
Commit 2/3: feat: add OAuth provider support
Created commit
Building...
Build failed, consulting LLM...
Created WIP commit
Building...
Build passed
✓ Commit complete
The Spec File is State
Retcon updates your spec file as it works. After running, you'll see:
[[commit]]
message = "refactor: extract validation into dedicated module"
hints = "..."
history = [
{ commit_created = "a1b2c3d" },
"complete",
]
[[commit]]
message = "feat: add OAuth provider support"
hints = "..."
history = [
{ commit_created = "e4f5g6h" },
{ commit_created = "i7j8k9l" }, # WIP fix
"complete",
]
Step 3: Handle Stuck States
Sometimes retcon can't proceed:
Commit 2/3: feat: add OAuth provider support
...
Build failed, consulting LLM...
LLM: "I'm stuck. OAuthProvider depends on SessionManager which
isn't in the diff yet - it's probably in commit 3."
✗ Stuck - stopping
Your spec now shows:
history = [
{ commit_created = "a1b2c3d" },
{ stuck = "OAuthProvider depends on SessionManager..." },
]
To Continue
- Understand the problem: Read the stuck message
- Fix it: Edit hints, reorder commits, or manually adjust code
- Add a resolved entry: Tell retcon what you changed
history = [
{ commit_created = "a1b2c3d" },
{ stuck = "OAuthProvider depends on SessionManager..." },
{ resolved = "Reordered commits 2 and 3 - SessionManager needs to come first" },
]
- Resume:
retcon execute my-spec.toml
Retcon will retry with your resolution note as context.
If You Don't Add Resolved
$ retcon execute my-spec.toml
Resuming from commit 2/3: feat: add OAuth provider support
✗ Previously stuck - add a `resolved` entry to continue
Edit the spec file and add after the `stuck` entry:
{ resolved = "description of what you changed" }
This ensures the LLM knows what changed before retrying.
Step 4: Review the Result
When complete:
# Check out the clean branch
git checkout my-feature-branch-clean
# Review the history
git log --oneline
# Compare to original (should be identical content)
git diff my-feature-branch
# (should show nothing)
Handling WIP Commits
If retcon created WIP commits during fixes, you can squash them:
git checkout my-feature-branch-clean
git rebase -i origin/main
# Mark WIP commits as "fixup" to fold them into their parent
Or keep them for transparency about the reconstruction process.
Common Patterns
Circular Dependencies
Problem: Commit A needs something from commit B, but B depends on A.
Solution: Combine them into one commit, or extract the shared piece into a third commit that comes first.
# Before (broken)
[[commit]]
message = "feat: add TokenStore"
# ...
[[commit]]
message = "feat: add SessionManager"
# SessionManager uses TokenStore, but TokenStore uses SessionManager!
# After (fixed)
[[commit]]
message = "feat: add TokenStore and SessionManager"
hints = "These have circular dependencies - must be in same commit"
Interleaved Changes
Problem: One file has changes for multiple logical commits.
Solution: Use hints to specify which changes belong where.
[[commit]]
message = "refactor: rename foo to bar"
hints = """
In src/lib.rs: ONLY the foo→bar renames (lines 10-50 of the diff).
Do NOT include the new baz() function - that's commit 2.
"""
[[commit]]
message = "feat: add baz functionality"
hints = """
In src/lib.rs: the new baz() function.
Builds on the bar rename from commit 1.
"""
Missing Dependencies
Problem: Build fails because something from a later commit is needed.
Solution: Either reorder commits, or pull the dependency into the current commit's hints.
[[commit]]
message = "feat: add OAuth flow"
hints = """
Include the OAuthConfig struct even though it's "supposed" to be
in the config commit - we need it here for the code to compile.
"""
Troubleshooting
"Failed to find merge-base"
Your source and remote branches don't share history. Make sure:
sourceis your feature branch nameremoteis the target branch (e.g.,origin/main)- Both branches exist
"No more changes to extract"
The diff between cleaned and source is empty. This means either:
- All changes have been extracted (success!)
- The branches are identical (nothing to do)
- Wrong branch names in the spec
Build Keeps Failing
If the LLM keeps getting stuck:
- Check if changes are correctly split - maybe they need to be combined
- Add more specific hints about what to include
- Manually make the fix and add a
resolvedentry
Want to Start Over
# Delete the clean branch
git branch -D my-feature-branch-clean
# Remove history from spec (or delete and recreate)
# Edit my-spec.toml, remove all `history = [...]` fields
# Run again
retcon execute my-spec.toml