016 — Release deletes the merged story branch (#42)
Status: shipped (v0.12.0) Roadmap: #47
Why
At code level 1 the release is prepared on the story branch, the human
merges its pull request, and tp release — waiting for the merge
(story 008) — checks out the base branch, fast-forwards it, tags and
publishes. The story branch is finished at that moment: its commits are
on the base branch and the forge has deleted its copy on merge. The
local branch stays, so every story leaves one behind (this repo had
story-014 and story-015 lying around after v0.10.0) and the last
step of a story's life is left to the human's memory. The release
branch of a level-0 release is already tidied (executeTagMerged
deletes release/vX.Y.Z on both sides); the story branch should get
the same end.
What changes
tp release, once the merge wait ends in a merge and the release on the base branch has tagged and published, checks whether the story branch is still on the release remote. Gone — the forge deleted it on merge — and the local branch is deleted too (git branch -D: a squash or rebase merge leaves it unmerged in git's eyes; the merged pull request and the forge's deletion are the proof). One line reports it:Deleted story-016-… (merged in PR #41, gone from origin).- Still on the remote, and nothing is deleted on either side; one line names the branch and where it still is. The forge not deleting a merged branch is a repo setting the human chose, and tp does not second-guess it.
- The deletion is the last step, after the tag and the publish: a release that fails on the base branch keeps the branch, and the existing error ("run 'tp release' on main to tag vX.Y.Z") still holds.
--dry-runnever reaches this step: it does not wait for the merge (story 008), so nothing is deleted.
Acceptance
| Release on the base branch | Story branch on the remote | Local story branch | Output |
|---|---|---|---|
| tagged and published | deleted by the forge | deleted | Deleted <branch> (merged in PR #N, gone from <remote>) |
| tagged and published | still present | kept | <branch> is still on <remote>; left locally too |
--dry-run |
any | kept | no wait, so no merge to act on |
| the remote cannot be queried | unknown | kept | warning naming the branch |
| checks or Execute fail | any | kept | existing error, unchanged |
| PR closed, wait timed out, or Ctrl-C | any | kept | as before |
| second run on the base branch (two-run flow, story 008) | any | kept | out of scope; see below |
Out of scope
- Deleting the story branch on the remote when the forge did not. The
merged pull request would justify it, as it does for
release/vX.Y.Z, but this story keys the local deletion off the forge's deletion by design; extending it is a one-line follow-up if wanted. - The two-run flow: a second
tp releaseon the base branch does not know which story branch produced the merged heading. - Sweeping other stale local branches (a
fetch --prunestyle tidy).
Decisions
None recorded as an ADR. The fork was git branch -d (refuses an
unmerged branch) against -D: the forge's squash and rebase merges
rewrite the commits, so -d would refuse exactly the branches this
story is for. -D it is, gated on two facts tp already holds — the
pull request is merged and the forge has removed the branch.
Done when
- tests express the acceptance table and pass
- spec updated (
docs/release-workflow.md) - roadmap ticked and stamped; changelog entry
- issue closed with a link to the release