Skip to content

feat(create-pr): add reuse_branch to keep one self-updating pull request - #80

Open
marc0olo wants to merge 1 commit into
mainfrom
feat/create-pr-reuse-branch
Open

feat(create-pr): add reuse_branch to keep one self-updating pull request#80
marc0olo wants to merge 1 commit into
mainfrom
feat/create-pr-reuse-branch

Conversation

@marc0olo

@marc0olo marc0olo commented Aug 3, 2026

Copy link
Copy Markdown
Member

Closes #77.

create-pr appends a random suffix to branch_name on every run, so each run that finds a diff opens a new branch and a new pull request. While an earlier one is unmerged, every subsequent run legitimately still sees a diff against the base and opens another for the same content. They accumulate, and once a release lands they all go permanently conflicting, because the release commit folds those entries into a version section.

dfinity/icp-js-core accumulated 8 changelog pull requests representing 2 distinct changelog states: 3 with byte-identical diffs, and 5 that went conflicting after v6.0.0 and were closed unresolved. dfinity/pic-js currently has 6 open, 3 conflicting. This repo produced #82 the same way.

This is not about no-op runs — create-pr already skips when there is nothing to commit. The defect is purely branch reuse.

Change

New reuse_branch input on actions/create-pr. When enabled:

  • branch_name is used as-is, with no random suffix.
  • The branch is reset to the current commit (git checkout -B) and force pushed.
  • An already-open pull request for that head and base is updated rather than duplicated — pulls.create would return 422 for a duplicate head.
  • When there is nothing left to propose, that pull request is closed rather than left to go stale. This is what actually removes the permanent-conflict symptom.

New pull_request_updated output distinguishes an update from a creation; pull_request_created stays honest and reports false in the update case.

Defaults differ deliberately: false on the action, so existing callers such as create-release-pr are unchanged (release branches are already unique per version); true on the generate-changelog reusable workflow, where the accumulation happens. Flagging that explicitly, since it is a behaviour change for the five consuming repos on merge — happy to make it opt-in if you would rather roll it out per repo.

--force rather than --force-with-lease: the branch is reset from the base branch on every run, so the local ref never matches the remote one and a lease check would reject every push. The branch is bot-owned and fully regenerated each run, so there is no human work to clobber.

Verification

tsc and pnpm build clean, prettier --check . clean, both changed YAML files parse and the input threads through to the action step. Compiled output confirmed to contain the new behaviour: git checkout -B, git push --force, the reuse branch, and the find/close paths.

Not exercised against a live run — that needs a real push to main in a consuming repo.

Rebased onto main after #79. The bundle conflict I had expected did not materialise: git auto-merged the disjoint regions, and I verified the result matches a fresh pnpm build byte-for-byte, so no rebuild commit was needed.

🤖 Generated with Claude Code

create-pr appends a random suffix to branch_name on every run, so each run that
finds a diff opens a new branch and a new pull request. While an earlier one is
still unmerged, every subsequent run legitimately still sees a diff against the
base branch and opens another pull request for it. They accumulate, and once a
release lands they all go permanently conflicting.

In dfinity/icp-js-core this produced 8 changelog pull requests for 2 distinct
changelog states: 3 with byte-identical diffs, and 5 that went conflicting
after v6.0.0 shipped and had to be closed unresolved. dfinity/pic-js currently
has 6 open, 3 of them conflicting.

Adds a reuse_branch input. When enabled, branch_name is used as-is, the branch
is reset to the current commit and force pushed, and the pull request already
open for it is updated rather than a second one being created. When there is
nothing left to propose, that pull request is closed instead of being left to
go stale.

The input defaults to false, so existing callers such as create-release-pr keep
the current behaviour. The generate-changelog reusable workflow opts in by
default, since a single self-updating changelog pull request is the intent
there.

A plain --force is used rather than --force-with-lease: the branch is reset from
the base branch on every run, so the local ref never matches the remote one and
a lease check would always reject.

Closes #77

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@marc0olo
marc0olo force-pushed the feat/create-pr-reuse-branch branch from 4efc5fc to 40e8fec Compare August 4, 2026 07:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

generate-changelog: new branch per run causes changelog PRs to accumulate and go permanently conflicting

1 participant