Skip to content

finishing-a-development-branch

End-of-branch workflow covering final verification, PR creation, merge strategy selection, and cleanup. Presents structured integration options (merge, PR, park, or discard) after confirming all tests pass. A core spellbook capability for cleanly completing feature work and integrating it into the main branch.

Auto-invocation: Your coding assistant will automatically invoke this skill when it detects a matching trigger.

Use when implementation is complete, tests pass, and you need to decide the integration path. Triggers: 'done with this branch', 'ready to merge', 'ship it', 'wrap this up', 'how should I integrate this', 'what next after implementation'. NOT for: PR creation mechanics (use creating-issues-and-pull-requests).

Origin

This skill originated from obra/superpowers.

Workflow Diagram

Finishing a Development Branch - Diagrams

Workflow for completing a development branch: verifies tests pass, determines base branch, presents 4 structured integration options (merge, PR, keep, discard), executes the chosen option via subagent, and performs worktree cleanup where applicable.

Overview Diagram

High-level flow from entry through the 5 steps to terminal states.

flowchart TD
    subgraph Legend
        L1[Process]
        L2{Decision}
        L3([Terminal])
        L4[/Subagent Dispatch/]
        L5[[Quality Gate]]
    end

    style L4 fill:#4a9eff,color:#fff
    style L5 fill:#ff6b6b,color:#fff
    style L3 fill:#51cf66,color:#fff

    Entry([Skill Entry:<br>Tests must pass]) --> AutoCheck{Autonomous<br>mode?}

    AutoCheck -->|Yes| PostImpl{post_impl<br>setting?}
    AutoCheck -->|No| Step1

    PostImpl -->|auto_pr| DirectPR[Skip to Option 2]
    PostImpl -->|stop| StopReport([Report completion,<br>no action])
    PostImpl -->|offer_options| Step1
    PostImpl -->|unset| DefaultPR[Default to Option 2.<br>Log decision.]

    DirectPR --> Step4
    DefaultPR --> Step4

    Step1[[Step 1:<br>Verify Tests]] --> TestResult{Tests<br>pass?}
    TestResult -->|No| TestFail([STOP:<br>Fix failures first])
    TestResult -->|Yes| Step2

    Step2[Step 2:<br>Determine Base Branch] --> MergeBase{Base branch<br>detected?}
    MergeBase -->|Yes| Step3
    MergeBase -->|Ambiguous| AskBase[Ask user to<br>confirm base branch] --> Step3

    Step3[Step 3:<br>Present 4 Options] --> UserChoice{User selects<br>option}

    UserChoice -->|Option 1| Step4
    UserChoice -->|Option 2| Step4
    UserChoice -->|Option 3| Step4
    UserChoice -->|Option 4| Step4

    Step4[/Step 4: Execute Choice<br>finish-branch-execute/] --> Step5{Option 3<br>selected?}

    Step5 -->|Yes| KeepDone([Branch kept.<br>Worktree preserved.])
    Step5 -->|No| Step5Cleanup[/Step 5: Cleanup Worktree<br>finish-branch-cleanup/]

    Step5Cleanup --> SelfCheck[[Self-Check:<br>5-point checklist]]
    SelfCheck --> Done([Integration<br>complete])

    style Entry fill:#51cf66,color:#fff
    style StopReport fill:#51cf66,color:#fff
    style TestFail fill:#ff6b6b,color:#fff
    style KeepDone fill:#51cf66,color:#fff
    style Done fill:#51cf66,color:#fff
    style Step1 fill:#ff6b6b,color:#fff
    style SelfCheck fill:#ff6b6b,color:#fff
    style Step4 fill:#4a9eff,color:#fff
    style Step5Cleanup fill:#4a9eff,color:#fff

Detail: Step 4 - Execute Choice (finish-branch-execute)

Decision tree for each of the four integration options dispatched as a subagent.

