Files
dckc 792e535a56 Polish retcon and yarn-lock-separate-commit for this workspace
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
2026-10-07 02:40:25 -05:00

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).