Prune references to other kriscendobot/garden skills and roles (fixer, weaver, judge's panel, boatman/ferry, journal entries, references/endo-but-for-bots) and per-PR session lore. Replace the garden's created/updated/author frontmatter with name + a trigger-first description. Keep the two skills cross-linked, since both now live here, and credit upstream with links pinned to the source commits. retcon: tag pre-retcon tip as a numbered step; verify with a single empty `git diff pre-retcon HEAD`; drop `git -C project`. yarn-lock-separate-commit: promote the rebase --skip recipe from field notes to its own section. Generated-by: Claude Opus 5.5
130 lines
5.2 KiB
Markdown
130 lines
5.2 KiB
Markdown
---
|
|
name: retcon
|
|
description: Retcon a PR branch — use when a maintainer says "retcon", or asks to clean up, regroup, squash, or reorganize a PR's commits into sensibly grouped commits; one commit per affected package with implementation and tests together, conventional-commit messages, and yarn.lock isolated in its own commit. Resets to the base and restages the same net diff; the merge result is byte-identical. Not a rebase onto a new base.
|
|
---
|
|
|
|
# Retcon
|
|
|
|
Reset a PR's branch to its base and restage the same net diff as a
|
|
sensibly grouped commit history. The PR's diff doesn't change. Only the
|
|
commit grouping changes. The name is short for *retroactive continuity*:
|
|
fixing the story the branch's history tells.
|
|
|
|
## When to use
|
|
|
|
- A maintainer says "retcon #N" or "please retcon this branch".
|
|
- A PR's history sprawled during review: one commit per round of
|
|
feedback, work-in-progress commits, lockfile churn mixed in with code.
|
|
- Reviewers upstream read commit by commit, and the history isn't ready
|
|
for that.
|
|
|
|
A retcon is **not** a rebase onto a new base. If the branch lags its
|
|
base, rebase first, then retcon. A retcon assumes the base is current.
|
|
|
|
## What a retcon produces
|
|
|
|
A linear history with commits grouped as:
|
|
|
|
- **One commit per affected package.** Changes under `packages/foo/` go
|
|
in one commit, and changes under `packages/bar/` go in another. Each
|
|
message is scoped to its package: `feat(foo): ...`, `fix(bar): ...`.
|
|
- **One `chore: Update yarn.lock` commit**, separate from the
|
|
`package.json` change that caused it. This applies the
|
|
[yarn.lock separate-commit rule](../yarn-lock-separate-commit/SKILL.md)
|
|
to the whole branch at once.
|
|
- **Implementation and tests in the same commit.** A package's behavior
|
|
change and the tests covering it ship together, not as a "test" commit
|
|
plus an "implement" commit.
|
|
- **Conventional-commit messages.** The first line is
|
|
`<type>(<scope>): <imperative summary>`. The body, if any, says *why*,
|
|
not what the diff shows.
|
|
|
|
The PR's net diff (its merge result) is byte-identical before and
|
|
after.
|
|
|
|
## Procedure
|
|
|
|
Run on the PR's head branch, in a worktree that is up to date with the
|
|
base.
|
|
|
|
```sh
|
|
# 0. Sanity: clean tree, and the tip matches the remote we'll push to.
|
|
git status --porcelain # must be empty
|
|
git log --oneline origin/<head-branch>..HEAD # must be empty
|
|
|
|
# 1. Save the pre-retcon tip for the no-net-change check.
|
|
git tag pre-retcon HEAD
|
|
|
|
# 2. Find the base branch.
|
|
BASE=$(gh pr view <N> --json baseRefName --jq .baseRefName)
|
|
|
|
# 3. Reset to the base, keeping the net diff as unstaged changes.
|
|
# --mixed, so each `git add` that follows is deliberate.
|
|
git reset --mixed origin/$BASE
|
|
|
|
# 4. Restage by package: implementation + tests together.
|
|
git add packages/foo/
|
|
git commit -m "feat(foo): <summary>"
|
|
git add packages/bar/
|
|
git commit -m "fix(bar): <summary>"
|
|
# ... one commit per affected package ...
|
|
|
|
# 5. Lockfile last.
|
|
git add yarn.lock
|
|
git commit -m "chore: Update yarn.lock"
|
|
|
|
# 6. Verify: no net change.
|
|
git diff pre-retcon HEAD # must be empty
|
|
|
|
# 7. Push without clobbering concurrent work, then clean up.
|
|
git push --force-with-lease origin HEAD:<head-branch>
|
|
git tag -d pre-retcon
|
|
```
|
|
|
|
Run `git status` after each `git add` to confirm that only the intended
|
|
files are staged.
|
|
|
|
## Changes that don't fit one package
|
|
|
|
Name these groupings when you report the retcon, so the reviewer reads
|
|
the new history as a deliberate shape:
|
|
|
|
- **Top-level config or build:** one `chore:` or `build:` commit.
|
|
- **Cross-package refactors that must land atomically:** one
|
|
`refactor(<area>):` commit, where the area names the concept, not a
|
|
package.
|
|
- **Docs-only files** (READMEs, design notes): one `docs:` commit, or
|
|
`docs(<scope>):` if it's scoped.
|
|
|
|
## Net diff is invariant
|
|
|
|
This is the property everything else rests on. `git diff pre-retcon
|
|
HEAD` must be empty, because the two heads have the same tree. If it
|
|
isn't empty, **don't push.** Run `git reset --hard pre-retcon` and start
|
|
over.
|
|
|
|
## Pitfalls
|
|
|
|
- **No pre-retcon tag:** the no-net-change check has nothing to compare
|
|
against. Tag before you reset.
|
|
- **`git reset --hard` instead of `--mixed`:** it throws away the net
|
|
diff. Use `--mixed`, or `--soft` to keep the index.
|
|
- **Lockfile in a package commit:** `git add packages/foo/` can stage a
|
|
lockfile that lives under that package. Check `git status`.
|
|
- **Implementation without tests:** if a package commit adds behavior
|
|
and changes no tests, either the tests live in a separate cross-package
|
|
commit, or the code is untested. That's a review finding, not
|
|
something the retcon should fix.
|
|
- **The lease is rejected:** someone pushed since your last fetch. Don't
|
|
fall back to `--force`. Fetch, then redo the retcon on the new tip.
|
|
|
|
## Origin
|
|
|
|
Kris Kowal coined the verb: *"Please reset this branch and restage the
|
|
changes in sensibly grouped commits. This should generally have a single
|
|
commit for each affected package, a separate commit for chore: Update
|
|
yarn.lock, conventional-commit messages, and a single implementation and
|
|
test commit."* Adapted from
|
|
[the retcon skill in kriscendobot/garden](https://github.com/kriscendobot/garden/blob/aa94ebd0877a931ac67e29018b0fd4b62c257ece/skills/retcon/SKILL.md)
|
|
(May 2026).
|