flowchart TD
    subgraph Legend
        L1[Process]
        L2{Decision}
        L3([Terminal])
        L4[[Quality Gate]]
    end

    style L4 fill:#ff6b6b,color:#fff
    style L3 fill:#51cf66,color:#fff

    Entry{Which option<br>was chosen?} -->|Option 1| O1_Checkout
    Entry -->|Option 2| O2_Push
    Entry -->|Option 3| O3_Report
    Entry -->|Option 4| O4_Confirm

    %% Option 1: Merge Locally
    O1_Checkout[git checkout base-branch] --> O1_Pull[git pull]
    O1_Pull --> O1_Merge[git merge feature-branch]
    O1_Merge --> O1_Test[[Run test suite<br>on merged result]]
    O1_Test --> O1_TestResult{Post-merge<br>tests pass?}
    O1_TestResult -->|No| O1_Fail([STOP: Report failure.<br>Do NOT delete branch.])
    O1_TestResult -->|Yes| O1_Delete[git branch -d feature-branch]
    O1_Delete --> O1_Done([Invoke cleanup])

    %% Option 2: Push and Create PR
    O2_Push[git push -u origin<br>feature-branch] --> O2_PushOK{Push<br>succeeded?}
    O2_PushOK -->|No| O2_Fail([STOP: Report error.<br>No cleanup.])
    O2_PushOK -->|Yes| O2_PR[gh pr create<br>with summary + test plan]
    O2_PR --> O2_PROK{PR creation<br>succeeded?}
    O2_PROK -->|No| O2_Fail
    O2_PROK -->|Yes| O2_Report[Report PR URL to user]
    O2_Report --> O2_Done([Invoke cleanup])

    %% Option 3: Keep As-Is
    O3_Report([Report: Branch kept.<br>Worktree preserved.<br>No cleanup invoked.])

    %% Option 4: Discard
    O4_Confirm[[Require typed<br>'discard' confirmation]] --> O4_Check{Exact string<br>'discard' received?}
    O4_Check -->|No / Partial| O4_Reject([STOP: Do not proceed.<br>Ask again.])
    O4_Check -->|Yes| O4_Checkout[git checkout base-branch]
    O4_Checkout --> O4_Delete[git branch -D feature-branch]
    O4_Delete --> O4_Done([Invoke cleanup])

    style O1_Test fill:#ff6b6b,color:#fff
    style O4_Confirm fill:#ff6b6b,color:#fff
    style O1_Fail fill:#ff6b6b,color:#fff
    style O2_Fail fill:#ff6b6b,color:#fff
    style O4_Reject fill:#ff6b6b,color:#fff
    style O3_Report fill:#51cf66,color:#fff
    style O1_Done fill:#51cf66,color:#fff
    style O2_Done fill:#51cf66,color:#fff
    style O4_Done fill:#51cf66,color:#fff

Detail: Step 5 - Cleanup Worktree (finish-branch-cleanup)

Worktree detection and removal logic, gated by option selection.

flowchart TD
    subgraph Legend
        L1[Process]
        L2{Decision}
        L3([Terminal])
        L4[[Quality Gate]]
    end

    style L4 fill:#ff6b6b,color:#fff
    style L3 fill:#51cf66,color:#fff

    Entry{Which option<br>was executed?} -->|Option 3| Skip([No cleanup.<br>Worktree stays intact.])

    Entry -->|Option 1, 2, or 4| Detect[Detect worktree:<br>git worktree list]

    Detect --> InWorktree{Output matches<br>current branch?}
    InWorktree -->|No| NoWT([Not in a worktree.<br>Nothing to remove.])
    InWorktree -->|Yes| Remove[git worktree remove path]

    Remove --> RemoveOK{Removal<br>succeeded?}
    RemoveOK -->|Yes| Done([Worktree removed.<br>Integration complete.])
    RemoveOK -->|No| CheckDirty{Uncommitted<br>changes detected?}
    CheckDirty -->|Yes| WarnUser[[Warn user.<br>Do NOT force-remove.]]
    CheckDirty -->|No| OtherError([Report error.<br>Do NOT force-remove.])

    WarnUser --> AskForce{User confirms<br>force removal?}
    AskForce -->|Yes| ForceRemove[git worktree remove --force]
    AskForce -->|No| Preserve([Worktree preserved<br>per user decision.])

    ForceRemove --> Done

    style Skip fill:#51cf66,color:#fff
    style NoWT fill:#51cf66,color:#fff
    style Done fill:#51cf66,color:#fff
    style Preserve fill:#51cf66,color:#fff
    style OtherError fill:#ff6b6b,color:#fff
    style WarnUser fill:#ff6b6b,color:#fff

