publish-pr · git:20260628.3255910 · 2026-06-28 · sha256 8b0f476f33a60e88
publish-pr git:20260628.3255910A
Immutable. This exact content is served forever at /api/v1/blob/8b0f476f33a60e88.
--- name: publish-pr description: Use in /implement at the draft→ready boundary to squash the branch's review-iteration commits into one (non-interactive soft-reset + recommit + force-with-lease) and mark the draft PR ready. Takes the commit message as input (sourced from the plan-file before cleanup). GitHub-specific (gh) behind a host-neutral contract. --- # Publish PR The finalize step of `/implement`'s repo path: collapse the review-iteration commit noise into one clean commit, then mark the draft PR ready for humans. Runs **after** `cleanup-artifacts` (so a tracked plan-file deletion folds into the squashed commit). The squash is a **non-interactive** local rewrite — `git rebase -i` isn't available in this harness, and isn't needed. ## Input - **branch** — the current feature branch (committed; reviewed in its draft PR). - **commit message** — the final squashed-commit message. The recipe sources it from the `plan-file` (story ref + change summary) **before** `cleanup-artifacts` deletes that file. - **PR ref** — the draft PR to mark ready (from `open-draft-pr`). ## Steps 1. **Squash** the branch to one commit: ``` git reset --soft "$(git merge-base origin/main HEAD)" git add -A git commit -m "<commit message>" ``` Soft-reset to the branch point keeps the branch's work staged; `git add -A` then folds in working-tree changes the index doesn't yet reflect — notably `cleanup-artifacts`' plan-file *deletion*, so a **tracked** plan file isn't re-committed into the squash (the `reset --soft` index still holds it otherwise). No-op for the gitignored default. One commit then collapses the WIP + review-feedback commits. The goal is eliminating review-iteration noise, **not** single-commit dogma — squash-to-one is just the simplest mechanism that guarantees no feedback-churn commits survive. If the branch has no changes vs the merge-base, there's nothing to finalize — treat it as a no-op rather than letting `git commit` error on an empty index. (`git add -A` assumes the finalize tree is clean apart from `cleanup-artifacts`' deletions; stray untracked scratch/build files would otherwise be swept into the squash.) 2. **Force-push** the rewritten branch with an explicit refspec: `git push --force-with-lease origin <branch>` (explicit so it doesn't depend on a configured upstream; the lease guards against clobbering an unexpected remote update; safe on a solo feature branch). 3. **Mark the PR ready:** `gh pr ready <PR ref>`. ## Output / contract - **In:** (branch, commit message, PR ref). - **Out:** a single-commit branch, force-pushed; the PR marked ready for review. - **Side effects:** rewrites branch history (force-push); changes PR state draft→ready. **No merge** — merging stays a human action. ## Project overrides - A repo that prefers GitHub's squash-at-merge over a local pre-ready squash overrides steps 1–2; the contract (clean history at draft→ready) still holds. ## Future scope - **Absorb PR creation (post-v1).** Under the flow simplification, `open-draft-pr` goes away and `publish-pr` *creates* the PR at the end (review having happened on the branch). Don't hard-assume a pre-existing draft beyond the `gh pr ready` step, so that shift stays cheap.