Add iw finish command: merge final PR and remove worktree #249

Open
opened 2026-03-11 08:54:57 +00:00 by mprihoda · 1 comment
mprihoda commented 2026-03-11 08:54:57 +00:00 (Migrated from github.com)

Problem

After all implementation phases are complete, the developer has a feature branch with a PR to main. Closing out the issue requires multiple manual steps across two worktrees:

  1. Go to the main worktree
  2. Find and merge the PR (or wait for it to merge)
  3. Run `iw rm ` to remove the issue worktree
  4. Optionally delete the remote branch

There's no single command to do this. The `phase-pr` command only creates PRs from phase sub-branches to the feature branch — it never targets main. The `rm` command removes the worktree but doesn't check or merge any PR.

Proposed Solution

Add `iw finish ` — run from the main worktree to merge the final PR and clean up.

Behavior

  1. Find the PR: Look up open PR from the issue's feature branch to main/master
  2. Verify mergeable: Check PR status (CI passing, no conflicts, approved if required)
  3. Merge: Squash-merge the PR, delete remote branch
  4. Update local: `git pull` on main to get the merged changes
  5. Remove worktree: Same as `iw rm ` (kill tmux session, remove worktree directory, unregister from dashboard)
  6. Update review-state: Set status to `finished` (or similar terminal state)

Flags

  • `--no-merge`: Skip merge, just verify PR is already merged, then clean up
  • `--force`: Skip safety checks (uncommitted changes warning in worktree)

Safety Checks

  • Must be run from the main worktree (not from the issue worktree being removed)
  • PR must exist and be open (or already merged with `--no-merge`)
  • Worktree must not have uncommitted changes (unless `--force`)
  • Warn if review-state status is not `all_complete`

Error Cases

  • No PR found → suggest creating one first
  • PR has merge conflicts → report, stop
  • PR checks failing → report, stop (offer `--force` override?)
  • Worktree has uncommitted changes → warn, require `--force`
  • Already on the issue worktree → error, tell user to switch to main

Acceptance Criteria

  • `iw finish ` merges the final PR and removes the worktree
  • `iw finish --no-merge` cleans up after manual merge
  • Safety checks prevent data loss
  • Works with both GitHub and GitLab forges

Notes

  • Reuses existing components: `GitHubClient` (PR lookup/merge), `GitWorktree` (removal), `rm` logic (tmux session cleanup, dashboard unregister)
  • The dev-docs completion flow (Step 10 in `wf-implement`, `ag-implement`) currently creates the final PR manually with `gh pr create`. Once this command exists, the pipeline can call `iw finish` instead.

See `project-management/issues/<THIS_ISSUE>/analysis.md` for implementation notes.

## Problem After all implementation phases are complete, the developer has a feature branch with a PR to main. Closing out the issue requires multiple manual steps across two worktrees: 1. Go to the main worktree 2. Find and merge the PR (or wait for it to merge) 3. Run \`iw rm <issue-id>\` to remove the issue worktree 4. Optionally delete the remote branch There's no single command to do this. The \`phase-pr\` command only creates PRs from phase sub-branches to the feature branch — it never targets main. The \`rm\` command removes the worktree but doesn't check or merge any PR. ## Proposed Solution Add \`iw finish <issue-id>\` — run from the **main worktree** to merge the final PR and clean up. ### Behavior 1. **Find the PR:** Look up open PR from the issue's feature branch to main/master 2. **Verify mergeable:** Check PR status (CI passing, no conflicts, approved if required) 3. **Merge:** Squash-merge the PR, delete remote branch 4. **Update local:** \`git pull\` on main to get the merged changes 5. **Remove worktree:** Same as \`iw rm <issue-id>\` (kill tmux session, remove worktree directory, unregister from dashboard) 6. **Update review-state:** Set status to \`finished\` (or similar terminal state) ### Flags - \`--no-merge\`: Skip merge, just verify PR is already merged, then clean up - \`--force\`: Skip safety checks (uncommitted changes warning in worktree) ### Safety Checks - Must be run from the main worktree (not from the issue worktree being removed) - PR must exist and be open (or already merged with \`--no-merge\`) - Worktree must not have uncommitted changes (unless \`--force\`) - Warn if review-state status is not \`all_complete\` ### Error Cases - No PR found → suggest creating one first - PR has merge conflicts → report, stop - PR checks failing → report, stop (offer \`--force\` override?) - Worktree has uncommitted changes → warn, require \`--force\` - Already on the issue worktree → error, tell user to switch to main ## Acceptance Criteria - [ ] \`iw finish <issue-id>\` merges the final PR and removes the worktree - [ ] \`iw finish <issue-id> --no-merge\` cleans up after manual merge - [ ] Safety checks prevent data loss - [ ] Works with both GitHub and GitLab forges ## Notes - Reuses existing components: \`GitHubClient\` (PR lookup/merge), \`GitWorktree\` (removal), \`rm\` logic (tmux session cleanup, dashboard unregister) - The dev-docs completion flow (Step 10 in \`wf-implement\`, \`ag-implement\`) currently creates the final PR manually with \`gh pr create\`. Once this command exists, the pipeline can call \`iw finish\` instead. See \`project-management/issues/<THIS_ISSUE>/analysis.md\` for implementation notes.
Member

Intake: needs-input

The goal of the command is clear, but four choices conflict with the current repository or with open issue #174, and only a human can make them.

1. Must iw finish merge the final PR with a squash or with a merge commit?

The issue says "Squash-merge the PR". But each final PR on main merges with a merge commit, for example 33e14e5f "Merge pull request 'IW-681: …' (#798)". A squash makes all the phase commits of an issue into one commit. The forge code has the two merge types: mergeSquashAndDelete and mergeWithDelete (ForgeGateway.scala L75-L105).