Legend

Color Meaning
Blue (#4a9eff) Subagent dispatch
Red (#ff6b6b) Quality gate / stop condition
Green (#51cf66) Success terminal

Cross-Reference Table

Overview Node Detail Diagram Source Reference
Step 1: Verify Tests Overview only (single gate) SKILL.md lines 82-107
Step 2: Determine Base Branch Overview only (single step) SKILL.md lines 109-115
Step 3: Present 4 Options Overview only (user interaction) SKILL.md lines 117-130
Step 4: Execute Choice Detail: Step 4 - Execute Choice finish-branch-execute.md
Step 5: Cleanup Worktree Detail: Step 5 - Cleanup Worktree finish-branch-cleanup.md
Autonomous Mode Overview (AutoCheck / PostImpl nodes) SKILL.md lines 44-59
Self-Check Overview (SelfCheck node) SKILL.md lines 173-184

Skill Content

# Finishing a Development Branch

<ROLE>
Release Engineer. Your reputation depends on clean integrations that never break main or lose work. A merge that breaks the build is a public failure. A discard without confirmation is unforgivable.
</ROLE>

**Announce:** "Using finishing-a-development-branch skill to complete this work."

## Invariant Principles

1. **Tests Gate Everything** - Never present options until tests pass. Never merge without verifying tests on merged result.
2. **Structured Choice Over Open Questions** - Present exactly 4 options, never "what should I do?"
3. **Destruction Requires Proof** - Option 4 (Discard) demands typed "discard" confirmation. No shortcuts.
4. **Worktree Lifecycle Matches Work State** - Cleanup only for Options 1 (merged) and 4 (discarded). Keep for Options 2 and 3.

---

## Inputs

| Input | Required | Description |
|-------|----------|-------------|
| Passing test suite | Yes | Tests must pass before this skill can proceed |
| Feature branch | Yes | Current branch with completed implementation |
| Base branch | No | Branch to merge into (auto-detected if unset) |
| `post_impl` setting | No | Autonomous mode directive (auto_pr, offer_options, stop) |

## Outputs

| Output | Type | Description |
|--------|------|-------------|
| Integration result | Action | Merge, PR, preserved branch, or discarded branch |
| PR URL | Inline | GitHub PR URL (Option 2 only) |
| Worktree state | State | Removed (Options 1, 4) or preserved (Options 2, 3) |

---

## Autonomous Mode

Check context for autonomous mode indicators: "Mode: AUTONOMOUS", "autonomous mode", or `post_impl` preference.

| `post_impl` value | Behavior |
|-------------------|----------|
| `auto_pr` | Skip Step 3, execute Option 2 directly |
| `offer_options` | Present options normally |
| `stop` | Skip Step 3, report completion without action |
| (unset in autonomous) | Default to Option 2. Log: "Autonomous mode: defaulting to PR creation" |

<CRITICAL>
**Circuit breakers (always pause):**
- Tests failing - NEVER proceed
- Option 4 (Discard) selected - ALWAYS require typed confirmation, never auto-execute
</CRITICAL>

---

## Branch-Relative Documentation

<CRITICAL>
Changelogs, PR titles, PR descriptions, commit messages, and code comments describe the delta between current branch HEAD and the merge base with the target branch. Nothing else exists. The only reality is `git diff $(git merge-base HEAD <target>)...HEAD`.
</CRITICAL>

**Required behavior:**

- Derive all changelog/PR/commit content from the merge base diff at time of writing.
- When HEAD changes (new commits, rebases, amends), re-evaluate and actively delete stale entries. Never accumulate entries session-by-session.
- Code comments describe the present. Git describes the past. No "changed from X to Y", "previously did Z", "refactored from old approach", "CRITICAL FIX: now does X instead of Y".
- Test: "Does this comment make sense to someone reading the code for the first time, with no knowledge of prior implementation?" If no, delete it.

**The rare exception:** A comment may reference external historical facts that explain non-obvious constraints (e.g., "SQLite < 3.35 doesn't support RETURNING"). Reframe as a present-tense constraint, not a change narrative.

---

## The Process

### Step 1: Verify Tests

<analysis>
Before presenting options:
- Do tests pass on current branch?
- What is the base branch?
- Am I in a worktree?
</analysis>

```bash
# Run project's test suite
npm test / cargo test / pytest / go test ./...
```

**If tests fail:**
```
Tests failing (<N> failures). Must fix before completing:

[Show failures]

Cannot proceed with merge/PR until tests pass.
```

STOP. Do not proceed to Step 2.

**If tests pass:** Continue to Step 2.

### Step 2: Determine Base Branch

```bash
git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
```

If the command fails or is ambiguous, ask: "This branch split from main - is that correct?"

### Step 3: Present Options

Present exactly these 4 options:

```
Implementation complete. What would you like to do?

1. Merge back to <base-branch> locally
2. Push and create a Pull Request
3. Keep the branch as-is (I'll handle it later)
4. Discard this work

Which option?
```

**Don't add explanation** - keep options concise.

### Step 4: Execute Choice

**Dispatch subagent** with command: `finish-branch-execute`

Provide context: chosen option number, feature branch name, base branch name, worktree path (if applicable).

### Step 5: Cleanup Worktree

**Dispatch subagent** with command: `finish-branch-cleanup`

Provide context: chosen option number, worktree path. Note: Option 3 skips cleanup entirely.

---

## Quick Reference

| Option | Merge | Push | Keep Worktree | Cleanup Branch |
|--------|-------|------|---------------|----------------|
| 1. Merge locally | Yes | - | - | Yes |
| 2. Create PR | - | Yes | Yes | - |
| 3. Keep as-is | - | - | Yes | - |
| 4. Discard | - | - | - | Yes (force) |

---

## Anti-Patterns

<FORBIDDEN>
- Proceeding with failing tests
- Merging without post-merge test verification
- Deleting branches without typed "discard" confirmation
- Force-pushing without explicit user request
- Presenting open-ended questions instead of structured options
- Cleaning up worktrees for Options 2 or 3
- Accepting partial confirmation for Option 4
</FORBIDDEN>

---

## Self-Check

<reflection>
Before completing:
- [ ] Tests pass on current branch
- [ ] Tests pass after merge (Option 1 only)
- [ ] User explicitly selected one of the 4 options
- [ ] Typed "discard" received (Option 4 only)
- [ ] Worktree cleaned only for Options 1 or 4

IF ANY unchecked: STOP and fix.
</reflection>

---

## Integration

**Called by:**
- **executing-plans** (Step 5) - After all batches complete
- **executing-plans --mode subagent** (Step 7) - After all tasks complete in subagent mode

**Pairs with:**
- **using-git-worktrees** - Cleans up worktree created by that skill

<FINAL_EMPHASIS>
You are a Release Engineer. Clean integrations that never break main and never lose work without confirmation are your entire reputation. A test-gated, confirmation-gated, option-structured handoff is the only acceptable delivery. Anything less is negligence.
</FINAL_EMPHASIS>