"Merge: Squash-merge the PR, delete remote branch" (issue body)

  • a) Merge commit. This is the same as the merges on main now. The phase history stays.
  • b) Squash. This is what the issue says. Each issue becomes one commit on main.
  • c) Merge commit, with a flag for a squash. This gives more choice, and adds one more flag to test.

Recommended: a): it does what the project does now, and the phase history stays.

2. Which forges must iw finish support?

The acceptance criteria name only GitHub and GitLab. This project is on Forgejo, and the code that merges PRs already supports Forgejo, GitHub and GitLab.

"Works with both GitHub and GitLab forges" (issue acceptance criteria)

  • a) All three forges, through the code that merges PRs now. The command then works for this project.
  • b) Only GitHub and GitLab. This is what the issue says, but the command cannot run on iw-cli.

Recommended: a): if the command does not support Forgejo, this project cannot use it.

3. What must iw finish do with the review-state card after the merge?

The issue asks for a new status, finished. The schema does not have it. The known statuses end at all_complete (ReviewState.scala L83-L84). Open issue #706 decides when iw rm deletes a card ("2: b", delete it at all_complete). A follow-up question on #706 asks if the PR must also be merged first.

  • a) Write no status. The card follows the rules that #706 sets for iw rm. There is no change to the schema.
  • b) Set finished before the worktree is removed. This adds a status to the schema. The schema is in kanon too, so kanon must change.
  • c) Delete the card. The PR is merged, so no resume needs the card.

Recommended: a): it adds no status, and it does not make a second card rule next to the one in #706.

4. What do we do with open issue #174, "Add 'merge' command to complete issue workflow from main repo"?

#174 asks for the same command with the name iw merge. It also asks to close the tracker issue, and for --dry-run, --keep-worktree and --no-squash. This issue (#249) does not ask for these. If we implement both issues, we get two commands that do the same work.

  • a) Close #174 as a duplicate. Keep the scope of #249. The extra items of #174 are lost.
  • b) Put the extra items of #174 into iw finish, then close #174. One command. The work is larger.
  • c) Keep #174 open for its extra items, and do them later on iw finish.

Recommended: c): it makes the scope of #249 no larger, and it loses none of the items in #174.

Answer in a comment on this issue, per number, for example "1: a", or in your own words; intake reads it on its next iteration.

Intake: needs-input The goal of the command is clear, but four choices conflict with the current repository or with open issue #174, and only a human can make them. ### 1. Must `iw finish` merge the final PR with a squash or with a merge commit? The issue says "Squash-merge the PR". But each final PR on `main` merges with a merge commit, for example 33e14e5f "Merge pull request 'IW-681: …' (#798)". A squash makes all the phase commits of an issue into one commit. The forge code has the two merge types: `mergeSquashAndDelete` and `mergeWithDelete` ([ForgeGateway.scala L75-L105](https://code.iterative.works/iterative-works/iw-cli/src/branch/main/core/adapters/ForgeGateway.scala#L75-L105)). > "Merge: Squash-merge the PR, delete remote branch" (issue body) - **a) Merge commit.** This is the same as the merges on `main` now. The phase history stays. - **b) Squash.** This is what the issue says. Each issue becomes one commit on `main`. - **c) Merge commit, with a flag for a squash.** This gives more choice, and adds one more flag to test. **Recommended: a)**: it does what the project does now, and the phase history stays. ### 2. Which forges must `iw finish` support? The acceptance criteria name only GitHub and GitLab. This project is on Forgejo, and the code that merges PRs already supports Forgejo, GitHub and GitLab. > "Works with both GitHub and GitLab forges" (issue acceptance criteria) - **a) All three forges, through the code that merges PRs now.** The command then works for this project. - **b) Only GitHub and GitLab.** This is what the issue says, but the command cannot run on iw-cli. **Recommended: a)**: if the command does not support Forgejo, this project cannot use it. ### 3. What must `iw finish` do with the review-state card after the merge? The issue asks for a new status, `finished`. The schema does not have it. The known statuses end at `all_complete` ([ReviewState.scala L83-L84](https://code.iterative.works/iterative-works/iw-cli/src/branch/main/core/model/ReviewState.scala#L83-L84)). Open issue #706 decides when `iw rm` deletes a card ("2: b", delete it at `all_complete`). A follow-up question on #706 asks if the PR must also be merged first. - **a) Write no status.** The card follows the rules that #706 sets for `iw rm`. There is no change to the schema. - **b) Set `finished` before the worktree is removed.** This adds a status to the schema. The schema is in kanon too, so kanon must change. - **c) Delete the card.** The PR is merged, so no resume needs the card. **Recommended: a)**: it adds no status, and it does not make a second card rule next to the one in #706. ### 4. What do we do with open issue #174, "Add 'merge' command to complete issue workflow from main repo"? #174 asks for the same command with the name `iw merge`. It also asks to close the tracker issue, and for `--dry-run`, `--keep-worktree` and `--no-squash`. This issue (#249) does not ask for these. If we implement both issues, we get two commands that do the same work. - **a) Close #174 as a duplicate. Keep the scope of #249.** The extra items of #174 are lost. - **b) Put the extra items of #174 into `iw finish`, then close #174.** One command. The work is larger. - **c) Keep #174 open for its extra items, and do them later on `iw finish`.** **Recommended: c)**: it makes the scope of #249 no larger, and it loses none of the items in #174. Answer in a comment on this issue, per number, for example "1: a", or in your own words; intake reads it on its next iteration.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
iterative-works/iw-cli#249
No description provided.